diff --git a/DEPS b/DEPS index b963f18..0f69d9a 100644 --- a/DEPS +++ b/DEPS
@@ -308,19 +308,19 @@ # 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': '102d89f4b1f0fab6a3b07a16e128345053b6db9d', + 'src_internal_revision': '4bac053d081d6987ceef3dd358e4c5ac84caab58', # 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': '122a1f31d3f9bf50cedc03e46ba0fa87e46176ec', + 'skia_revision': '02ba2eac9d65834f70e239e4db87b750dd489e73', # 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': '13f57cb4f1c0a5d04345d42ce3bfadb5c71d3b4e', + 'v8_revision': 'bd829db3f269af2aeb5f080d1ed0a96c6d2eb235', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. - 'angle_revision': '9fd0c2508166fb74bcedbd128d502028c712575d', + 'angle_revision': 'f7571cf4c526b7a9cd0c88424ed6244fac1b55ac', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. @@ -376,15 +376,15 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': '9bc4a2aee9361b6d2018c2f230c27c64a9e99b36', + 'catapult_revision': 'f7a1fb2d8f3d155f6d52e95fa486bf91a9ebca81', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling CrossBench # and whatever else without interference from each other. - 'crossbench_revision': '4b00420261e9a2695d8d9b3b3672d1e0092ce241', + 'crossbench_revision': '877a1b48c4c43c063150584de7526a103ed92119', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling CrossBench # and whatever else without interference from each other. - 'crossbench_web_tests_revision': '909ad1733b50f28510c840ebad7b878a5ce07715', + 'crossbench_web_tests_revision': 'b19e4e52c33fb8a105c3fc99598b0b9b4bc59752', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -392,7 +392,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling fuzztest # and whatever else without interference from each other. - 'fuzztest_revision': '41e160679e3c010a860e674e7997e2b285c6e0a2', + 'fuzztest_revision': '3e42dc3c305dd22a22e7d2996c7e24177f3a43ad', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling domato # and whatever else without interference from each other. @@ -400,7 +400,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling devtools-frontend # and whatever else without interference from each other. - 'devtools_frontend_revision': '384800eeb706ed5877c72fb9ff662357bbd6fc7d', + 'devtools_frontend_revision': '9824f31eceddd182136914feecb60f516bc68487', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libprotobuf-mutator # and whatever else without interference from each other. @@ -424,11 +424,11 @@ # 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': 'ff05aac692cbbce4978d9233313a85d96c391023', + 'dawn_revision': '18eb229ef5f707c1464cc581252e7603c73a3ef0', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'quiche_revision': '99a5e60cd6d87a0be2e8679ed91111d65a4abeda', + 'quiche_revision': 'b91dd3088416ab1c47cfc7a078d306e7a2c4fb6b', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ink # and whatever else without interference from each other. @@ -543,7 +543,7 @@ 'libcxx_revision': '7ab65651aed6802d2599dcb7a73b1f82d5179d05', # GN CIPD package version. - 'gn_version': 'git_revision:2941d2a26fa9cef3103f10e1dee5da7cd404008a', + 'gn_version': 'git_revision:d22fa2d126d8e4db585e9db0f3fb2fb4e0bf601b', # ninja CIPD package. 'ninja_package': 'infra/3pp/tools/ninja/', @@ -1209,7 +1209,7 @@ 'packages': [ { 'package': 'chromium/chrome/android/orderfiles/arm64', - 'version': '481_fKmp4VgmYDP8HeHerPZz9Ft5ixMterEgk5hvdAwC', + 'version': 'Gl7r93I8PSYAQYs3AEC9qdX0c5Cj4oUhn2GANw4F5PMC', }, ], 'condition': 'checkout_android and non_git_source', @@ -1220,7 +1220,7 @@ 'packages': [ { 'package': 'chromium/android_webview/tools/orderfiles/arm', - 'version': 'EjzF3fh3r_f23ZHUUGfcvEGKbEd96Q9rAZRzgfb0yqAC', + 'version': 'MR0Lv5_g8Ga9tC7xE7tSrJzz2THIZkc6gwYOgENR9NQC', }, ], 'condition': 'checkout_android and non_git_source', @@ -1231,7 +1231,7 @@ 'packages': [ { 'package': 'chromium/android_webview/tools/orderfiles/arm64', - 'version': 'fpCx8hSaDjnv8lI_E4kP_HNYqgZnZQOwRY-2J2wLU6gC', + 'version': 'CLGYKXfSNATHJIOdr3PNgCfckO3Z8JUBCIJAddEgkTIC', }, ], 'condition': 'checkout_android and non_git_source', @@ -1403,7 +1403,7 @@ 'packages': [ { 'package': 'chromium/third_party/updater/chromium_linux64', - 'version': 'version:2@1595001', + 'version': 'version:2@1596007', }, ], }, @@ -1414,7 +1414,7 @@ 'packages': [ { 'package': 'chromium/third_party/updater/chromium_mac_amd64', - 'version': 'version:2@1594028', + 'version': 'version:2@1596008', }, ], }, @@ -1425,7 +1425,7 @@ 'packages': [ { 'package': 'chromium/third_party/updater/chromium_mac_arm64', - 'version': 'version:2@1594030', + 'version': 'version:2@1596007', }, ], }, @@ -1536,7 +1536,7 @@ 'packages': [ { 'package': 'chromium/third_party/enterprise_companion/chromium_linux64', - 'version': 'dmWFkgR6d1DBXuUomHR7nwSaTS-grGYf7Pfa50zRou0C', + 'version': 'bfXobrW2w1AKos1jV_l6Y0QNaDNQt_w22fCx_P1QG8kC', }, ], }, @@ -1547,7 +1547,7 @@ 'packages': [ { 'package': 'chromium/third_party/enterprise_companion/chromium_mac_amd64', - 'version': '4lmwUzmjaGPmG4zzMro-AXn_TvYnKrWHxZJADsZUnZgC', + 'version': '4ZDsQkj4PhTNaYQwIDBuNNpdod_hkeBbwkL1mjt0RSYC', }, ], }, @@ -1558,7 +1558,7 @@ 'packages': [ { 'package': 'chromium/third_party/enterprise_companion/chromium_mac_arm64', - 'version': 'T0bhWkZ2WPP2Nhv_B82jLRuuA5s6932NF1-F84v3z_UC', + 'version': 'SZhTzCS8Hr8eAeKbOh305RyOMZbvOVdGpa-iDOnyFI4C', }, ], }, @@ -1580,7 +1580,7 @@ 'packages': [ { 'package': 'chromium/third_party/enterprise_companion/chromium_win_x86_64', - 'version': 'VSQv7u-vLdC_AP9rdIet8yrpltG7obv7EKFTk6Rz5iAC', + 'version': 'KgJ-4IWAjRBClgHWczMVxxAFkJ7T95LHgT0GpbesQHQC', }, ], }, @@ -1628,12 +1628,12 @@ 'src/clank': { 'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' + - 'ae77a657d2f3c9282aa750ef27dc7d97225871bc', + '726cd20140f7147db6e09fd3e78291b77efd64c3', 'condition': 'checkout_android and checkout_src_internal', }, 'src/docs/website': { - 'url': Var('chromium_git') + '/website.git' + '@' + '42a6e5a316866471cb6a8792794523e4520b8d90', + 'url': Var('chromium_git') + '/website.git' + '@' + '86cb4eb2aa8ddc985c6ffd29bb696398dbc0a8d6', }, 'src/ios/third_party/earl_grey2/src': { @@ -1728,7 +1728,7 @@ 'packages': [ { 'package': 'chromium/third_party/androidx', - 'version': 'cOeVS8IOLGMV68S9vCCdb9hdKvQOTDppiUZ5rIYtIZoC', + 'version': 'IxP1FmK52UK5we5ZE7jEkvED0_fBvkCslzXKDVIuV9QC', }, ], 'condition': 'checkout_android and non_git_source', @@ -2064,7 +2064,7 @@ Var('chromium_git') + '/chromium/web-tests.git' + '@' + Var('crossbench_web_tests_revision'), 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '4e58caf8aa08befe78cf40d08ba33da072b15cf9', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '95d1432b5c506cc6b500b34c23f06c4708139fe9', 'src/third_party/devtools-frontend/src': Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'), @@ -2076,7 +2076,7 @@ Var('chromium_git') + '/external/github.com/jk-jeon/dragonbox.git' + '@' + 'beeeef91cf6fef89a4d4ba5e95d47ca64ccb3a44', 'src/third_party/eigen3/src': - Var('chromium_git') + '/external/gitlab.com/libeigen/eigen.git' + '@' + 'ea13a98decd497a8c5588fb5de71b57bcf10d864', + Var('chromium_git') + '/external/gitlab.com/libeigen/eigen.git' + '@' + '1726a929009be60a5ed049d23052cbb7ce6f2f96', 'src/third_party/emoji-metadata/src': { 'url': Var('chromium_git') + '/external/github.com/googlefonts/emoji-metadata' + '@' + '045f146fca682a836e01cd265171312bfb300e06', @@ -2349,7 +2349,7 @@ Var('chromium_git') + '/external/libaddressinput.git' + '@' + 'e20690c8d5178bb282641d5eb06ef0298ff4cbc5', 'src/third_party/libaom/source/libaom': - Var('aomedia_git') + '/aom.git' + '@' + '0c15af06af108af03cbe237e4bffa4b700b76d81', + Var('aomedia_git') + '/aom.git' + '@' + '34f25197c6e9efef129992bb763aefa6036119fd', 'src/third_party/crabbyavif/src': Var('chromium_git') + '/external/github.com/webmproject/CrabbyAvif.git' + '@' + Var('crabbyavif_revision'), @@ -2455,7 +2455,7 @@ }, 'src/third_party/libunwindstack': { - 'url': Var('chromium_git') + '/chromium/src/third_party/libunwindstack.git' + '@' + '0928ad0d25e4af07c8be5ab06d0ca584f9f4ceb5', + 'url': Var('chromium_git') + '/chromium/src/third_party/libunwindstack.git' + '@' + '333fcafb91bd3830c5ef814c071ff73df9cdc976', 'condition': 'checkout_android', }, @@ -2617,7 +2617,7 @@ Var('pdfium_git') + '/pdfium.git' + '@' + Var('pdfium_revision'), 'src/third_party/perfetto': - Var('chromium_git') + '/external/github.com/google/perfetto.git' + '@' + '4e4843ae073504d2f58540031a8f41471fa86a76', + Var('chromium_git') + '/external/github.com/google/perfetto.git' + '@' + '9b59f48e11a56a8d2dddd60299e7e25b68b3072c', 'src/base/tracing/test/data': { 'bucket': 'perfetto', @@ -2944,9 +2944,9 @@ Var('chromium_git') + '/external/github.com/GoogleChromeLabs/text-fragments-polyfill.git' + '@' + 'c036420683f672d685e27415de0a5f5e85bdc23f', 'src/third_party/tflite/src': - Var('chromium_git') + '/external/github.com/tensorflow/tensorflow.git' + '@' + 'd20369f4f226598800e0d406db567d2d1c17fa95', + Var('chromium_git') + '/external/github.com/tensorflow/tensorflow.git' + '@' + '24d66fbe6c5e87d291207494e4e83d39de3f7d90', 'src/third_party/litert/src': - Var('chromium_git') + '/external/github.com/google-ai-edge/LiteRT.git' + '@' + '36dcf5a2ac1d6cc02df53d5e3f5bcd6dd6876ff0', + Var('chromium_git') + '/external/github.com/google-ai-edge/LiteRT.git' + '@' + '13469058b8ee37e2153481ba49644764666ad275', 'src/third_party/turbine/cipd': { 'packages': [ { @@ -2958,7 +2958,7 @@ 'dep_type': 'cipd', }, - 'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@98fee6234d1614a87f58a40b35643d3766259a26', + 'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@7c625f80e8cc10f33333a556ebb55a0443289b42', 'src/third_party/glslang/src': '{chromium_git}/external/github.com/KhronosGroup/glslang@09c541ee5b22bbac307987b50d86ec2b4f683d75', 'src/third_party/spirv-cross/src': '{chromium_git}/external/github.com/KhronosGroup/SPIRV-Cross@b8fcf307f1f347089e3c46eb4451d27f32ebc8d3', 'src/third_party/spirv-headers/src': '{chromium_git}/external/github.com/KhronosGroup/SPIRV-Headers@465055f6c9128772e20082e893d974146acf7a02', @@ -2967,7 +2967,7 @@ 'src/third_party/vulkan-loader/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Loader@9e84f0b6a16647e99b190674db1916d9e9da41a6', 'src/third_party/vulkan-tools/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Tools@734638ea758c82b65dc7e326ae790d797d375ae3', 'src/third_party/vulkan-utility-libraries/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Utility-Libraries@c15a1ac31670cb2ce61c235f070fb40ec6e42612', - 'src/third_party/vulkan-validation-layers/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-ValidationLayers@ea525ef7ecc94e55e821c784ab3f4b7ef1c4feba', + 'src/third_party/vulkan-validation-layers/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-ValidationLayers@d2575968391366f3eb2fa41656076a906dcf86ed', 'src/third_party/vulkan_memory_allocator': Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + 'cb0597213b0fcb999caa9ed08c2f88dc45eb7d50', @@ -3010,7 +3010,7 @@ Var('chromium_git') + '/webpagereplay.git' + '@' + Var('webpagereplay_revision'), 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + 'aa217206b9ce8b929dc56d112d670a5931ef8cc1', + Var('webrtc_git') + '/src.git' + '@' + '6f76a57334e3d1f4629fdbf7f9d9bc3c38feadc9', # 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. @@ -3034,7 +3034,7 @@ }, 'src/third_party/xnnpack/src': - Var('chromium_git') + '/external/github.com/google/XNNPACK.git' + '@' + '15e04ff8b61e0bc2118bad268447be5b2075aa66', + Var('chromium_git') + '/external/github.com/google/XNNPACK.git' + '@' + 'ee91cc745bc715bfa38c5e8241aeb435ca59f433', 'src/third_party/libei/cipd': { @@ -3236,7 +3236,7 @@ 'packages': [ { 'package': 'chromium/third_party/android_deps/autorolled', - 'version': 'Iv8_79hT6eno7q3HWp8otQ560vHfs_HhOBqWLLyLCscC', + 'version': 'bSNUpmo1wIHCZI5w3gxpUEAdVSqFPcTlstxTARVxcuwC', }, ], 'condition': 'checkout_android and non_git_source', @@ -3554,7 +3554,7 @@ 'src/chrome/browser/platform_experience/win': { 'url': Var('chrome_git') + '/chrome/browser/platform_experience/win.git' + '@' + - 'd93f2deda5040ed4675535a608ee89cf92d208cc', + 'eae77b923c7cb4953c2ed0a228942f9129e9a48e', 'condition': 'checkout_src_internal', }, @@ -3721,7 +3721,7 @@ 'src/components/optimization_guide/internal': { 'url': Var('chrome_git') + '/chrome/components/optimization_guide.git' + '@' + - '89bf056f23fe4545522f6c2fde4ed5e15957544e', + '53d3b7da14796b293ff6d501fb2b7ccbcff1086b', 'condition': 'checkout_src_internal', }, @@ -3977,7 +3977,7 @@ 'src/third_party/wix': { 'url': Var('chrome_git') + '/chrome/deps/wix/v3_5_2519.git' + '@' + - '1cda03778b09bee24389da73daef3de862da37fc', + 'd0745e3bc7a7a83b8848d9384ac0178036c1fd04', 'condition': 'checkout_win and checkout_src_internal', },
diff --git a/android_webview/browser/aw_contents.cc b/android_webview/browser/aw_contents.cc index 81bc430..04a07efc 100644 --- a/android_webview/browser/aw_contents.cc +++ b/android_webview/browser/aw_contents.cc
@@ -103,6 +103,7 @@ #include "content/public/browser/preload_pipeline_info.h" #include "content/public/browser/preloading.h" #include "content/public/browser/prerender_handle.h" +#include "content/public/browser/prerender_host_id.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_view_host.h" @@ -1465,7 +1466,7 @@ static_cast<NotRestoredReason>(reason)); } -int32_t AwContents::StartPrerendering( +int64_t AwContents::StartPrerendering( JNIEnv* env, const std::string& prerendering_url, const base::android::JavaRef<jobject>& j_prefetch_params, @@ -1492,7 +1493,7 @@ if (IsPrerenderHandleEquivalentTo(handle, url, no_vary_search_hint)) { handle->AddActivationCallback(std::move(activation_callback)); handle->AddErrorCallback(std::move(error_callback)); - return handle->GetHandleId(); + return handle->GetPrerenderHostId().GetUnsafeValue(); } // If the handle is not equivalent but has the same prerendering URL, cancel @@ -1543,9 +1544,9 @@ /*prerender_navigation_handle_callback=*/{}, /*allow_reuse=*/false); - int32_t handle_id = -1; + int64_t host_id = -1; if (prerender_handle) { - handle_id = prerender_handle->GetHandleId(); + host_id = prerender_handle->GetPrerenderHostId().GetUnsafeValue(); prerender_handle->AddActivationCallback(std::move(activation_callback)); prerender_handle->AddErrorCallback(std::move(error_callback)); prerender_handles_.push_back(std::move(prerender_handle)); @@ -1553,14 +1554,16 @@ base::SequencedTaskRunner::GetCurrentDefault()->PostTask( FROM_HERE, std::move(error_callback)); } - return handle_id; + return host_id; } -void AwContents::CancelPrerendering(JNIEnv* env, int32_t prerender_id) { - EraseIf( +void AwContents::CancelPrerendering(JNIEnv* env, int64_t prerender_id) { + content::PrerenderHostId host_id = + content::PrerenderHostId::FromUnsafeValue(prerender_id); + base::EraseIf( prerender_handles_, - [prerender_id](const std::unique_ptr<content::PrerenderHandle>& handle) { - return handle->GetHandleId() == prerender_id; + [host_id](const std::unique_ptr<content::PrerenderHandle>& handle) { + return handle->GetPrerenderHostId() == host_id; }); }
diff --git a/android_webview/browser/aw_contents.h b/android_webview/browser/aw_contents.h index 9f347aa..5bc94e5 100644 --- a/android_webview/browser/aw_contents.h +++ b/android_webview/browser/aw_contents.h
@@ -208,7 +208,7 @@ // Returns a non-negative non-zero integer when prerendering successfully // started. The returned integer can be passed to CancelPrerendering(). // Returns -1 when prerendering failed to start. - int32_t StartPrerendering( + int64_t StartPrerendering( JNIEnv* env, const std::string& prerendering_url, const base::android::JavaRef<jobject>& j_prefetch_params, @@ -218,7 +218,7 @@ // `prerender_id` should be a returned value of StartPrerendering(). If a // corresponding prerendering has already been canceled or activated, this // does nothing. - void CancelPrerendering(JNIEnv* env, int prerender_id); + void CancelPrerendering(JNIEnv* env, int64_t prerender_id); // Cancel all prerendering running on this contents regardless of how they are // triggered (StartPrerendering() or speculation rules).
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 93ad7b9..5ee49f6 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwContents.java +++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -1885,7 +1885,7 @@ // implementation, bind a tentative error message here. See also the comments in // `PrerenderHandleImpl::OnHostDestroyed()`. // TODO(crbug.com/41490450): Pass a more meaningful error message to the error callback. - int prerenderId = + long prerenderId = AwContentsJni.get() .startPrerendering( mNativeAwContents, @@ -5096,14 +5096,14 @@ void flushBackForwardCache(long nativeAwContents, int reason); - int startPrerendering( + long startPrerendering( long nativeAwContents, @JniType("std::string") @NonNull String prerenderingUrl, @Nullable AwPrefetchParameters prefetchParameters, @JniType("base::OnceClosure") Runnable activationCallback, @JniType("base::OnceClosure") Runnable errorCallback); - void cancelPrerendering(long nativeAwContents, int prerenderId); + void cancelPrerendering(long nativeAwContents, long prerenderId); void cancelAllPrerendering(long nativeAwContents); }
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 5d5b9d8..7cd8b5a6 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
@@ -1361,6 +1361,9 @@ Flag.baseFeature( "ConsolidateMetricsServiceLocales", "Consolidate the source of locale used by MetricsService."), + Flag.baseFeature( + AwFeatures.PRERENDER2_WARM_UP_COMPOSITOR_FOR_WEBVIEW, + "Requests the compositor warm-up for the WebView prerender triggers."), // Add new commandline switches and features above. The final entry should have a // trailing comma for cleaner diffs.
diff --git a/android_webview/test/BUILD.gn b/android_webview/test/BUILD.gn index eceff9c1..924e38d 100644 --- a/android_webview/test/BUILD.gn +++ b/android_webview/test/BUILD.gn
@@ -889,6 +889,7 @@ android_assets("android_webview_unittests_assets") { sources = [ "unittest/assets/asset_file.ogg" ] + deps = [ "//third_party/icu:icu_assets" ] } android_library("android_webview_unittests_java") {
diff --git a/android_webview/test/data/web_tests/webexposed/global-interface-listing-expected.txt b/android_webview/test/data/web_tests/webexposed/global-interface-listing-expected.txt index 52d2c3e..04f58278 100644 --- a/android_webview/test/data/web_tests/webexposed/global-interface-listing-expected.txt +++ b/android_webview/test/data/web_tests/webexposed/global-interface-listing-expected.txt
@@ -2007,7 +2007,10 @@ getter onmouseover getter onmouseup getter onmousewheel - getter onoverscroll + getter onoverscrollcancel + getter onoverscrollchanging + getter onoverscrollend + getter onoverscrollstart getter onpaste getter onpause getter onplay @@ -2233,7 +2236,10 @@ setter onmouseover setter onmouseup setter onmousewheel - setter onoverscroll + setter onoverscrollcancel + setter onoverscrollchanging + setter onoverscrollend + setter onoverscrollstart setter onpaste setter onpause setter onplay @@ -3833,7 +3839,10 @@ getter onmouseover getter onmouseup getter onmousewheel - getter onoverscroll + getter onoverscrollcancel + getter onoverscrollchanging + getter onoverscrollend + getter onoverscrollstart getter onpaste getter onpause getter onplay @@ -3973,7 +3982,10 @@ setter onmouseover setter onmouseup setter onmousewheel - setter onoverscroll + setter onoverscrollcancel + setter onoverscrollchanging + setter onoverscrollend + setter onoverscrollstart setter onpaste setter onpause setter onplay @@ -5844,7 +5856,10 @@ getter onmouseover getter onmouseup getter onmousewheel - getter onoverscroll + getter onoverscrollcancel + getter onoverscrollchanging + getter onoverscrollend + getter onoverscrollstart getter onpaste getter onpause getter onplay @@ -5959,7 +5974,10 @@ setter onmouseover setter onmouseup setter onmousewheel - setter onoverscroll + setter onoverscrollcancel + setter onoverscrollchanging + setter onoverscrollend + setter onoverscrollstart setter onpaste setter onpause setter onplay @@ -6956,7 +6974,8 @@ method constructor interface OverscrollEvent : Event attribute @@toStringTag - getter overscrollElement + getter overscrollTarget + getter overscrolling method constructor interface PageRevealEvent : Event attribute @@toStringTag @@ -8175,7 +8194,10 @@ getter onmouseover getter onmouseup getter onmousewheel - getter onoverscroll + getter onoverscrollcancel + getter onoverscrollchanging + getter onoverscrollend + getter onoverscrollstart getter onpaste getter onpause getter onplay @@ -8292,7 +8314,10 @@ setter onmouseover setter onmouseup setter onmousewheel - setter onoverscroll + setter onoverscrollcancel + setter onoverscrollchanging + setter onoverscrollend + setter onoverscrollstart setter onpaste setter onpause setter onplay @@ -12376,7 +12401,10 @@ getter onoffline getter ononline getter onorientationchange - getter onoverscroll + getter onoverscrollcancel + getter onoverscrollchanging + getter onoverscrollend + getter onoverscrollstart getter onpagehide getter onpagereveal getter onpageshow @@ -12603,7 +12631,10 @@ setter onoffline setter ononline setter onorientationchange - setter onoverscroll + setter onoverscrollcancel + setter onoverscrollchanging + setter onoverscrollend + setter onoverscrollstart setter onpagehide setter onpagereveal setter onpageshow
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd index f5176c6..bba79ce 100644 --- a/ash/ash_strings.grd +++ b/ash/ash_strings.grd
@@ -9229,6 +9229,301 @@ Uninstall </message> + <!-- ARC --> + <message name="IDS_ARC_PLAYSTORE_ICON_TITLE_BETA" desc="The Play Store icon title with the beta label in the launcher."> + Play Store + </message> + <message name="IDS_ARC_NOTIFICATION_DISPLAY_SOURCE" desc="Context title of the first-run notification that enables Android apps."> + Google Play + </message> + <message name="IDS_ARC_PLAYSTORE_SETTING_UP_TITLE" desc="The text tile which is shown when Play Store is initializing."> + Setting up Google Play... + </message> + <message name="IDS_ARC_OPT_IN_DIALOG_BUTTON_AGREE" desc="Agree button of the opt-in dialog for Android apps."> + Accept + </message> + <message name="IDS_ARC_OPT_IN_DIALOG_BUTTON_CANCEL" desc="Cancel button of the opt-in dialog for Android apps."> + Cancel + </message> + <message name="IDS_ARC_OPT_IN_DIALOG_BUTTON_NEXT" desc="Next button of the opt-in dialog for Android apps."> + More + </message> + <message name="IDS_ARC_OPT_IN_DIALOG_BUTTON_RETRY" desc="Retry button of the opt-in dialog for Android apps."> + Try again + </message> + <message name="IDS_ARC_OPT_IN_DIALOG_BUTTON_SEND_FEEDBACK" desc="Send feedback button of the opt-in dialog for Android apps."> + Send feedback + </message> + <message name="IDS_ARC_OPT_IN_DIALOG_BUTTON_RUN_NETWORK_TESTS" desc="Run network tests button of the opt-in dialog for Android apps."> + Check connection + </message> + <message name="IDS_ARC_OPT_IN_DIALOG_PROGRESS_TERMS" desc="Name of Terms Of Services loading progress of the opt-in dialog for Android apps."> + Just a sec... + </message> + <message name="IDS_ARC_OPT_IN_DIALOG_PROGRESS_ANDROID" desc="Name of Android loading progress of the opt-in dialog for Android apps."> + This may take a minute or so. + </message> + <message name="IDS_ARC_OPT_IN_DIALOG_AUTHORIZATION_FAILED" desc="Error message shown when an auth code is not returned by server."> + Authorization failed + </message> + <message name="IDS_ARC_OPT_IN_DIALOG_TERMS_OF_SERVICE" desc="Terms of service caption in the opt-in dialog for Android apps."> + Terms of Service + </message> + <message name="IDS_ARC_OPT_IN_DIALOG_METRICS_MANAGED_ENABLED" desc="Message in the opt-in dialog for Android apps in case metrics are managed on the device and on."> + Send usage and diagnostic data. This device is currently automatically sending diagnostic, device, and app usage data to Google. This will help system and app stability and other improvements. Some aggregate data will also help Google apps and partners, such as Android developers. This <ph name="BEGIN_LINK1"><a href="#" id="settings-link"></ph>setting<ph name="END_LINK1"></a><ex></a></ex></ph> is enforced by the owner. If your additional Web & App Activity setting is turned on, this data may be saved to your Google account. <ph name="BEGIN_LINK2"><a href="#" id="learn-more-link-metrics" aria-label="</ph>Learn more about metrics<ph name="BEGIN_LINK2_END">"></ph>Learn More<ph name="END_LINK2"></a><ex></a></ex></ph> + </message> + <message name="IDS_ARC_OPT_IN_DIALOG_METRICS_MANAGED_ENABLED_CHILD" desc="Message in the opt-in dialog for Android apps in case metrics are managed on the device and on, and a child account is in use."> + Send usage and diagnostic data. This device is currently automatically sending diagnostic, device, and app usage data to Google. This won't be used to identify your child and will help system and app stability and other improvements. Some aggregate data will also help Google apps and partners, such as Android developers. This <ph name="BEGIN_LINK1"><a href="#" id="settings-link"></ph>setting<ph name="END_LINK1"></a><ex></a></ex></ph> is enforced by the owner. If additional Web & App Activity setting is turned on for your child, this data may be saved to their Google account. <ph name="BEGIN_LINK2"><a href="#" id="learn-more-link-metrics" aria-label="</ph>Learn more about metrics<ph name="BEGIN_LINK2_END">"></ph>Learn More<ph name="END_LINK2"></a><ex></a></ex></ph> + </message> + <message name="IDS_ARC_OPT_IN_DIALOG_METRICS_MANAGED_DISABLED" desc="Message in the opt-in dialog for Android apps in case metrics are managed on the device and off."> + Send usage and diagnostic data. Help improve your Android experience by automatically sending diagnostic, device, and app usage data to Google. This will help system and app stability and other improvements. Some aggregate data will also help Google apps and partners, such as Android developers. This <ph name="BEGIN_LINK1"><a href="#" id="settings-link"></ph>setting<ph name="END_LINK1"></a><ex></a></ex></ph> is enforced by the owner. The owner may choose to send diagnostic and usage data for this device to Google. If your additional Web & App Activity setting is turned on, this data may be saved to your Google account. <ph name="BEGIN_LINK2"><a href="#" id="learn-more-link-metrics" aria-label="</ph>Learn more about metrics<ph name="BEGIN_LINK2_END">"></ph>Learn More<ph name="END_LINK2"></a><ex></a></ex></ph> + </message> + <message name="IDS_ARC_OPT_IN_DIALOG_METRICS_MANAGED_DISABLED_CHILD" desc="Message in the opt-in dialog for Android apps in case metrics are managed on the device and off, and a child account is in use."> + Send usage and diagnostic data. Help improve your child's Android experience by automatically sending diagnostic, device, and app usage data to Google. This won't be used to identify your child and will help system and app stability and other improvements. Some aggregate data will also help Google apps and partners, such as Android developers. This <ph name="BEGIN_LINK1"><a href="#" id="settings-link"></ph>setting<ph name="END_LINK1"></a><ex></a></ex></ph> is enforced by the owner. The owner may choose to send diagnostic and usage data for this device to Google. If additional Web & App Activity setting is turned on for your child, this data may be saved to their Google account. <ph name="BEGIN_LINK2"><a href="#" id="learn-more-link-metrics" aria-label="</ph>Learn more about metrics<ph name="BEGIN_LINK2_END">"></ph>Learn More<ph name="END_LINK2"></a><ex></a></ex></ph> + </message> + <message name="IDS_ARC_OPT_IN_DIALOG_METRICS_ENABLED" desc="Message in the opt-in dialog for Android apps in case metrics are already enabled on the device. User has no way to deactivate them using opt-in dialog."> + Send usage and diagnostic data. This device is currently automatically sending diagnostic, device, and app usage data to Google. This will help system and app stability and other improvements. Some aggregate data will also help Google apps and partners, such as Android developers. If your additional Web & App Activity setting is turned on, this data may be saved to your Google Account. <ph name="BEGIN_LINK2"><a href="#" id="learn-more-link-metrics" aria-label="</ph>Learn more about metrics<ph name="BEGIN_LINK2_END">"></ph>Learn More<ph name="END_LINK2"></a><ex></a></ex></ph> + </message> + <message name="IDS_ARC_OPT_IN_DIALOG_METRICS_ENABLED_CHILD" desc="Message in the opt-in dialog for Android apps in case metrics are already enabled on the device, and a child account is in use. User has no way to deactivate them using opt-in dialog."> + Send usage and diagnostic data. This device is currently automatically sending diagnostic, device, and app usage data to Google. This won't be used to idenfity your child and will help system and app stability and other improvements. Some aggregate data will also help Google apps and partners, such as Android developers. If additional Web & App Activity setting is turned on for your child, this data may be saved to their Google Account. <ph name="BEGIN_LINK2"><a href="#" id="learn-more-link-metrics" aria-label="</ph>Learn more about metrics<ph name="BEGIN_LINK2_END">"></ph>Learn More<ph name="END_LINK2"></a><ex></a></ex></ph> + </message> + <message name="IDS_ARC_OPT_IN_DIALOG_METRICS_DISABLED" desc="Message in the opt-in dialog for Android apps in case metrics are disabled on the device. User has an option to active them using opt-in dialog"> + Send usage and diagnostic data. Help improve your Android experience by automatically sending diagnostic, device, and app usage data to Google. This will help system and app stability and other improvements. Some aggregate data will also help Google apps and partners, such as Android developers. If your additional Web & App Activity setting is turned on, this data may be saved to your Google account. <ph name="BEGIN_LINK1"><a href="#" id="learn-more-link-metrics" aria-label="</ph>Learn more about metrics<ph name="BEGIN_LINK1_END">"></ph>Learn More<ph name="END_LINK1"></a><ex></a></ex></ph> + </message> + <message name="IDS_ARC_OPT_IN_DIALOG_METRICS_DISABLED_CHILD" desc="Message in the opt-in dialog for Android apps in case metrics are disabled on the device, and a child account is in use. User has an option to active them using opt-in dialog"> + Send usage and diagnostic data. Help improve your child's Android experience by automatically sending diagnostic, device, and app usage data to Google. This won't be used to identify your child and will help system and app stability and other improvements. Some aggregate data will also help Google apps and partners, such as Android developers. If additional Web & App Activity is turned on for you child, this data may be saved to their Google account. <ph name="BEGIN_LINK1"><a href="#" id="learn-more-link-metrics" aria-label="</ph>Learn more about metrics<ph name="BEGIN_LINK1_END">"></ph>Learn More<ph name="END_LINK1"></a><ex></a></ex></ph> + </message> + <message name="IDS_ARC_OPT_IN_DIALOG_BACKUP_RESTORE" desc="Message in the opt-in dialog for users to enable Backup and Restore for Android apps."> + Back up to Google Drive. Easily restore your data or switch device at any time. Your backup includes app data. Your backups are uploaded to Google and encrypted using your Google Account password. <ph name="BEGIN_LINK1"><a href="#" id="learn-more-link-backup-restore" aria-label="</ph>Learn more about backup<ph name="BEGIN_LINK1_END">"></ph>Learn More<ph name="END_LINK1"></a><ex></a></ex></ph> + </message> + <message name="IDS_ARC_OPT_IN_DIALOG_BACKUP_RESTORE_CHILD" desc="Message in the opt-in dialog for users to enable Backup and Restore for Android apps, and a child account is in use."> + Back up to Google Drive. Easily restore data or switch device at any time. This backup includes app data. Backups are uploaded to Google and encrypted using your child's Google Account password. <ph name="BEGIN_LINK1"><a href="#" id="learn-more-link-backup-restore" aria-label="</ph>Learn more about backup<ph name="BEGIN_LINK1_END">"></ph>Learn More<ph name="END_LINK1"></a><ex></a></ex></ph> + </message> + <message name="IDS_ARC_OPT_IN_DIALOG_BACKUP_RESTORE_LABEL" desc="This string is spoken when ChromeVox focuses the checkbox to enable Backup and Restore for Android apps in the opt-in dialog." is_accessibility_with_no_ui="true"> + Back up to Google Drive. Easily restore your data or switch device at any time. Your backup includes app data. Your backups are uploaded to Google and encrypted using your Google Account password. + </message> + <message name="IDS_ARC_OPT_IN_DIALOG_BACKUP_RESTORE_CHILD_LABEL" desc="This string is spoken when ChromeVox focuses the checkbox to enable Backup and Restore for Android apps in the opt-in dialog, and a child account is in use." is_accessibility_with_no_ui="true"> + Back up to Google Drive. Easily restore data or switch device at any time. This backup includes app data. Backups are uploaded to Google and encrypted using your child's Google Account password. + </message> + <message name="IDS_ARC_OPT_IN_LOCATION_SETTING" desc="Message in the opt-in dialog for Android apps for the user to turn on Google location services."> + Use location. Allow apps and services with location permission to use your device’s location. Google may collect location data periodically and use this data in an anonymous way to improve location accuracy and location-based services. <ph name="BEGIN_LINK1"><a href="#" id="learn-more-link-location-service" aria-label="</ph>Learn more about location<ph name="BEGIN_LINK1_END">"></ph>Learn More<ph name="END_LINK1"></a><ex></a></ex></ph> + </message> + <message name="IDS_ARC_OPT_IN_LOCATION_SETTING_CHILD" desc="Message in the opt-in dialog for Android apps for the user to turn on Google location services, and a child account is in use."> + Use location. Allow apps and services with location permission to use this device’s location. Google may collect location data periodically and use this data in an anonymous way to improve location accuracy and location-based services. <ph name="BEGIN_LINK1"><a href="#" id="learn-more-link-location-service" aria-label="</ph>Learn more about location<ph name="BEGIN_LINK1_END">"></ph>Learn More<ph name="END_LINK1"></a><ex></a></ex></ph> + </message> + <message name="IDS_ARC_CROS_OPT_IN_LOCATION_SETTING" desc="Message in the opt-in dialog for Android apps for the user to turn on Google location services."> + Use location. Allow ChromeOS and Android apps, websites, and services with location permission to use your device's location. Location Accuracy provides more accurate location for Android apps and services. To do this, Google periodically processes information about device sensors and wireless signals from your device to crowdsource wireless signal locations. These are used without identifying you to improve location accuracy and location-based services and to improve, provide, and maintain Google's services based on Google's and third parties' legitimate interests to serve users' needs. <ph name="BEGIN_LINK1"><a href="#" id="learn-more-link-location-service"></ph>Learn more about using location<ph name="END_LINK1"></a><ex></a></ex></ph> + </message> + <message name="IDS_ARC_CROS_OPT_IN_LOCATION_SETTING_CHILD" desc="Message in the opt-in dialog for Android apps for the user to turn on Google location services, and a child account is in use."> + Use location. Allow ChromeOS and Android apps, websites, and services with location permission to use this device's location. Location Accuracy provides more accurate location for Android apps and services. To do this, Google periodically processes information about device sensors and wireless signals from this device to crowdsource wireless signal locations. These are used without identifying any individual to improve location accuracy and location-based services and to improve, provide, and maintain Google's services based on Google's and third parties' legitimate interests to serve users' needs. <ph name="BEGIN_LINK1"><a href="#" id="learn-more-link-location-service"></ph>Learn more about using location<ph name="END_LINK1"></a><ex></a></ex></ph> + </message> + <message name="IDS_ARC_OPT_IN_PAI" desc="Message in the opt-in dialog for Play auto install."> + Install updates & apps. By continuing, you agree that this device may also automatically download and install updates and apps from Google, your carrier, and your device's manufacturer, possibly using cellular data. Some of these apps may offer in-app purchases. <ph name="BEGIN_LINK1"><a href="#" id="learn-more-link-pai" aria-label="</ph>Learn more about play auto install<ph name="BEGIN_LINK1_END">"></ph>Learn More<ph name="END_LINK1"></a><ex></a></ex></ph> + </message> + <message name="IDS_ARC_OPT_IN_GOOGLE_SERVICE_CONFIRMATION" desc="Message in the opt-in dialog for Accepting Google services."> + Tap “Accept” to confirm your selection of these Google services settings. + </message> + <message name="IDS_ARC_OPT_IN_LEARN_MORE_CLOSE" desc="Text for close button in learn more dialog"> + Close + </message> + <message name="IDS_ARC_OPT_IN_LEARN_MORE_STATISTICS_TITLE" desc="Title for pop up overlay dialog when user clicks learn more UMA"> + Usage and diagnostic data + </message> + <message name="IDS_ARC_OPT_IN_LEARN_MORE_STATISTICS" desc="Message shown in pop up overlay dialog when user clicks learn more UMA"> + <ph name="BEGIN_PARAGRAPH1"><p></ph>This is general information about your device and how you use it (such as battery level, system and app activity, and errors). The data will be used to improve Android, and some aggregated information will also help Google apps and partners, such as Android developers, make their apps and products better.<ph name="END_PARAGRAPH1"></p></ph> + <ph name="BEGIN_PARAGRAPH2"><p></ph>Turning off this feature doesn't affect your device's ability to send the information needed for essential services such as system updates and security.<ph name="END_PARAGRAPH2"></p></ph> + <ph name="BEGIN_PARAGRAPH3"><p></ph>The owner can control this feature from Settings > Advanced > Automatically send diagnostic and usage data to Google.<ph name="END_PARAGRAPH3"></p></ph> + <ph name="BEGIN_PARAGRAPH4"><p></ph>If your additional Web & App Activity setting is turned on, this data may be saved to your Google Account. You can see your data, delete it, and change your account settings at account.google.com.<ph name="END_PARAGRAPH4"></p></ph> + </message> + <message name="IDS_ARC_OPT_IN_LEARN_MORE_STATISTICS_CHILD" desc="Message shown in pop up overlay dialog when user clicks learn more UMA, and a child account is in use"> + <ph name="BEGIN_PARAGRAPH1"><p></ph>This is general information about this device and how it's used (such as battery level, system and app activity, and errors). The data will be used to improve Android, and some aggregated information will also help Google apps and partners, such as Android developers, make their apps and products better.<ph name="END_PARAGRAPH1"></p></ph> + <ph name="BEGIN_PARAGRAPH2"><p></ph>Turning off this feature doesn't affect this device's ability to send the information needed for essential services such as system updates and security.<ph name="END_PARAGRAPH2"></p></ph> + <ph name="BEGIN_PARAGRAPH3"><p></ph>The owner can control this feature from Settings > Advanced > Automatically send diagnostic and usage data to Google.<ph name="END_PARAGRAPH3"></p></ph> + <ph name="BEGIN_PARAGRAPH4"><p></ph>If additional Web & App Activity setting is turned on for your child, this data may be saved to their Google Account. Learn more about these settings and how to adjust them at families.google.com.<ph name="END_PARAGRAPH4"></p></ph> + </message> + <message name="IDS_ARC_OPT_IN_LEARN_MORE_BACKUP_AND_RESTORE_TITLE" desc="Title for pop up overlay dialog when user clicks learn more backup and restore"> + Back up to Google Drive + </message> + <message name="IDS_ARC_OPT_IN_LEARN_MORE_BACKUP_AND_RESTORE" desc="Message shown in pop up overlay dialog when user clicks learn more backup and restore"> + <ph name="BEGIN_PARAGRAPH1"><p></ph>Back up to Google Drive. Easily restore your data or switch device at any time. Your backup includes app data.<ph name="END_PARAGRAPH1"></p></ph> + <ph name="BEGIN_PARAGRAPH2"><p></ph>Your backups are uploaded to Google and encrypted using your Google Account password.<ph name="END_PARAGRAPH2"></p></ph> + <ph name="BEGIN_PARAGRAPH3"><p></ph>App data can be any data that an app has saved (based on developer settings), including data such as contacts, messages, and photos.<ph name="END_PARAGRAPH3"></p></ph> + <ph name="BEGIN_PARAGRAPH4"><p></ph>Backup data will not count toward your Drive storage quota.<ph name="END_PARAGRAPH4"></p></ph> + <ph name="BEGIN_PARAGRAPH5"><p></ph>You can turn this service off in Settings.<ph name="END_PARAGRAPH5"></p></ph> + </message> + <message name="IDS_ARC_OPT_IN_LEARN_MORE_BACKUP_AND_RESTORE_CHILD" desc="Message shown in pop up overlay dialog when user clicks learn more backup and restore, and a child account is in use"> + <ph name="BEGIN_PARAGRAPH1"><p></ph>App data can be any data that an app has saved (based on developer settings), including data such as contacts, messages, and photos.<ph name="END_PARAGRAPH1"></p></ph> + <ph name="BEGIN_PARAGRAPH2"><p></ph>Backup data will not count toward your child's Drive storage quota.<ph name="END_PARAGRAPH2"></p></ph> + <ph name="BEGIN_PARAGRAPH3"><p></ph>You can turn this service off in Settings.<ph name="END_PARAGRAPH3"></p></ph> + </message> + <message name="IDS_ARC_OPT_IN_LEARN_MORE_LOCATION_SERVICES_TITLE" desc="Title for pop up overlay dialog when user clicks learn more location services"> + Location Services + </message> + <message name="IDS_ARC_OPT_IN_LEARN_MORE_LOCATION_SERVICES" desc="Message shown in pop up overlay dialog when user clicks learn more location services"> + <ph name="BEGIN_PARAGRAPH1"><p></ph>Google's location service uses sources like Wi-Fi, mobile networks, and sensors to help estimate your device’s location.<ph name="END_PARAGRAPH1"></p></ph> + <ph name="BEGIN_PARAGRAPH2"><p></ph>You can turn off Location by turning off the main Location setting on your device. You can also turn off the use of Wi-Fi, mobile networks, and sensors for location in location settings.<ph name="END_PARAGRAPH2"></p></ph> + </message> + <message name="IDS_ARC_OPT_IN_LEARN_MORE_LOCATION_SERVICES_CHILD" desc="Message shown in pop up overlay dialog when user clicks learn more location services, and a child account is in use"> + <ph name="BEGIN_PARAGRAPH1"><p></ph>Google's location service uses sources like Wi-Fi, mobile networks, and sensors to help estimate this device’s location.<ph name="END_PARAGRAPH1"></p></ph> + <ph name="BEGIN_PARAGRAPH2"><p></ph>You can turn off Location by turning off the main Location setting on this device. You can also turn off the use of Wi-Fi, mobile networks, and sensors for location in location settings.<ph name="END_PARAGRAPH2"></p></ph> + </message> + <message name="IDS_ARC_CROS_OPT_IN_LEARN_MORE_LOCATION_SERVICES" desc="Message shown in pop up overlay dialog when user clicks learn more location services"> + <ph name="BEGIN_PARAGRAPH1"><p></ph>When Location Accuracy is on, information about wireless signals, such as Wi-Fi access points and cellular network towers, along with device sensor data, such as accelerometer and gyroscope, is used to estimate more accurate device location, which Android apps and services use to provide location-based features. To do this, Google periodically collects information about device sensors and wireless signals near you to contribute to crowdsourced wireless signal locations.<ph name="END_PARAGRAPH1"></p></ph> + <ph name="BEGIN_PARAGRAPH2"><p></ph>Google uses this information without identifying you to: improve location accuracy and location-based services; and generally improve, provide, and maintain Google's services. We process this information based on the legitimate interests of Google and third parties to serve users' needs.<ph name="END_PARAGRAPH2"></p></ph> + <ph name="BEGIN_PARAGRAPH3"><p></ph>You can turn off Location Accuracy at any time in your device's location settings under Settings > Privacy and security > Privacy controls > Location access > Advanced location settings. If Location Accuracy is off, no Location Accuracy data will be collected. For Android apps and services, only IP address is used, if available, to determine your device's location, which may impact the availability and accuracy of locations for Android apps and services such as Google Maps.<ph name="END_PARAGRAPH3"></p></ph> + <ph name="BEGIN_PARAGRAPH4"><p></ph><ph name="LINK_BEGIN"><a id="LocationAccuracyLink" href="$1<ex>https://google.com/</ex>" target="_blank"></ph>Learn more about Location Accuracy<ph name="LINK_END"></a></ph><ph name="END_PARAGRAPH4"></p></ph> + </message> + <message name="IDS_ARC_CROS_OPT_IN_LEARN_MORE_LOCATION_SERVICES_CHILD" desc="Message shown in pop up overlay dialog when user clicks learn more location services, and a child account is in use"> + <ph name="BEGIN_PARAGRAPH1"><p></ph>When Location Accuracy is on, information about wireless signals, such as Wi-Fi access points and cellular network towers, along with device sensor data, such as accelerometer and gyroscope, is used to estimate more accurate device location, which Android apps and services use to provide location-based features. To do this, Google periodically collects information about device sensors and wireless signals near this device to contribute to crowdsourced wireless signal locations.<ph name="END_PARAGRAPH1"></p></ph> + <ph name="BEGIN_PARAGRAPH2"><p></ph>Google uses this information collected from this device to: improve location accuracy and location-based services; and generally improve, provide, and maintain Google's services. We process this information based on the legitimate interests of Google and third parties to serve users' needs. This information is not used to identify any individual.<ph name="END_PARAGRAPH2"></p></ph> + <ph name="BEGIN_PARAGRAPH3"><p></ph>You can turn off Location Accuracy at any time in this device's location settings under Settings > Privacy and security > Privacy controls > Location access > Advanced location settings. If Location Accuracy is off, no Location Accuracy data will be collected. For Android apps and services, only IP address is used, if available, to determine this device's location, which may impact the availability and accuracy of locations for Android apps and services such as Google Maps.<ph name="END_PARAGRAPH3"></p></ph> + <ph name="BEGIN_PARAGRAPH4"><p></ph><ph name="LINK_BEGIN"><a id="LocationAccuracyLink" href="$1<ex>https://google.com/</ex>" target="_blank"></ph>Learn more about Location Accuracy<ph name="LINK_END"></a></ph><ph name="END_PARAGRAPH4"></p></ph> + </message> + <message name="IDS_ARC_OPT_IN_LEARN_MORE_PAI_SERVICE_TITLE" desc="Title for pop up overlay dialog when user clicks learn more play auto install services"> + Install Updates and Apps + </message> + <message name="IDS_ARC_OPT_IN_LEARN_MORE_PAI_SERVICE" desc="Message shown in pop up overlay dialog when user clicks learn more play auto install services."> + <ph name="BEGIN_PARAGRAPH1"><p></ph>To remove apps, go to Settings > Google Play Store > Manage Android preferences > Apps or Application manager. Then tap the app you want to uninstall (you may need to swipe right or left to find the app). Then tap Uninstall or Disable.<ph name="END_PARAGRAPH1"></p></ph> + </message> + <message name="IDS_ARC_OPT_IN_CONTACT_ADMIN_TITLE" desc="Title of dialog shown when user tries to launch ARC app but ARC is diabled by admin"> + This app requires access to the Play Store + </message> + <message name="IDS_ARC_OPT_IN_CONTACT_ADMIN_CONTEXT" desc="Text of dialog shown when user tries to launch ARC app but ARC is diabled by admin"> + To ask for access, contact the administrator of this device. + </message> + <message name="IDS_ARC_OPT_IN_PRIVACY_POLICY_LINK" desc="Text of the Link to Goolge Privacy Policy in opt-in dialog"> + Google privacy policy + </message> + <message name="IDS_ARC_SIGN_IN_NETWORK_ERROR" desc="Android sign-in error because of network error"> + Network connection was lost. Check your network connection or try another Wi-Fi network. + </message> + <message name="IDS_ARC_SIGN_IN_GMS_SIGNIN_ERROR" desc="Android sign-in error because of service is unavailable"> + Couldn't connect to Google Play. Check your network connection and try again. Error code: <ph name="ERROR_CODE">$1<ex>7</ex></ph>. + </message> + <message name="IDS_ARC_SIGN_IN_BAD_AUTHENTICATION_ERROR" desc="Android sign-in error because of bad authentification"> + Couldn't verify your account. Please try again or restart your Chromebook. + </message> + <message name="IDS_ARC_SIGN_IN_GMS_CHECKIN_ERROR" desc="Android sign-in error because of GMS services are unavailable"> + Couldn't connect with Google services. Check your network connection and try again. Error code: <ph name="ERROR_CODE">$1<ex>7</ex></ph>. + </message> + <message name="IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_ACCOUNT_MISSING_ERROR" desc="Android permament sign-in error because of cloud provision flow failed"> + Provisioning failed because your account details could not be retrieved. Please try again. Error code: <ph name="ERROR_CODE">$1<ex>7</ex></ph>. + </message> + <message name="IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_DOMAIN_JOIN_FAIL_ERROR" desc="Android permament sign-in error because of cloud provision flow failed"> + Can't join the device to the domain. Please try again or contact your device owner or administrator. Error code: <ph name="ERROR_CODE">$1<ex>7</ex></ph>. + </message> + <message name="IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_ENROLLMENT_TOKEN_INVALID" desc="Android permament sign-in error because of cloud provision flow failed"> + Device enrollment token is invalid. Please contact your device owner or administrator. Error code: <ph name="ERROR_CODE">$1<ex>7</ex></ph>. + </message> + <message name="IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_INTERRUPTED_ERROR" desc="Android permament sign-in error because of cloud provision flow failed"> + Provisioning flow was interrupted. Please try again or contact your device owner or administrator. Error code: <ph name="ERROR_CODE">$1<ex>7</ex></ph>. + </message> + <message name="IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_NETWORK_ERROR" desc="Android permament sign-in error because of cloud provision flow failed"> + Couldn’t connect with the server. Check your network connection and try again. If you're still having trouble, try restarting your Chromebook. Error code: <ph name="ERROR_CODE">$1<ex>7</ex></ph>. + </message> + <message name="IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_PERMANENT_ERROR" desc="Android permament sign-in error because of cloud provision flow failed"> + Something went wrong. Please contact your device owner or administrator. Error code: <ph name="ERROR_CODE">$1<ex>7</ex></ph>. + </message> + <message name="IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_TRANSIENT_ERROR" desc="Android transient sign-in error because of cloud provision flow failed"> + Something went wrong. Please try again or contact your device owner or administrator. Error code: <ph name="ERROR_CODE">$1<ex>7</ex></ph>. + </message> + <message name="IDS_ARC_LOW_DISK_SPACE_ERROR" desc="Android sign-in failed due to low disk space"> + Disk space is critically low. Please free up disk space. + </message> + <message name="IDS_ARC_LOW_DISK_SPACE_PRE_STOP_NOTIFICATION_TITLE" desc="Title of the notification warning Android users that they are critically low on disk space"> + Device disk space critically low + </message> + <message name="IDS_ARC_LOW_DISK_SPACE_PRE_STOP_NOTIFICATION_MESSAGE" desc="Message in the notification warning Android users that they are critically low on disk space"> + Free up space to avoid losing access to Android. + </message> + <message name="IDS_ARC_LOW_DISK_SPACE_POST_STOP_NOTIFICATION_TITLE" desc="Title of the notification shown when Android is stopped due to low disk space"> + Android apps were stopped + </message> + <message name="IDS_ARC_LOW_DISK_SPACE_POST_STOP_NOTIFICATION_MESSAGE" desc="Message in the notification shown when Android is stopped due to low disk space"> + Free up disk space to launch Android apps. + </message> + <message name="IDS_ARC_SIGN_IN_UNKNOWN_ERROR" desc="Android sign-in error because of unknown error"> + Something went wrong. Error code: <ph name="ERROR_CODE">$1<ex>7</ex></ph>. + </message> + <message name="IDS_ARC_SERVER_COMMUNICATION_ERROR" desc="Android sign-in error because of server communication error"> + Couldn’t connect with the server. Check your network connection and try again. If you're still having trouble, try restarting your Chromebook. + </message> + <message name="IDS_ARC_ANDROID_MANAGEMENT_REQUIRED_ERROR" desc="Error message shown when Android management is required for an unmanaged ChromeOS user."> + Your organization has not enabled Google Play Store for your account. Contact your administrator for more information. + </message> + <message name="IDS_ARC_NETWORK_UNAVAILABLE_ERROR" desc="Error message shown when Android cannot set up network connection."> + Network connection cannot be established. Check your network connection and try again. + </message> + <message name="IDS_ARC_CRITICALLY_LOW_DISK_NOTIFICATION_TITLE" desc="Title of the notification warning users that they are critically low on disk space and Android apps can not be launched."> + Device disk space critically low + </message> + <message name="IDS_ARC_CRITICALLY_LOW_DISK_NOTIFICATION_MESSAGE" desc="Notification text warning users that they are critically low on disk space and Android apps can not be launched."> + Free up disk space to launch Android apps. + </message> + <message name="IDS_ARC_MANAGED_PROVISION_NOTIFICATION_TITLE" desc="Title of the notification shown to user during ARC provision when the ARC opt-in flow happens silently due to enterprise policies"> + Google Play Store + </message> + <message name="IDS_ARC_MANAGED_PROVISION_NOTIFICATION_MESSAGE" desc="Notification shown to user during ARC provision when the ARC opt-in flow happens silently due to enterprise policies."> + Installing the Google Play Store on your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph>. This could take a few minutes. + </message> + <message name="IDS_ARC_OOBE_TERMS_HEADING" desc="Heading of the Arc Terms OOBE dialog."> + Google Play apps and services + </message> + <message name="IDS_ARC_OOBE_TERMS_DESCRIPTION" desc="Description of the Arc Terms OOBE dialog."> + Use Google Play to install Android apps + </message> + <message name="IDS_ARC_OOBE_TERMS_POPUP_HELP_CLOSE_BUTTON" desc="Close button of the popup local help of Arc Play Store Terms OOBE dialog."> + Close + </message> + <message name="IDS_ARC_POPUP_HELP_LOADING" desc="Loading message of the Arc popup help."> + Loading... + </message> + <message name="IDS_ARC_CHILD_TRANSITION_TITLE" desc="Title of the notification shown when the user tries to activate ARC app and transition from child to regular user or from regular to child user is not completed."> + Action not available + </message> + <message name="IDS_ARC_CHILD_TRANSITION_MESSAGE" desc="Message of the notification shown when the user tries to activate ARC app and transition from child to regular user or from regular to child user is not completed."> + Please try again in a few moments + </message> + <message name="IDS_ARC_DATA_REMOVAL_CONFIRMATION_HEADING" desc="Heading text in the content area of the confirmation for data removal in case ARC comes to wrong state."> + To use apps from Google Play, you must first restore your apps. Some data may have been lost. + </message> + <message name="IDS_ARC_DATA_REMOVAL_CONFIRMATION_OK_BUTTON" desc="Text for the OK button of the confirmation for data removal in case ARC comes to wrong state."> + Restore apps + </message> + <message name="IDS_ARC_DATA_REMOVAL_CONFIRMATION_TITLE" desc="Title of the confirmation for data removal in case in case ARC comes to wrong state."> + Something went wrong + </message> + <message name="IDS_ARC_MIGRATE_ENCRYPTION_NOTIFICATION_TITLE" desc="Title of the notification to navigate the user to first update the device encryption before running Android apps."> + Install critical update + </message> + <message name="IDS_ARC_MIGRATE_ENCRYPTION_NOTIFICATION_MESSAGE" desc="Main message of the notification to navigate the user to first update the device encryption before running Android apps."> + To use Android apps and keep your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph> working properly, sign in again and update. + </message> + <message name="IDS_ARC_MIGRATE_ENCRYPTION_NOTIFICATION_LOW_BATTERY_MESSAGE" desc="Main message of the notification to navigate the user to first update the device encryption before running Android apps."> + To use Android apps, charge & update your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph>. + </message> + <message name="IDS_ARC_USB_PERMISSION_TITLE" desc="Titlebar of Android app USB permissions prompt window"> + Confirm USB Permission + </message> + <message name="IDS_ARC_USB_SCAN_DEVICE_LIST_PERMISSION_HEADING" desc="Heading text in the content area of the Android app scan device list permission prompt. Tells the user the app will be able to scan attached USB device list if confirmed."> + Allow "<ph name="APP_NAME">$1<ex>Gmail Checker</ex></ph>" to get the list of your attached USB devices? + </message> + <message name="IDS_ARC_USB_ACCESS_PERMISSION_HEADING" desc="Heading text in the content area of the Android app USB device access permission prompt. Tells the user the app will be able to access the usb device if confirmed."> + Allow "<ph name="APP_NAME">$1<ex>Gmail Checker</ex></ph>" to access: + </message> + <message name="IDS_ARC_ACCESSIBILITY_SELECTED_STATUS" desc="Text used by screen readers that represents that the element is selected."> + Selected + </message> + <message name="IDS_ARC_ACCESSIBILITY_WINDOW_TITLE_IN_PIP" is_accessibility_with_no_ui="true" desc="A hint text that is read by screen readers appended to the window title, explaning that the window is in the picture-pi-picture mode."> + Picture in picture + </message> + <message name="IDS_ARC_SDK_VERSION_LABEL" desc="Label for Android SDK Version bundled with ARC"> + SDK Version: + </message> + <message name="IDS_ARC_SDK_VERSION_UNKNOWN" desc="Message displayed when the Android SDK Version can not be found"> + Unknown + </message> + <!-- Borealis strings --> <!-- TODO(danielng): Add string descriptions and remove translateable tags when strings are finalized. -->
diff --git a/chrome/app/chromeos_strings_grdp/IDS_CROS_OPT_IN_LEARN_MORE_LOCATION_SERVICES.png.sha1 b/ash/ash_strings_grd/IDS_ARC_CROS_OPT_IN_LEARN_MORE_LOCATION_SERVICES.png.sha1 similarity index 100% rename from chrome/app/chromeos_strings_grdp/IDS_CROS_OPT_IN_LEARN_MORE_LOCATION_SERVICES.png.sha1 rename to ash/ash_strings_grd/IDS_ARC_CROS_OPT_IN_LEARN_MORE_LOCATION_SERVICES.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_CROS_OPT_IN_LEARN_MORE_LOCATION_SERVICES_CHILD.png.sha1 b/ash/ash_strings_grd/IDS_ARC_CROS_OPT_IN_LEARN_MORE_LOCATION_SERVICES_CHILD.png.sha1 similarity index 100% rename from chrome/app/chromeos_strings_grdp/IDS_CROS_OPT_IN_LEARN_MORE_LOCATION_SERVICES_CHILD.png.sha1 rename to ash/ash_strings_grd/IDS_ARC_CROS_OPT_IN_LEARN_MORE_LOCATION_SERVICES_CHILD.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_CROS_OPT_IN_LOCATION_SETTING.png.sha1 b/ash/ash_strings_grd/IDS_ARC_CROS_OPT_IN_LOCATION_SETTING.png.sha1 similarity index 100% rename from chrome/app/chromeos_strings_grdp/IDS_CROS_OPT_IN_LOCATION_SETTING.png.sha1 rename to ash/ash_strings_grd/IDS_ARC_CROS_OPT_IN_LOCATION_SETTING.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_CROS_OPT_IN_LOCATION_SETTING_CHILD.png.sha1 b/ash/ash_strings_grd/IDS_ARC_CROS_OPT_IN_LOCATION_SETTING_CHILD.png.sha1 similarity index 100% rename from chrome/app/chromeos_strings_grdp/IDS_CROS_OPT_IN_LOCATION_SETTING_CHILD.png.sha1 rename to ash/ash_strings_grd/IDS_ARC_CROS_OPT_IN_LOCATION_SETTING_CHILD.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_ARC_LOW_DISK_SPACE_ERROR.png.sha1 b/ash/ash_strings_grd/IDS_ARC_LOW_DISK_SPACE_ERROR.png.sha1 similarity index 100% rename from chrome/app/chromeos_strings_grdp/IDS_ARC_LOW_DISK_SPACE_ERROR.png.sha1 rename to ash/ash_strings_grd/IDS_ARC_LOW_DISK_SPACE_ERROR.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_ARC_LOW_DISK_SPACE_POST_STOP_NOTIFICATION_MESSAGE.png.sha1 b/ash/ash_strings_grd/IDS_ARC_LOW_DISK_SPACE_POST_STOP_NOTIFICATION_MESSAGE.png.sha1 similarity index 100% rename from chrome/app/chromeos_strings_grdp/IDS_ARC_LOW_DISK_SPACE_POST_STOP_NOTIFICATION_MESSAGE.png.sha1 rename to ash/ash_strings_grd/IDS_ARC_LOW_DISK_SPACE_POST_STOP_NOTIFICATION_MESSAGE.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_ARC_LOW_DISK_SPACE_POST_STOP_NOTIFICATION_TITLE.png.sha1 b/ash/ash_strings_grd/IDS_ARC_LOW_DISK_SPACE_POST_STOP_NOTIFICATION_TITLE.png.sha1 similarity index 100% rename from chrome/app/chromeos_strings_grdp/IDS_ARC_LOW_DISK_SPACE_POST_STOP_NOTIFICATION_TITLE.png.sha1 rename to ash/ash_strings_grd/IDS_ARC_LOW_DISK_SPACE_POST_STOP_NOTIFICATION_TITLE.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_ARC_LOW_DISK_SPACE_PRE_STOP_NOTIFICATION_MESSAGE.png.sha1 b/ash/ash_strings_grd/IDS_ARC_LOW_DISK_SPACE_PRE_STOP_NOTIFICATION_MESSAGE.png.sha1 similarity index 100% rename from chrome/app/chromeos_strings_grdp/IDS_ARC_LOW_DISK_SPACE_PRE_STOP_NOTIFICATION_MESSAGE.png.sha1 rename to ash/ash_strings_grd/IDS_ARC_LOW_DISK_SPACE_PRE_STOP_NOTIFICATION_MESSAGE.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_ARC_LOW_DISK_SPACE_PRE_STOP_NOTIFICATION_TITLE.png.sha1 b/ash/ash_strings_grd/IDS_ARC_LOW_DISK_SPACE_PRE_STOP_NOTIFICATION_TITLE.png.sha1 similarity index 100% rename from chrome/app/chromeos_strings_grdp/IDS_ARC_LOW_DISK_SPACE_PRE_STOP_NOTIFICATION_TITLE.png.sha1 rename to ash/ash_strings_grd/IDS_ARC_LOW_DISK_SPACE_PRE_STOP_NOTIFICATION_TITLE.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_ARC_NETWORK_UNAVAILABLE_ERROR.png.sha1 b/ash/ash_strings_grd/IDS_ARC_NETWORK_UNAVAILABLE_ERROR.png.sha1 similarity index 100% rename from chrome/app/chromeos_strings_grdp/IDS_ARC_NETWORK_UNAVAILABLE_ERROR.png.sha1 rename to ash/ash_strings_grd/IDS_ARC_NETWORK_UNAVAILABLE_ERROR.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_ARC_OPT_IN_DIALOG_BACKUP_RESTORE.png.sha1 b/ash/ash_strings_grd/IDS_ARC_OPT_IN_DIALOG_BACKUP_RESTORE.png.sha1 similarity index 100% rename from chrome/app/chromeos_strings_grdp/IDS_ARC_OPT_IN_DIALOG_BACKUP_RESTORE.png.sha1 rename to ash/ash_strings_grd/IDS_ARC_OPT_IN_DIALOG_BACKUP_RESTORE.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_ARC_OPT_IN_DIALOG_BACKUP_RESTORE_CHILD.png.sha1 b/ash/ash_strings_grd/IDS_ARC_OPT_IN_DIALOG_BACKUP_RESTORE_CHILD.png.sha1 similarity index 100% rename from chrome/app/chromeos_strings_grdp/IDS_ARC_OPT_IN_DIALOG_BACKUP_RESTORE_CHILD.png.sha1 rename to ash/ash_strings_grd/IDS_ARC_OPT_IN_DIALOG_BACKUP_RESTORE_CHILD.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_ARC_OPT_IN_DIALOG_BUTTON_RUN_NETWORK_TESTS.png.sha1 b/ash/ash_strings_grd/IDS_ARC_OPT_IN_DIALOG_BUTTON_RUN_NETWORK_TESTS.png.sha1 similarity index 100% rename from chrome/app/chromeos_strings_grdp/IDS_ARC_OPT_IN_DIALOG_BUTTON_RUN_NETWORK_TESTS.png.sha1 rename to ash/ash_strings_grd/IDS_ARC_OPT_IN_DIALOG_BUTTON_RUN_NETWORK_TESTS.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_ARC_OPT_IN_DIALOG_METRICS_DISABLED.png.sha1 b/ash/ash_strings_grd/IDS_ARC_OPT_IN_DIALOG_METRICS_DISABLED.png.sha1 similarity index 100% rename from chrome/app/chromeos_strings_grdp/IDS_ARC_OPT_IN_DIALOG_METRICS_DISABLED.png.sha1 rename to ash/ash_strings_grd/IDS_ARC_OPT_IN_DIALOG_METRICS_DISABLED.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_ARC_OPT_IN_DIALOG_METRICS_DISABLED_CHILD.png.sha1 b/ash/ash_strings_grd/IDS_ARC_OPT_IN_DIALOG_METRICS_DISABLED_CHILD.png.sha1 similarity index 100% rename from chrome/app/chromeos_strings_grdp/IDS_ARC_OPT_IN_DIALOG_METRICS_DISABLED_CHILD.png.sha1 rename to ash/ash_strings_grd/IDS_ARC_OPT_IN_DIALOG_METRICS_DISABLED_CHILD.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_ARC_OPT_IN_DIALOG_METRICS_ENABLED.png.sha1 b/ash/ash_strings_grd/IDS_ARC_OPT_IN_DIALOG_METRICS_ENABLED.png.sha1 similarity index 100% rename from chrome/app/chromeos_strings_grdp/IDS_ARC_OPT_IN_DIALOG_METRICS_ENABLED.png.sha1 rename to ash/ash_strings_grd/IDS_ARC_OPT_IN_DIALOG_METRICS_ENABLED.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_ARC_OPT_IN_DIALOG_METRICS_ENABLED_CHILD.png.sha1 b/ash/ash_strings_grd/IDS_ARC_OPT_IN_DIALOG_METRICS_ENABLED_CHILD.png.sha1 similarity index 100% rename from chrome/app/chromeos_strings_grdp/IDS_ARC_OPT_IN_DIALOG_METRICS_ENABLED_CHILD.png.sha1 rename to ash/ash_strings_grd/IDS_ARC_OPT_IN_DIALOG_METRICS_ENABLED_CHILD.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_ARC_OPT_IN_DIALOG_METRICS_MANAGED_DISABLED.png.sha1 b/ash/ash_strings_grd/IDS_ARC_OPT_IN_DIALOG_METRICS_MANAGED_DISABLED.png.sha1 similarity index 100% rename from chrome/app/chromeos_strings_grdp/IDS_ARC_OPT_IN_DIALOG_METRICS_MANAGED_DISABLED.png.sha1 rename to ash/ash_strings_grd/IDS_ARC_OPT_IN_DIALOG_METRICS_MANAGED_DISABLED.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_ARC_OPT_IN_DIALOG_METRICS_MANAGED_DISABLED_CHILD.png.sha1 b/ash/ash_strings_grd/IDS_ARC_OPT_IN_DIALOG_METRICS_MANAGED_DISABLED_CHILD.png.sha1 similarity index 100% rename from chrome/app/chromeos_strings_grdp/IDS_ARC_OPT_IN_DIALOG_METRICS_MANAGED_DISABLED_CHILD.png.sha1 rename to ash/ash_strings_grd/IDS_ARC_OPT_IN_DIALOG_METRICS_MANAGED_DISABLED_CHILD.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_ARC_OPT_IN_DIALOG_METRICS_MANAGED_ENABLED.png.sha1 b/ash/ash_strings_grd/IDS_ARC_OPT_IN_DIALOG_METRICS_MANAGED_ENABLED.png.sha1 similarity index 100% rename from chrome/app/chromeos_strings_grdp/IDS_ARC_OPT_IN_DIALOG_METRICS_MANAGED_ENABLED.png.sha1 rename to ash/ash_strings_grd/IDS_ARC_OPT_IN_DIALOG_METRICS_MANAGED_ENABLED.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_ARC_OPT_IN_DIALOG_METRICS_MANAGED_ENABLED_CHILD.png.sha1 b/ash/ash_strings_grd/IDS_ARC_OPT_IN_DIALOG_METRICS_MANAGED_ENABLED_CHILD.png.sha1 similarity index 100% rename from chrome/app/chromeos_strings_grdp/IDS_ARC_OPT_IN_DIALOG_METRICS_MANAGED_ENABLED_CHILD.png.sha1 rename to ash/ash_strings_grd/IDS_ARC_OPT_IN_DIALOG_METRICS_MANAGED_ENABLED_CHILD.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_ARC_OPT_IN_LOCATION_SETTING.png.sha1 b/ash/ash_strings_grd/IDS_ARC_OPT_IN_LOCATION_SETTING.png.sha1 similarity index 100% rename from chrome/app/chromeos_strings_grdp/IDS_ARC_OPT_IN_LOCATION_SETTING.png.sha1 rename to ash/ash_strings_grd/IDS_ARC_OPT_IN_LOCATION_SETTING.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_ARC_OPT_IN_LOCATION_SETTING_CHILD.png.sha1 b/ash/ash_strings_grd/IDS_ARC_OPT_IN_LOCATION_SETTING_CHILD.png.sha1 similarity index 100% rename from chrome/app/chromeos_strings_grdp/IDS_ARC_OPT_IN_LOCATION_SETTING_CHILD.png.sha1 rename to ash/ash_strings_grd/IDS_ARC_OPT_IN_LOCATION_SETTING_CHILD.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_ARC_OPT_IN_PAI.png.sha1 b/ash/ash_strings_grd/IDS_ARC_OPT_IN_PAI.png.sha1 similarity index 100% rename from chrome/app/chromeos_strings_grdp/IDS_ARC_OPT_IN_PAI.png.sha1 rename to ash/ash_strings_grd/IDS_ARC_OPT_IN_PAI.png.sha1
diff --git a/chromeos/chromeos_strings_grd/IDS_ARC_SDK_VERSION_LABEL.png.sha1 b/ash/ash_strings_grd/IDS_ARC_SDK_VERSION_LABEL.png.sha1 similarity index 100% rename from chromeos/chromeos_strings_grd/IDS_ARC_SDK_VERSION_LABEL.png.sha1 rename to ash/ash_strings_grd/IDS_ARC_SDK_VERSION_LABEL.png.sha1
diff --git a/chromeos/chromeos_strings_grd/IDS_ARC_SDK_VERSION_UNKNOWN.png.sha1 b/ash/ash_strings_grd/IDS_ARC_SDK_VERSION_UNKNOWN.png.sha1 similarity index 100% rename from chromeos/chromeos_strings_grd/IDS_ARC_SDK_VERSION_UNKNOWN.png.sha1 rename to ash/ash_strings_grd/IDS_ARC_SDK_VERSION_UNKNOWN.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_ARC_SERVER_COMMUNICATION_ERROR.png.sha1 b/ash/ash_strings_grd/IDS_ARC_SERVER_COMMUNICATION_ERROR.png.sha1 similarity index 100% rename from chrome/app/chromeos_strings_grdp/IDS_ARC_SERVER_COMMUNICATION_ERROR.png.sha1 rename to ash/ash_strings_grd/IDS_ARC_SERVER_COMMUNICATION_ERROR.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_ARC_SIGN_IN_BAD_AUTHENTICATION_ERROR.png.sha1 b/ash/ash_strings_grd/IDS_ARC_SIGN_IN_BAD_AUTHENTICATION_ERROR.png.sha1 similarity index 100% rename from chrome/app/chromeos_strings_grdp/IDS_ARC_SIGN_IN_BAD_AUTHENTICATION_ERROR.png.sha1 rename to ash/ash_strings_grd/IDS_ARC_SIGN_IN_BAD_AUTHENTICATION_ERROR.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_ACCOUNT_MISSING_ERROR.png.sha1 b/ash/ash_strings_grd/IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_ACCOUNT_MISSING_ERROR.png.sha1 similarity index 100% rename from chrome/app/chromeos_strings_grdp/IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_ACCOUNT_MISSING_ERROR.png.sha1 rename to ash/ash_strings_grd/IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_ACCOUNT_MISSING_ERROR.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_DOMAIN_JOIN_FAIL_ERROR.png.sha1 b/ash/ash_strings_grd/IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_DOMAIN_JOIN_FAIL_ERROR.png.sha1 similarity index 100% rename from chrome/app/chromeos_strings_grdp/IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_DOMAIN_JOIN_FAIL_ERROR.png.sha1 rename to ash/ash_strings_grd/IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_DOMAIN_JOIN_FAIL_ERROR.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_ENROLLMENT_TOKEN_INVALID.png.sha1 b/ash/ash_strings_grd/IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_ENROLLMENT_TOKEN_INVALID.png.sha1 similarity index 100% rename from chrome/app/chromeos_strings_grdp/IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_ENROLLMENT_TOKEN_INVALID.png.sha1 rename to ash/ash_strings_grd/IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_ENROLLMENT_TOKEN_INVALID.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_INTERRUPTED_ERROR.png.sha1 b/ash/ash_strings_grd/IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_INTERRUPTED_ERROR.png.sha1 similarity index 100% rename from chrome/app/chromeos_strings_grdp/IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_INTERRUPTED_ERROR.png.sha1 rename to ash/ash_strings_grd/IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_INTERRUPTED_ERROR.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_NETWORK_ERROR.png.sha1 b/ash/ash_strings_grd/IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_NETWORK_ERROR.png.sha1 similarity index 100% rename from chrome/app/chromeos_strings_grdp/IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_NETWORK_ERROR.png.sha1 rename to ash/ash_strings_grd/IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_NETWORK_ERROR.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_PERMANENT_ERROR.png.sha1 b/ash/ash_strings_grd/IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_PERMANENT_ERROR.png.sha1 similarity index 100% rename from chrome/app/chromeos_strings_grdp/IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_PERMANENT_ERROR.png.sha1 rename to ash/ash_strings_grd/IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_PERMANENT_ERROR.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_TRANSIENT_ERROR.png.sha1 b/ash/ash_strings_grd/IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_TRANSIENT_ERROR.png.sha1 similarity index 100% rename from chrome/app/chromeos_strings_grdp/IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_TRANSIENT_ERROR.png.sha1 rename to ash/ash_strings_grd/IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_TRANSIENT_ERROR.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_ARC_SIGN_IN_GMS_CHECKIN_ERROR.png.sha1 b/ash/ash_strings_grd/IDS_ARC_SIGN_IN_GMS_CHECKIN_ERROR.png.sha1 similarity index 100% rename from chrome/app/chromeos_strings_grdp/IDS_ARC_SIGN_IN_GMS_CHECKIN_ERROR.png.sha1 rename to ash/ash_strings_grd/IDS_ARC_SIGN_IN_GMS_CHECKIN_ERROR.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_ARC_SIGN_IN_GMS_SIGNIN_ERROR.png.sha1 b/ash/ash_strings_grd/IDS_ARC_SIGN_IN_GMS_SIGNIN_ERROR.png.sha1 similarity index 100% rename from chrome/app/chromeos_strings_grdp/IDS_ARC_SIGN_IN_GMS_SIGNIN_ERROR.png.sha1 rename to ash/ash_strings_grd/IDS_ARC_SIGN_IN_GMS_SIGNIN_ERROR.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_ARC_SIGN_IN_NETWORK_ERROR.png.sha1 b/ash/ash_strings_grd/IDS_ARC_SIGN_IN_NETWORK_ERROR.png.sha1 similarity index 100% rename from chrome/app/chromeos_strings_grdp/IDS_ARC_SIGN_IN_NETWORK_ERROR.png.sha1 rename to ash/ash_strings_grd/IDS_ARC_SIGN_IN_NETWORK_ERROR.png.sha1
diff --git a/chrome/app/chromeos_strings_grdp/IDS_ARC_SIGN_IN_UNKNOWN_ERROR.png.sha1 b/ash/ash_strings_grd/IDS_ARC_SIGN_IN_UNKNOWN_ERROR.png.sha1 similarity index 100% rename from chrome/app/chromeos_strings_grdp/IDS_ARC_SIGN_IN_UNKNOWN_ERROR.png.sha1 rename to ash/ash_strings_grd/IDS_ARC_SIGN_IN_UNKNOWN_ERROR.png.sha1
diff --git a/ash/constants/ash_pref_names.h b/ash/constants/ash_pref_names.h index 5fed944d..9ce310e20 100644 --- a/ash/constants/ash_pref_names.h +++ b/ash/constants/ash_pref_names.h
@@ -3360,6 +3360,53 @@ "native_printing.user_native_printers_allowed"; //----------------------------------------------------------------------------- +// Enrollment related Prefs +//----------------------------------------------------------------------------- + +// Whether to automatically start the enterprise enrollment step during OOBE. +inline constexpr char kDeviceEnrollmentAutoStart[] = "enrollment.auto_start"; + +// Whether the user may exit enrollment. +inline constexpr char kDeviceEnrollmentCanExit[] = "enrollment.can_exit"; + +// Device requisition for enterprise enrollment. +inline constexpr char kDeviceEnrollmentRequisition[] = + "enrollment.device_requisition"; + +// Sub organization for enterprise enrollment. +inline constexpr char kDeviceEnrollmentSubOrganization[] = + "enrollment.sub_organization"; + +// A boolean pref of the device registered flag (second part after first login). +inline constexpr char kDeviceRegistered[] = "DeviceRegistered"; + +// An integer pref. Its valid values are defined in +// enterprise_management::DeviceRegisterRequest::PsmExecutionResult enum which +// indicates all possible PSM execution results in the Chrome OS enrollment +// flow. +inline constexpr char kEnrollmentPsmResult[] = "EnrollmentPsmResult"; + +// An int64 pref to record the timestamp of PSM retrieving the device's +// determination successfully in the Chrome OS enrollment flow. +inline constexpr char kEnrollmentPsmDeterminationTime[] = + "EnrollmentPsmDeterminationTime"; + +// Boolean pref to signal corrupted enrollment to force the device through +// enrollment recovery flow upon next boot. +inline constexpr char kEnrollmentRecoveryRequired[] = + "EnrollmentRecoveryRequired"; + +// String pref with the data about the OS version and browser version at the +// time of enrollment. The format is established by release management team. +// The Chrome OS version format is +// [Milestone.]TIP_BUILD.BRANCH_BUILD.BRANCH_BRANCH_BUILD. +// Example: 15711.0.0 +// For browser version the format is MAJOR.MINOR.BRANCH.BUILD. +// Example: 122.0.6252.0 +inline constexpr char kEnrollmentVersionOS[] = "EnrollmentVersionOS"; +inline constexpr char kEnrollmentVersionBrowser[] = "EnrollmentVersionBrowser"; + +//----------------------------------------------------------------------------- // Child account related Prefs //-----------------------------------------------------------------------------
diff --git a/ash/constants/ash_switches.cc b/ash/constants/ash_switches.cc index fd34f43..07fce463 100644 --- a/ash/constants/ash_switches.cc +++ b/ash/constants/ash_switches.cc
@@ -1103,30 +1103,6 @@ // Enables verbose logging level for Nearby Share. const char kNearbyShareVerboseLogging[] = "nearby-share-verbose-logging"; -// Custom crosh command. -const char kCroshCommand[] = "crosh-command"; - -// Passes the name of the current running automated test to Chrome. -const char kTestName[] = "test-name"; - -// Overrides the default validity period for Nearby Share certificates. Value -// must be larger than 0. -const char kNearbyShareCertificateValidityPeriodHours[] = - "nearby-share-certificate-validity-period-hours"; - -// Overrides the default device ID to provide a stable ID in test environments. -// By default we generate a random 10-character string. -const char kNearbyShareDeviceID[] = "nearby-share-device-id"; - -// Overrides the default URL for Google APIs (https://www.googleapis.com) used -// by Nearby Share -const char kNearbyShareHTTPHost[] = "nearbysharing-http-host"; - -// Overrides the default number of private certificates generated. Value must be -// larger than 0. -const char kNearbyShareNumPrivateCertificates[] = - "nearby-share-num-private-certificates"; - bool IsAuthSessionCryptohomeEnabled() { return base::CommandLine::ForCurrentProcess()->HasSwitch( kCryptohomeUseAuthSession);
diff --git a/ash/constants/ash_switches.h b/ash/constants/ash_switches.h index 1625c20d..c7a76e12 100644 --- a/ash/constants/ash_switches.h +++ b/ash/constants/ash_switches.h
@@ -382,14 +382,6 @@ COMPONENT_EXPORT(ASH_CONSTANTS) extern const char kCustomAndroidMessagesDomain[]; COMPONENT_EXPORT(ASH_CONSTANTS) extern const char kNearbyShareVerboseLogging[]; -COMPONENT_EXPORT(ASH_CONSTANTS) extern const char kCroshCommand[]; -COMPONENT_EXPORT(ASH_CONSTANTS) extern const char kTestName[]; -COMPONENT_EXPORT(ASH_CONSTANTS) -extern const char kNearbyShareCertificateValidityPeriodHours[]; -COMPONENT_EXPORT(ASH_CONSTANTS) extern const char kNearbyShareDeviceID[]; -COMPONENT_EXPORT(ASH_CONSTANTS) extern const char kNearbyShareHTTPHost[]; -COMPONENT_EXPORT(ASH_CONSTANTS) -extern const char kNearbyShareNumPrivateCertificates[]; ////////////////////////////////////////////////////////////////////////////////
diff --git a/ash/display/cros_display_config.cc b/ash/display/cros_display_config.cc index 3edebb77..29fc3cc 100644 --- a/ash/display/cros_display_config.cc +++ b/ash/display/cros_display_config.cc
@@ -58,9 +58,7 @@ return display_id; } -// Gets the display with the provided string id. -display::Display GetDisplay(const std::string& display_id_str) { - int64_t display_id = GetDisplayId(display_id_str); +display::Display GetDisplay(int64_t display_id) { if (display_id == display::kInvalidDisplayId) { return display::Display(); } @@ -77,62 +75,30 @@ return display_manager->GetDisplayForId(display_id); } -crosapi::mojom::DisplayLayoutPosition GetMojomDisplayLayoutPosition( - display::DisplayPlacement::Position position) { - switch (position) { - case display::DisplayPlacement::TOP: - return crosapi::mojom::DisplayLayoutPosition::kTop; - case display::DisplayPlacement::RIGHT: - return crosapi::mojom::DisplayLayoutPosition::kRight; - case display::DisplayPlacement::BOTTOM: - return crosapi::mojom::DisplayLayoutPosition::kBottom; - case display::DisplayPlacement::LEFT: - return crosapi::mojom::DisplayLayoutPosition::kLeft; - } - NOTREACHED(); +// Gets the display with the provided string id. +display::Display GetDisplay(const std::string& display_id_str) { + return GetDisplay(GetDisplayId(display_id_str)); } -display::DisplayPlacement::Position GetDisplayPlacementPosition( - crosapi::mojom::DisplayLayoutPosition position) { - switch (position) { - case crosapi::mojom::DisplayLayoutPosition::kTop: - return display::DisplayPlacement::TOP; - case crosapi::mojom::DisplayLayoutPosition::kRight: - return display::DisplayPlacement::RIGHT; - case crosapi::mojom::DisplayLayoutPosition::kBottom: - return display::DisplayPlacement::BOTTOM; - case crosapi::mojom::DisplayLayoutPosition::kLeft: - return display::DisplayPlacement::LEFT; - } - NOTREACHED(); -} - -std::vector<crosapi::mojom::DisplayLayoutPtr> GetDisplayLayouts() { - auto layouts = std::vector<crosapi::mojom::DisplayLayoutPtr>(); +std::vector<display::DisplayPlacement> GetDisplayLayouts() { + std::vector<display::DisplayPlacement> layouts; display::Screen* screen = display::Screen::Get(); - const std::vector<display::Display>& displays = screen->GetAllDisplays(); display::DisplayManager* display_manager = GetDisplayManager(); - for (const display::Display& display : displays) { + const std::vector<display::Display>& displays = screen->GetAllDisplays(); + for (const auto& display : displays) { const display::DisplayPlacement placement = display_manager->GetCurrentResolvedDisplayLayout().FindPlacementById( display.id()); - if (placement.display_id == display::kInvalidDisplayId) { - continue; + if (placement.display_id != display::kInvalidDisplayId) { + layouts.push_back(std::move(placement)); } - auto layout = crosapi::mojom::DisplayLayout::New(); - layout->id = base::NumberToString(placement.display_id); - layout->parent_id = base::NumberToString(placement.parent_display_id); - layout->position = GetMojomDisplayLayoutPosition(placement.position); - layout->offset = placement.offset; - layouts.emplace_back(std::move(layout)); } return layouts; } -std::vector<crosapi::mojom::DisplayLayoutPtr> GetDisplayUnifiedLayouts() { - auto layouts = std::vector<crosapi::mojom::DisplayLayoutPtr>(); +std::vector<display::DisplayPlacement> GetDisplayUnifiedLayouts() { + std::vector<display::DisplayPlacement> layouts; display::DisplayManager* display_manager = GetDisplayManager(); - const display::UnifiedDesktopLayoutMatrix& matrix = display_manager->current_unified_desktop_matrix(); for (size_t row_index = 0; row_index < matrix.size(); ++row_index) { @@ -142,68 +108,65 @@ // No placement for the primary display. continue; } - auto layout = crosapi::mojom::DisplayLayout::New(); + display::DisplayPlacement layout; const int64_t display_id = row[column_index]; // Parent display is either the one in the above row, or the one on the // left in the same row. const int64_t parent_id = column_index == 0 ? matrix[row_index - 1][column_index] : row[column_index - 1]; - layout->id = base::NumberToString(display_id); - layout->parent_id = base::NumberToString(parent_id); - layout->position = column_index == 0 - ? crosapi::mojom::DisplayLayoutPosition::kBottom - : crosapi::mojom::DisplayLayoutPosition::kRight; - layout->offset = 0; - layouts.emplace_back(std::move(layout)); + layout.display_id = display_id; + layout.parent_display_id = parent_id; + layout.position = column_index == 0 ? display::DisplayPlacement::BOTTOM + : display::DisplayPlacement::RIGHT; + layout.offset = 0; + layouts.push_back(std::move(layout)); } } return layouts; } -crosapi::mojom::DisplayConfigResult SetDisplayLayoutMode( - const crosapi::mojom::DisplayLayoutInfo& info) { +DisplayConfigResult SetDisplayLayoutMode(const DisplayLayoutInfo& info) { display::DisplayManager* display_manager = GetDisplayManager(); if (display_manager->num_connected_displays() < 2) { - return crosapi::mojom::DisplayConfigResult::kSingleDisplayError; + return DisplayConfigResult::kSingleDisplayError; } - if (info.layout_mode == crosapi::mojom::DisplayLayoutMode::kNormal) { + if (info.layout_mode == DisplayLayoutMode::kNormal) { display_manager->SetDefaultMultiDisplayModeForCurrentDisplays( display::DisplayManager::EXTENDED); display_manager->SetMirrorMode(display::MirrorMode::kOff, std::nullopt); - return crosapi::mojom::DisplayConfigResult::kSuccess; + return DisplayConfigResult::kSuccess; } - if (info.layout_mode == crosapi::mojom::DisplayLayoutMode::kUnified) { + if (info.layout_mode == DisplayLayoutMode::kUnified) { if (!display_manager->unified_desktop_enabled()) { - return crosapi::mojom::DisplayConfigResult::kUnifiedNotEnabledError; + return DisplayConfigResult::kUnifiedNotEnabledError; } display_manager->SetDefaultMultiDisplayModeForCurrentDisplays( display::DisplayManager::UNIFIED); display_manager->SetMirrorMode(display::MirrorMode::kOff, std::nullopt); - return crosapi::mojom::DisplayConfigResult::kSuccess; + return DisplayConfigResult::kSuccess; } - DCHECK(info.layout_mode == crosapi::mojom::DisplayLayoutMode::kMirrored); + CHECK_EQ(info.layout_mode, DisplayLayoutMode::kMirrored); - // 'Normal' mirror mode. - if (!info.mirror_source_id) { + if (!info.mirror_source_id.has_value()) { + // 'Normal' mirror mode. display_manager->SetMirrorMode(display::MirrorMode::kNormal, std::nullopt); - return crosapi::mojom::DisplayConfigResult::kSuccess; + return DisplayConfigResult::kSuccess; } // 'Mixed' mirror mode. display::Display source = GetDisplay(*info.mirror_source_id); if (source.id() == display::kInvalidDisplayId) { - return crosapi::mojom::DisplayConfigResult::kMirrorModeSourceIdError; + return DisplayConfigResult::kMirrorModeSourceIdError; } display::DisplayIdList destination_ids; - if (info.mirror_destination_ids) { - for (const std::string& id_str : *info.mirror_destination_ids) { - int64_t destination_id = GetDisplayId(id_str); + if (info.mirror_destination_ids.has_value()) { + for (int64_t destination_id : *info.mirror_destination_ids) { if (destination_id == display::kInvalidDisplayId) { - return crosapi::mojom::DisplayConfigResult::kMirrorModeDestIdError; + return DisplayConfigResult::kMirrorModeDestIdError; } destination_ids.emplace_back(destination_id); } @@ -221,18 +184,18 @@ display_manager->GetConnectedDisplayIdList(), *mixed_params); switch (error_type) { case display::MixedMirrorModeParamsErrors::kErrorSingleDisplay: - return crosapi::mojom::DisplayConfigResult::kSingleDisplayError; + return DisplayConfigResult::kSingleDisplayError; case display::MixedMirrorModeParamsErrors::kErrorSourceIdNotFound: - return crosapi::mojom::DisplayConfigResult::kMirrorModeSourceIdError; + return DisplayConfigResult::kMirrorModeSourceIdError; case display::MixedMirrorModeParamsErrors::kErrorDestinationIdsEmpty: case display::MixedMirrorModeParamsErrors::kErrorDestinationIdNotFound: case display::MixedMirrorModeParamsErrors::kErrorDuplicateId: - return crosapi::mojom::DisplayConfigResult::kMirrorModeDestIdError; + return DisplayConfigResult::kMirrorModeDestIdError; case display::MixedMirrorModeParamsErrors::kSuccess: break; } display_manager->SetMirrorMode(display::MirrorMode::kMixed, mixed_params); - return crosapi::mojom::DisplayConfigResult::kSuccess; + return DisplayConfigResult::kSuccess; } crosapi::mojom::DisplayModePtr GetDisplayMode( @@ -373,30 +336,29 @@ // Validates that DisplayProperties are valid with the current DisplayManager // configuration. Returns an error on failure. -crosapi::mojom::DisplayConfigResult ValidateDisplayProperties( - const crosapi::mojom::DisplayConfigProperties& properties, +DisplayConfigResult ValidateDisplayProperties( + const DisplayConfigProperties& properties, const display::Display& display) { display::DisplayManager* display_manager = GetDisplayManager(); - const crosapi::mojom::DisplayConfigProperties* prop_ptr = &properties; - auto dump_state = [display, prop_ptr]() -> std::string { + auto dump_state = [&display, &properties]() -> std::string { std::stringstream ss; ss << "display={" << display.ToString() << "}"; ss << ", config properties={"; - if (prop_ptr->overscan) { - ss << "overscan=" << prop_ptr->overscan->ToString() << ", "; + if (properties.overscan.has_value()) { + ss << "overscan=" << properties.overscan->ToString() << ", "; } - if (prop_ptr->bounds_origin) { - ss << "bounds_origin=" << prop_ptr->bounds_origin->ToString() << ", "; + if (properties.bounds_origin.has_value()) { + ss << "bounds_origin=" << properties.bounds_origin->ToString() << ", "; } - ss << "zoom_factor=" << prop_ptr->display_zoom_factor; + ss << "zoom_factor=" << properties.display_zoom_factor; return ss.str() + "}"; }; int64_t id = display.id(); if (id == display::kInvalidDisplayId) { DISPLAY_LOG(ERROR) << "Invalid display id:" << dump_state(); - return crosapi::mojom::DisplayConfigResult::kInvalidDisplayIdError; + return DisplayConfigResult::kInvalidDisplayIdError; } // Overscan cannot be changed for the internal display, and should be at most @@ -405,14 +367,13 @@ if (display.IsInternal()) { DISPLAY_LOG(ERROR) << "Overscan is not supported on the internal display:" << dump_state(); - return crosapi::mojom::DisplayConfigResult:: - kNotSupportedOnInternalDisplayError; + return DisplayConfigResult::kNotSupportedOnInternalDisplayError; } if (properties.overscan->left() < 0 || properties.overscan->top() < 0 || properties.overscan->right() < 0 || properties.overscan->bottom() < 0) { DISPLAY_LOG(ERROR) << "Negative overscan:" << dump_state(); - return crosapi::mojom::DisplayConfigResult::kPropertyValueOutOfRangeError; + return DisplayConfigResult::kPropertyValueOutOfRangeError; } const gfx::Insets overscan = display_manager->GetOverscanInsets(id); @@ -427,7 +388,7 @@ << ", overscan (" << properties.overscan->ToString() << ") exceeds bounds (" << screen_width << "x" << screen_height << ")"; - return crosapi::mojom::DisplayConfigResult::kPropertyValueOutOfRangeError; + return DisplayConfigResult::kPropertyValueOutOfRangeError; } } @@ -438,15 +399,14 @@ display::Screen::Get()->GetPrimaryDisplay(); if (id == primary.id() || properties.set_primary) { LOG(ERROR) << "Not Supported on Internal Display:" << dump_state(); - return crosapi::mojom::DisplayConfigResult:: - kNotSupportedOnInternalDisplayError; + return DisplayConfigResult::kNotSupportedOnInternalDisplayError; } if (properties.bounds_origin->x() > kMaxBoundsOrigin || properties.bounds_origin->x() < -kMaxBoundsOrigin || properties.bounds_origin->y() > kMaxBoundsOrigin || properties.bounds_origin->y() < -kMaxBoundsOrigin) { DISPLAY_LOG(ERROR) << "Bounds origin out of range:" << dump_state(); - return crosapi::mojom::DisplayConfigResult::kPropertyValueOutOfRangeError; + return DisplayConfigResult::kPropertyValueOutOfRangeError; } } @@ -456,7 +416,7 @@ display::ManagedDisplayMode current_mode; if (!display_manager->GetActiveModeForDisplayId(id, ¤t_mode)) { DISPLAY_LOG(ERROR) << "No active mode for display:" << dump_state(); - return crosapi::mojom::DisplayConfigResult::kInvalidDisplayIdError; + return DisplayConfigResult::kInvalidDisplayIdError; } // This check is added to limit the range of display zoom that can be // applied via the system display API. The said range is such that when a @@ -473,11 +433,11 @@ if (current_width / properties.display_zoom_factor > max_allowed_width || current_width / properties.display_zoom_factor < min_allowed_width) { DISPLAY_LOG(ERROR) << "Display zoom factor out of range:" << dump_state(); - return crosapi::mojom::DisplayConfigResult::kPropertyValueOutOfRangeError; + return DisplayConfigResult::kPropertyValueOutOfRangeError; } } - return crosapi::mojom::DisplayConfigResult::kSuccess; + return DisplayConfigResult::kSuccess; } // Sets the display layout for the target display in reference to the primary @@ -501,7 +461,7 @@ } // Attempts to set the display mode for display |id|. -crosapi::mojom::DisplayConfigResult SetDisplayMode( +DisplayConfigResult SetDisplayMode( int64_t id, const crosapi::mojom::DisplayMode& display_mode, crosapi::mojom::DisplayConfigSource source) { @@ -509,7 +469,7 @@ display::ManagedDisplayMode current_mode; if (!display_manager->GetActiveModeForDisplayId(id, ¤t_mode)) { - return crosapi::mojom::DisplayConfigResult::kInvalidDisplayIdError; + return DisplayConfigResult::kInvalidDisplayIdError; } display::ManagedDisplayMode new_mode( @@ -529,20 +489,32 @@ id, current_mode, new_mode, source, base::BindOnce([]() { Shell::Get()->display_prefs()->MaybeStoreDisplayPrefs(); }))) { - return crosapi::mojom::DisplayConfigResult::kSetDisplayModeError; + return DisplayConfigResult::kSetDisplayModeError; } } - return crosapi::mojom::DisplayConfigResult::kSuccess; -} - -display::TouchCalibrationData::CalibrationPointPair GetCalibrationPair( - const crosapi::mojom::TouchCalibrationPair& pair) { - return std::make_pair(pair.display_point, pair.touch_point); + return DisplayConfigResult::kSuccess; } } // namespace +DisplayLayoutInfo::DisplayLayoutInfo() = default; +DisplayLayoutInfo::DisplayLayoutInfo(const DisplayLayoutInfo& other) = default; +DisplayLayoutInfo::DisplayLayoutInfo(DisplayLayoutInfo&& other) noexcept = + default; +DisplayLayoutInfo& DisplayLayoutInfo::operator=( + const DisplayLayoutInfo& other) = default; +DisplayLayoutInfo& DisplayLayoutInfo::operator=( + DisplayLayoutInfo&& other) noexcept = default; +DisplayLayoutInfo::~DisplayLayoutInfo() = default; + +DisplayConfigProperties::DisplayConfigProperties() = default; +DisplayConfigProperties::DisplayConfigProperties( + DisplayConfigProperties&& other) noexcept = default; +DisplayConfigProperties& DisplayConfigProperties::operator=( + DisplayConfigProperties&& other) noexcept = default; +DisplayConfigProperties::~DisplayConfigProperties() = default; + // ----------------------------------------------------------------------------- // CrosDisplayConfigImpl::ObserverImpl: @@ -625,64 +597,56 @@ observer_impl_->RemoveObserver(observer); } -crosapi::mojom::DisplayLayoutInfoPtr -CrosDisplayConfigImpl::GetDisplayLayoutInfo() { +DisplayLayoutInfo CrosDisplayConfigImpl::GetDisplayLayoutInfo() { display::DisplayManager* display_manager = GetDisplayManager(); - - auto info = crosapi::mojom::DisplayLayoutInfo::New(); - + DisplayLayoutInfo info; if (display_manager->IsInUnifiedMode()) { - info->layout_mode = crosapi::mojom::DisplayLayoutMode::kUnified; + info.layout_mode = DisplayLayoutMode::kUnified; } else if (display_manager->IsInMirrorMode()) { - info->layout_mode = crosapi::mojom::DisplayLayoutMode::kMirrored; - info->mirror_source_id = - base::NumberToString(display_manager->mirroring_source_id()); - info->mirror_destination_ids = std::vector<std::string>(); + info.layout_mode = DisplayLayoutMode::kMirrored; + info.mirror_source_id = display_manager->mirroring_source_id(); + info.mirror_destination_ids.emplace(); for (int64_t id : display_manager->GetMirroringDestinationDisplayIdList()) { - info->mirror_destination_ids->emplace_back(base::NumberToString(id)); + info.mirror_destination_ids->push_back(id); } } else { - info->layout_mode = crosapi::mojom::DisplayLayoutMode::kNormal; + info.layout_mode = DisplayLayoutMode::kNormal; } - if (display_manager->IsInUnifiedMode()) { - info->layouts = GetDisplayUnifiedLayouts(); + info.layouts = GetDisplayUnifiedLayouts(); } else if (display_manager->num_connected_displays() > 1) { - info->layouts = GetDisplayLayouts(); + info.layouts = GetDisplayLayouts(); } - return info; } -crosapi::mojom::DisplayConfigResult SetDisplayLayouts( - const std::vector<crosapi::mojom::DisplayLayoutPtr>& layouts) { +DisplayConfigResult SetDisplayLayouts( + const std::vector<display::DisplayPlacement>& layouts) { display::DisplayManager* display_manager = GetDisplayManager(); display::DisplayLayoutBuilder builder( display_manager->GetCurrentResolvedDisplayLayout()); int64_t root_id = display::kInvalidDisplayId; std::set<int64_t> layout_ids; builder.ClearPlacements(); - for (const crosapi::mojom::DisplayLayoutPtr& layout_ptr : layouts) { - const crosapi::mojom::DisplayLayout& layout = *layout_ptr; - display::Display display = GetDisplay(layout.id); + for (const auto& layout : layouts) { + display::Display display = GetDisplay(layout.display_id); if (display.id() == display::kInvalidDisplayId) { - DISPLAY_LOG(ERROR) << "Display layout has invalid id: " << layout.id; - return crosapi::mojom::DisplayConfigResult::kInvalidDisplayIdError; + DISPLAY_LOG(ERROR) << "Display layout has invalid id: " + << layout.display_id; + return DisplayConfigResult::kInvalidDisplayIdError; } - display::Display parent = GetDisplay(layout.parent_id); + display::Display parent = GetDisplay(layout.parent_display_id); if (parent.id() == display::kInvalidDisplayId) { if (root_id != display::kInvalidDisplayId) { DISPLAY_LOG(ERROR) << "Display layout has invalid parent: " - << layout.parent_id; - return crosapi::mojom::DisplayConfigResult::kInvalidDisplayLayoutError; + << layout.parent_display_id; + return DisplayConfigResult::kInvalidDisplayLayoutError; } root_id = display.id(); continue; // No placement for root (primary) display. } layout_ids.insert(display.id()); - display::DisplayPlacement::Position position = - GetDisplayPlacementPosition(layout.position); - builder.AddDisplayPlacement(display.id(), parent.id(), position, + builder.AddDisplayPlacement(display.id(), parent.id(), layout.position, layout.offset); } @@ -700,7 +664,7 @@ } if (root_id == display::kInvalidDisplayId) { DISPLAY_LOG(ERROR) << "Invalid unified layout: No root display id"; - return crosapi::mojom::DisplayConfigResult::kInvalidDisplayLayoutError; + return DisplayConfigResult::kInvalidDisplayLayoutError; } } layout->primary_id = root_id; @@ -708,7 +672,7 @@ if (!display::BuildUnifiedDesktopMatrix(display_ids, *layout, &matrix)) { DISPLAY_LOG(ERROR) << "Invalid unified layout: No proper conversion to a matrix"; - return crosapi::mojom::DisplayConfigResult::kInvalidDisplayLayoutError; + return DisplayConfigResult::kInvalidDisplayLayoutError; } Shell::Get() ->display_configuration_controller() @@ -716,27 +680,27 @@ } else { if (!display::DisplayLayout::Validate(display_ids, *layout)) { // No need to log an error since `Validate` already logged what's wrong. - return crosapi::mojom::DisplayConfigResult::kInvalidDisplayLayoutError; + return DisplayConfigResult::kInvalidDisplayLayoutError; } Shell::Get()->display_configuration_controller()->SetDisplayLayout( std::move(layout)); } - return crosapi::mojom::DisplayConfigResult::kSuccess; + return DisplayConfigResult::kSuccess; } -crosapi::mojom::DisplayConfigResult CrosDisplayConfigImpl::SetDisplayLayoutInfo( - crosapi::mojom::DisplayLayoutInfoPtr info) { - crosapi::mojom::DisplayConfigResult result = SetDisplayLayoutMode(*info); - if (result != crosapi::mojom::DisplayConfigResult::kSuccess) { +DisplayConfigResult CrosDisplayConfigImpl::SetDisplayLayoutInfo( + const DisplayLayoutInfo& info) { + DisplayConfigResult result = SetDisplayLayoutMode(info); + if (result != DisplayConfigResult::kSuccess) { return result; } - if (info->layouts) { - result = SetDisplayLayouts(*info->layouts); - if (result != crosapi::mojom::DisplayConfigResult::kSuccess) { + if (info.layouts) { + result = SetDisplayLayouts(*info.layouts); + if (result != DisplayConfigResult::kSuccess) { return result; } } - return crosapi::mojom::DisplayConfigResult::kSuccess; + return DisplayConfigResult::kSuccess; } std::vector<crosapi::mojom::DisplayUnitInfoPtr> @@ -768,14 +732,13 @@ return info_list; } -crosapi::mojom::DisplayConfigResult CrosDisplayConfigImpl::SetDisplayProperties( +DisplayConfigResult CrosDisplayConfigImpl::SetDisplayProperties( const std::string& id, - crosapi::mojom::DisplayConfigPropertiesPtr properties, + const DisplayConfigProperties& properties, crosapi::mojom::DisplayConfigSource source) { const display::Display display = GetDisplay(id); - crosapi::mojom::DisplayConfigResult result = - ValidateDisplayProperties(*properties, display); - if (result != crosapi::mojom::DisplayConfigResult::kSuccess) { + DisplayConfigResult result = ValidateDisplayProperties(properties, display); + if (result != DisplayConfigResult::kSuccess) { return result; } @@ -784,27 +747,27 @@ Shell::Get()->display_configuration_controller(); const display::Display& primary = display::Screen::Get()->GetPrimaryDisplay(); - if (properties->set_primary && display.id() != primary.id()) { + if (properties.set_primary && display.id() != primary.id()) { display_configuration_controller->SetPrimaryDisplayId( display.id(), false /* don't throttle */); } - if (properties->overscan) { - display_manager->SetOverscanInsets(display.id(), *properties->overscan); + if (properties.overscan.has_value()) { + display_manager->SetOverscanInsets(display.id(), *properties.overscan); } - if (properties->rotation) { + if (properties.rotation.has_value()) { const crosapi::mojom::DisplayRotationOptions rotation_options = - properties->rotation->rotation; + *properties.rotation; auto* screen_orientation_controller = Shell::Get()->screen_orientation_controller(); const bool is_auto_rotation_allowed = screen_orientation_controller->IsAutoRotationAllowed(); const bool auto_rotate_requested = rotation_options == crosapi::mojom::DisplayRotationOptions::kAutoRotate; - display::Display::Rotation rotation = - DisplayRotationFromRotationOptions(properties->rotation->rotation); + DisplayRotationFromRotationOptions(rotation_options); + if (is_auto_rotation_allowed && display.IsInternal()) { if (auto_rotate_requested) { if (screen_orientation_controller->user_rotation_locked()) { @@ -819,51 +782,50 @@ } } - if (properties->bounds_origin && - *properties->bounds_origin != display.bounds().origin()) { + if (properties.bounds_origin.has_value() && + *properties.bounds_origin != display.bounds().origin()) { gfx::Rect display_bounds = display.bounds(); - display_bounds.Offset( - properties->bounds_origin->x() - display.bounds().x(), - properties->bounds_origin->y() - display.bounds().y()); + display_bounds.Offset(properties.bounds_origin->x() - display.bounds().x(), + properties.bounds_origin->y() - display.bounds().y()); SetDisplayLayoutFromBounds(primary.bounds(), primary.id(), display_bounds, display.id()); } - if (properties->display_zoom_factor > 0) { + if (properties.display_zoom_factor > 0) { display_manager->UpdateZoomFactor(display.id(), - properties->display_zoom_factor); + properties.display_zoom_factor); } // Set the display mode. Note: if this returns an error, other properties // will have already been applied. TODO(stevenjb): Validate the display mode // before applying any properties. - if (properties->display_mode) { - result = SetDisplayMode(display.id(), *properties->display_mode, source); - if (result != crosapi::mojom::DisplayConfigResult::kSuccess) { + if (properties.display_mode) { + result = SetDisplayMode(display.id(), *properties.display_mode, source); + if (result != DisplayConfigResult::kSuccess) { return result; } } - return crosapi::mojom::DisplayConfigResult::kSuccess; + return DisplayConfigResult::kSuccess; } void CrosDisplayConfigImpl::SetUnifiedDesktopEnabled(bool enabled) { GetDisplayManager()->SetUnifiedDesktopEnabled(enabled); } -crosapi::mojom::DisplayConfigResult CrosDisplayConfigImpl::OverscanCalibration( +DisplayConfigResult CrosDisplayConfigImpl::OverscanCalibration( const std::string& display_id, crosapi::mojom::DisplayConfigOperation op, const std::optional<gfx::Insets>& delta) { display::Display display = GetDisplay(display_id); if (display.id() == display::kInvalidDisplayId) { - return crosapi::mojom::DisplayConfigResult::kInvalidDisplayIdError; + return DisplayConfigResult::kInvalidDisplayIdError; } OverscanCalibrator* calibrator = GetOverscanCalibrator(display_id); if (!calibrator && op != crosapi::mojom::DisplayConfigOperation::kStart) { DISPLAY_LOG(ERROR) << "Calibrator does not exist for op=" << op; - return crosapi::mojom::DisplayConfigResult::kCalibrationNotAvailableError; + return DisplayConfigResult::kCalibrationNotAvailableError; } switch (op) { case crosapi::mojom::DisplayConfigOperation::kStart: { @@ -882,7 +844,7 @@ if (!delta) { DISPLAY_LOG(ERROR) << "Delta not provided for for adjust: " << display_id; - return crosapi::mojom::DisplayConfigResult::kCalibrationFailedError; + return DisplayConfigResult::kCalibrationFailedError; } calibrator->UpdateInsets(calibrator->insets() + *delta); break; @@ -897,26 +859,25 @@ break; case crosapi::mojom::DisplayConfigOperation::kShowNative: DISPLAY_LOG(ERROR) << "Operation not supported: " << op; - return crosapi::mojom::DisplayConfigResult::kInvalidOperationError; + return DisplayConfigResult::kInvalidOperationError; case crosapi::mojom::DisplayConfigOperation::kShowNativeMappingDisplays: DISPLAY_LOG(ERROR) << "Operation not supported: " << op; - return crosapi::mojom::DisplayConfigResult::kInvalidOperationError; + return DisplayConfigResult::kInvalidOperationError; } - return crosapi::mojom::DisplayConfigResult::kSuccess; + return DisplayConfigResult::kSuccess; } void CrosDisplayConfigImpl::TouchCalibration( const std::string& display_id, crosapi::mojom::DisplayConfigOperation op, - crosapi::mojom::TouchCalibrationPtr calibration, + base::optional_ref<const display::TouchCalibrationData> calibration, TouchCalibrationCallback callback) { // For native touch display mapping. if (op == crosapi::mojom::DisplayConfigOperation::kShowNativeMappingDisplays) { if (touch_calibrator_ && touch_calibrator_->IsCalibrating()) { DISPLAY_LOG(ERROR) << "Touch calibration already active."; - std::move(callback).Run( - crosapi::mojom::DisplayConfigResult::kCalibrationInProgressError); + std::move(callback).Run(DisplayConfigResult::kCalibrationInProgressError); return; } if (!touch_calibrator_) { @@ -927,9 +888,8 @@ touch_calibrator_->StartNativeTouchscreenMappingExperience(base::BindOnce( [](TouchCalibrationCallback callback, bool result) { std::move(callback).Run( - result ? crosapi::mojom::DisplayConfigResult::kSuccess - : crosapi::mojom::DisplayConfigResult:: - kCalibrationFailedError); + result ? DisplayConfigResult::kSuccess + : DisplayConfigResult::kCalibrationFailedError); }, std::move(callback))); return; @@ -937,22 +897,19 @@ display::Display display = GetDisplay(display_id); if (display.id() == display::kInvalidDisplayId) { - std::move(callback).Run( - crosapi::mojom::DisplayConfigResult::kInvalidDisplayIdError); + std::move(callback).Run(DisplayConfigResult::kInvalidDisplayIdError); return; } if (display.IsInternal()) { DISPLAY_LOG(ERROR) << "Internal display cannot be calibrated for touch: " << display_id; - std::move(callback).Run( - crosapi::mojom::DisplayConfigResult::kCalibrationNotAvailableError); + std::move(callback).Run(DisplayConfigResult::kCalibrationNotAvailableError); return; } if (!display::HasExternalTouchscreenDevice()) { DISPLAY_LOG(ERROR) << "Touch calibration called with no external touch screen device."; - std::move(callback).Run( - crosapi::mojom::DisplayConfigResult::kCalibrationNotAvailableError); + std::move(callback).Run(DisplayConfigResult::kCalibrationNotAvailableError); return; } @@ -960,8 +917,7 @@ op == crosapi::mojom::DisplayConfigOperation::kShowNative) { if (touch_calibrator_ && touch_calibrator_->IsCalibrating()) { DISPLAY_LOG(ERROR) << "Touch calibration already active."; - std::move(callback).Run( - crosapi::mojom::DisplayConfigResult::kCalibrationInProgressError); + std::move(callback).Run(DisplayConfigResult::kCalibrationInProgressError); return; } if (!touch_calibrator_) { @@ -975,9 +931,8 @@ base::BindOnce( [](TouchCalibrationCallback callback, bool result) { std::move(callback).Run( - result ? crosapi::mojom::DisplayConfigResult::kSuccess - : crosapi::mojom::DisplayConfigResult:: - kCalibrationFailedError); + result ? DisplayConfigResult::kSuccess + : DisplayConfigResult::kCalibrationFailedError); }, std::move(callback))); return; @@ -985,48 +940,39 @@ // For custom calibration, start calibration and run |callback| now. touch_calibrator_->StartCalibration(display, /*is_custom_calibration=*/true, base::OnceCallback<void(bool)>()); - std::move(callback).Run(crosapi::mojom::DisplayConfigResult::kSuccess); + std::move(callback).Run(DisplayConfigResult::kSuccess); return; } if (op == crosapi::mojom::DisplayConfigOperation::kReset) { Shell::Get()->display_manager()->ClearTouchCalibrationData(display.id(), std::nullopt); - std::move(callback).Run(crosapi::mojom::DisplayConfigResult::kSuccess); + std::move(callback).Run(DisplayConfigResult::kSuccess); return; } if (op != crosapi::mojom::DisplayConfigOperation::kComplete) { DISPLAY_LOG(ERROR) << "Unknown operation: " << op; - std::move(callback).Run( - crosapi::mojom::DisplayConfigResult::kCalibrationNotStartedError); + std::move(callback).Run(DisplayConfigResult::kCalibrationNotStartedError); return; } if (!touch_calibrator_) { DISPLAY_LOG(ERROR) << "Touch calibration not active."; - std::move(callback).Run( - crosapi::mojom::DisplayConfigResult::kCalibrationNotStartedError); + std::move(callback).Run(DisplayConfigResult::kCalibrationNotStartedError); return; } - if (!calibration || calibration->pairs.size() != 4) { - DISPLAY_LOG(ERROR) << "Touch calibration requires four calibration pairs."; - std::move(callback).Run( - crosapi::mojom::DisplayConfigResult::kCalibrationInvalidDataError); + if (!calibration.has_value()) { + DISPLAY_LOG(ERROR) << "Touch calibration requires calibration data."; + std::move(callback).Run(DisplayConfigResult::kCalibrationInvalidDataError); return; } Shell::Get()->touch_transformer_controller()->SetForCalibration(false); - display::TouchCalibrationData::CalibrationPointPairQuad calibration_points; - calibration_points[0] = GetCalibrationPair(*calibration->pairs[0]); - calibration_points[1] = GetCalibrationPair(*calibration->pairs[1]); - calibration_points[2] = GetCalibrationPair(*calibration->pairs[2]); - calibration_points[3] = GetCalibrationPair(*calibration->pairs[3]); - - gfx::Size bounds = calibration->bounds; - for (auto& calibration_point : calibration_points) { + const gfx::Size bounds = calibration->bounds; + for (auto& calibration_point : calibration->point_pairs) { // Coordinates for display and touch point cannot be negative. if (calibration_point.first.x() < 0 || calibration_point.first.y() < 0 || calibration_point.second.x() < 0 || calibration_point.second.y() < 0) { @@ -1034,7 +980,7 @@ << "Display points and touch points cannot have negative coordinates"; touch_calibrator_->StopCalibrationAndResetParams(); std::move(callback).Run( - crosapi::mojom::DisplayConfigResult::kCalibrationInvalidDataError); + DisplayConfigResult::kCalibrationInvalidDataError); return; } // Coordinates for display points cannot be greater than the screen @@ -1046,13 +992,13 @@ "display."; touch_calibrator_->StopCalibrationAndResetParams(); std::move(callback).Run( - crosapi::mojom::DisplayConfigResult::kCalibrationInvalidDataError); + DisplayConfigResult::kCalibrationInvalidDataError); return; } } - touch_calibrator_->CompleteCalibration(calibration_points, bounds); - std::move(callback).Run(crosapi::mojom::DisplayConfigResult::kSuccess); + touch_calibrator_->CompleteCalibration(calibration->point_pairs, bounds); + std::move(callback).Run(DisplayConfigResult::kSuccess); } OverscanCalibrator* CrosDisplayConfigImpl::GetOverscanCalibrator(
diff --git a/ash/display/cros_display_config.h b/ash/display/cros_display_config.h index 385d0f7..256d3ba 100644 --- a/ash/display/cros_display_config.h +++ b/ash/display/cros_display_config.h
@@ -7,22 +7,154 @@ #include <map> #include <memory> +#include <optional> #include <string> +#include <vector> #include "ash/ash_export.h" #include "base/observer_list_types.h" +#include "base/types/optional_ref.h" #include "chromeos/crosapi/mojom/cros_display_config.mojom.h" +#include "ui/display/display_layout.h" +#include "ui/display/manager/touch_device_manager.h" +#include "ui/gfx/geometry/insets.h" +#include "ui/gfx/geometry/point.h" namespace ash { class OverscanCalibrator; class TouchCalibratorController; +// Describes how the displays are laid out. +enum class DisplayLayoutMode { + // In normal mode displays are laid out as described by + // DisplayLayoutInfo::layouts. + kNormal, + // In unified desktop mode, a single desktop will be stretched across all + // available displays. + kUnified, + // In mirrored mode, the display defined by DisplayLayoutInfo.mirrorSourceId + // will be mirrored in the displays defined by + // DisplayLayoutInfo::mirrorDestinationIds, or in all other displays if + // mirrorDestinationIds is empty. + kMirrored +}; + +// Defines the layout mode and details. +struct ASH_EXPORT DisplayLayoutInfo { + DisplayLayoutInfo(); + DisplayLayoutInfo(const DisplayLayoutInfo& other); + DisplayLayoutInfo(DisplayLayoutInfo&& other) noexcept; + DisplayLayoutInfo& operator=(const DisplayLayoutInfo& other); + DisplayLayoutInfo& operator=(DisplayLayoutInfo&& other) noexcept; + ~DisplayLayoutInfo(); + + // The layout mode to use, see DisplayLayoutMode for details. + DisplayLayoutMode layout_mode; + + // Ignored if layout_mode is not kMirrored. Otherwise, if provided, specifies + // the unique identifier of the source display for mirroring. If not provided, + // mirror_destination_ids will be ignored and default ('normal') mirrored mode + // will be enabled. + std::optional<int64_t> mirror_source_id; + + // Ignored if layout_mode is not kMirrored. Otherwise, if provided, specifies + // the unique identifiers of the displays to mirror the source display. If + // empty, all displays will mirror the source display. + std::optional<std::vector<int64_t>> mirror_destination_ids; + + // An array of layouts describing a directed graph of displays. Required if + // layout_mode is kNormal or kMirrored and not all displays are mirrored + // ('mixed' mode). Ignored if layout_mode is kUnified. + std::optional<std::vector<display::DisplayPlacement>> layouts; +}; + +// Properties for configuring an individual display, used in +// SetDisplayProperties. +struct ASH_EXPORT DisplayConfigProperties { + DisplayConfigProperties(); + DisplayConfigProperties(const DisplayConfigProperties& other) = delete; + DisplayConfigProperties(DisplayConfigProperties&& other) noexcept; + DisplayConfigProperties& operator=(const DisplayConfigProperties& other) = + delete; + DisplayConfigProperties& operator=(DisplayConfigProperties&& other) noexcept; + ~DisplayConfigProperties(); + + // If true, makes the display primary. No-op if set to false. + bool set_primary = false; + + // If provided, sets the display's overscan insets to the provided value. + // Note: overscan values may not be negative or larger than a half of the + // screen's size. Overscan cannot be changed on the internal monitor. + std::optional<gfx::Insets> overscan; + + // If provided, updates the display's rotation, or if the auto-rotation is + // allowed in the device, it can be used to set or clear the user rotation + // lock, enabling or disabling auto-rotation. + std::optional<crosapi::mojom::DisplayRotationOptions> rotation; + + // If provided, updates the display's logical bounds origin. Note: when + // updating the display origin, some constraints will be applied. so the final + // bounds origin may be different than the one set. The actual bounds will be + // reflected in DisplayUnitInfo. Cannot be changed on the primary display (or + // if set_primary is true). + std::optional<gfx::Point> bounds_origin; + + // If non-zero, updates the zoom associated with the display. This zoom + // performs relayout and repaint thus resulting in a better quality zoom than + // just performing a pixel by pixel stretch enlargement. + double display_zoom_factor = 0.0; + + // Optional DisplayMode properties to set. This should match one of the + // modes listed in DisplayUnitInfo.available_display_modes. Other custom + // modes may or may not be valid. + crosapi::mojom::DisplayModePtr display_mode; +}; + +// SetDisplayLayoutInfo or SetDisplayProperties result. +enum class DisplayConfigResult { + // Operation was successful. + kSuccess, + // Operation is not supported. + kInvalidOperationError, + // Input display ID represents an invalid display. + kInvalidDisplayIdError, + // Unified desktop mode is disabled. + kUnifiedNotEnabledError, + // Input property for operation is out of range. E.g. display zoom factor, + // bounds origin or overscan. + kPropertyValueOutOfRangeError, + // Operation is not supported for internal displays. + kNotSupportedOnInternalDisplayError, + // Negative values are not supported for the operation. + kNegativeValueError, + // Setting the display mode failed. + kSetDisplayModeError, + // Invalid display layout error. + kInvalidDisplayLayoutError, + // Mode requires multiple displays. + kSingleDisplayError, + // Mirror mode source ID is invalid. + kMirrorModeSourceIdError, + // Mirror mode destination ID is invalid. + kMirrorModeDestIdError, + // Calibration is not available (e.g. no external touch screen device). + kCalibrationNotAvailableError, + // Calibration was not started. + kCalibrationNotStartedError, + // Touch calibration is already active. + kCalibrationInProgressError, + // Invalid input data for calibration. + kCalibrationInvalidDataError, + // Calibration procedure failed. + kCalibrationFailedError, +}; + // Interface for configuring displays in Chrome OS. class CrosDisplayConfig { public: using TouchCalibrationCallback = - base::OnceCallback<void(crosapi::mojom::DisplayConfigResult)>; + base::OnceCallback<void(DisplayConfigResult)>; class Observer : public base::CheckedObserver { public: @@ -34,12 +166,12 @@ virtual void RemoveObserver(Observer* observer) = 0; // Returns the display layout info, including the list of layouts. - virtual crosapi::mojom::DisplayLayoutInfoPtr GetDisplayLayoutInfo() = 0; + virtual DisplayLayoutInfo GetDisplayLayoutInfo() = 0; // Sets the layout mode, mirroring, and layouts. Returns kSuccess if the // layout is valid or an error value otherwise. - virtual crosapi::mojom::DisplayConfigResult SetDisplayLayoutInfo( - crosapi::mojom::DisplayLayoutInfoPtr info) = 0; + virtual DisplayConfigResult SetDisplayLayoutInfo( + const DisplayLayoutInfo& info) = 0; // Returns the properties for all displays. If |single_unified| is true, a // single display will be returned if the display layout is in unified mode. @@ -49,9 +181,9 @@ // Sets |properties| for individual display with identifier |id|. |source| // should describe who initiated the change. Returns Success if the properties // are valid or an error value otherwise. - virtual crosapi::mojom::DisplayConfigResult SetDisplayProperties( + virtual DisplayConfigResult SetDisplayProperties( const std::string& id, - crosapi::mojom::DisplayConfigPropertiesPtr properties, + const DisplayConfigProperties& properties, crosapi::mojom::DisplayConfigSource source) = 0; // Enables or disables unified desktop mode. If the current display mode is @@ -62,7 +194,7 @@ // Starts, updates, completes, or resets overscan calibration for the display // with identifier |display_id|. If |op| is kAdjust, |delta| describes the // amount to change the overscan value. - virtual crosapi::mojom::DisplayConfigResult OverscanCalibration( + virtual DisplayConfigResult OverscanCalibration( const std::string& display_id, crosapi::mojom::DisplayConfigOperation op, const std::optional<gfx::Insets>& delta) = 0; @@ -71,10 +203,11 @@ // identifier |display_id|. If |op| is kShowNative shows the native // calibration UI. Runs the callback after performing the operation or on // error. - virtual void TouchCalibration(const std::string& display_id, - crosapi::mojom::DisplayConfigOperation op, - crosapi::mojom::TouchCalibrationPtr calibration, - TouchCalibrationCallback callback) = 0; + virtual void TouchCalibration( + const std::string& display_id, + crosapi::mojom::DisplayConfigOperation op, + base::optional_ref<const display::TouchCalibrationData> calibration, + TouchCalibrationCallback callback) = 0; // Sets |id| of display to render identification highlight on. Invalid |id| // turns identification highlight off. @@ -104,24 +237,25 @@ // CrosDisplayConfig: void AddObserver(Observer* observer) override; void RemoveObserver(Observer* observer) override; - crosapi::mojom::DisplayLayoutInfoPtr GetDisplayLayoutInfo() override; - crosapi::mojom::DisplayConfigResult SetDisplayLayoutInfo( - crosapi::mojom::DisplayLayoutInfoPtr info) override; + DisplayLayoutInfo GetDisplayLayoutInfo() override; + DisplayConfigResult SetDisplayLayoutInfo( + const DisplayLayoutInfo& info) override; std::vector<crosapi::mojom::DisplayUnitInfoPtr> GetDisplayUnitInfoList( bool single_unified) override; - crosapi::mojom::DisplayConfigResult SetDisplayProperties( + DisplayConfigResult SetDisplayProperties( const std::string& id, - crosapi::mojom::DisplayConfigPropertiesPtr properties, + const DisplayConfigProperties& properties, crosapi::mojom::DisplayConfigSource source) override; void SetUnifiedDesktopEnabled(bool enabled) override; - crosapi::mojom::DisplayConfigResult OverscanCalibration( + DisplayConfigResult OverscanCalibration( const std::string& display_id, crosapi::mojom::DisplayConfigOperation op, const std::optional<gfx::Insets>& delta) override; - void TouchCalibration(const std::string& display_id, - crosapi::mojom::DisplayConfigOperation op, - crosapi::mojom::TouchCalibrationPtr calibration, - TouchCalibrationCallback callback) override; + void TouchCalibration( + const std::string& display_id, + crosapi::mojom::DisplayConfigOperation op, + base::optional_ref<const display::TouchCalibrationData> calibration, + TouchCalibrationCallback callback) override; void HighlightDisplay(int64_t display_id) override; void DragDisplayDelta(int64_t display_id, int32_t delta_x,
diff --git a/ash/display/cros_display_config_unittest.cc b/ash/display/cros_display_config_unittest.cc index f8b7f89..f849ae1 100644 --- a/ash/display/cros_display_config_unittest.cc +++ b/ash/display/cros_display_config_unittest.cc
@@ -38,9 +38,9 @@ namespace { -void SetResult(crosapi::mojom::DisplayConfigResult* result_ptr, +void SetResult(DisplayConfigResult* result_ptr, base::OnceClosure callback, - crosapi::mojom::DisplayConfigResult result) { + DisplayConfigResult result) { *result_ptr = result; std::move(callback).Run(); } @@ -105,12 +105,12 @@ AshTestBase::TearDown(); } - crosapi::mojom::DisplayLayoutInfoPtr GetDisplayLayoutInfo() { + ash::DisplayLayoutInfo GetDisplayLayoutInfo() { return cros_display_config_->GetDisplayLayoutInfo(); } - crosapi::mojom::DisplayConfigResult SetDisplayLayoutInfo( - crosapi::mojom::DisplayLayoutInfoPtr display_layout_info) { + DisplayConfigResult SetDisplayLayoutInfo( + const ash::DisplayLayoutInfo& display_layout_info) { return cros_display_config_->SetDisplayLayoutInfo( std::move(display_layout_info)); } @@ -120,11 +120,11 @@ return cros_display_config_->GetDisplayUnitInfoList(single_unified); } - crosapi::mojom::DisplayConfigResult SetDisplayProperties( + DisplayConfigResult SetDisplayProperties( const std::string& id, - crosapi::mojom::DisplayConfigPropertiesPtr properties) { + const DisplayConfigProperties& properties) { return cros_display_config_->SetDisplayProperties( - id, std::move(properties), crosapi::mojom::DisplayConfigSource::kUser); + id, properties, crosapi::mojom::DisplayConfigSource::kUser); } bool OverscanCalibration(int64_t id, @@ -132,7 +132,7 @@ const std::optional<gfx::Insets>& delta) { return cros_display_config()->OverscanCalibration(base::NumberToString(id), op, delta) == - crosapi::mojom::DisplayConfigResult::kSuccess; + DisplayConfigResult::kSuccess; } bool DisplayExists(int64_t display_id) { @@ -141,37 +141,31 @@ return display.id() != display::kInvalidDisplayId; } - crosapi::mojom::TouchCalibrationPtr GetDefaultCalibration() { - auto calibration = crosapi::mojom::TouchCalibration::New(); - for (int i = 0; i < 4; ++i) - calibration->pairs.emplace_back( - crosapi::mojom::TouchCalibrationPair::New()); - return calibration; - } - bool StartTouchCalibration(const std::string& display_id) { - return CallTouchCalibration( - display_id, crosapi::mojom::DisplayConfigOperation::kStart, nullptr); + return CallTouchCalibration(display_id, + crosapi::mojom::DisplayConfigOperation::kStart, + std::nullopt); } bool CompleteCustomTouchCalibration( const std::string& display_id, - crosapi::mojom::TouchCalibrationPtr calibration) { + const display::TouchCalibrationData& calibration) { return CallTouchCalibration( display_id, crosapi::mojom::DisplayConfigOperation::kComplete, - std::move(calibration)); + calibration); } - bool CallTouchCalibration(const std::string& id, - crosapi::mojom::DisplayConfigOperation op, - crosapi::mojom::TouchCalibrationPtr calibration) { - crosapi::mojom::DisplayConfigResult result; + bool CallTouchCalibration( + const std::string& id, + crosapi::mojom::DisplayConfigOperation op, + base::optional_ref<const display::TouchCalibrationData> calibration) { + DisplayConfigResult result; base::RunLoop run_loop; cros_display_config_->TouchCalibration( - id, op, std::move(calibration), + id, op, calibration, base::BindOnce(&SetResult, &result, run_loop.QuitClosure())); run_loop.Run(); - return result == crosapi::mojom::DisplayConfigResult::kSuccess; + return result == DisplayConfigResult::kSuccess; } bool IsTouchCalibrationActive() { @@ -226,25 +220,20 @@ display::Screen::Get()->GetAllDisplays(); ASSERT_EQ(3u, displays.size()); - crosapi::mojom::DisplayLayoutInfoPtr display_layout_info = - GetDisplayLayoutInfo(); - - ASSERT_TRUE(display_layout_info); - const std::vector<crosapi::mojom::DisplayLayoutPtr>& layouts = - *display_layout_info->layouts; + ash::DisplayLayoutInfo display_layout_info = GetDisplayLayoutInfo(); + const std::vector<display::DisplayPlacement>& layouts = + *display_layout_info.layouts; ASSERT_EQ(2u, layouts.size()); - EXPECT_EQ(base::NumberToString(displays[1].id()), layouts[0]->id); - EXPECT_EQ(base::NumberToString(displays[0].id()), layouts[0]->parent_id); - EXPECT_EQ(crosapi::mojom::DisplayLayoutPosition::kRight, - layouts[0]->position); - EXPECT_EQ(0, layouts[0]->offset); + EXPECT_EQ(displays[1].id(), layouts[0].display_id); + EXPECT_EQ(displays[0].id(), layouts[0].parent_display_id); + EXPECT_EQ(display::DisplayPlacement::RIGHT, layouts[0].position); + EXPECT_EQ(0, layouts[0].offset); - EXPECT_EQ(base::NumberToString(displays[2].id()), layouts[1]->id); - EXPECT_EQ(layouts[0]->id, layouts[1]->parent_id); - EXPECT_EQ(crosapi::mojom::DisplayLayoutPosition::kRight, - layouts[1]->position); - EXPECT_EQ(0, layouts[1]->offset); + EXPECT_EQ(displays[2].id(), layouts[1].display_id); + EXPECT_EQ(layouts[0].display_id, layouts[1].parent_display_id); + EXPECT_EQ(display::DisplayPlacement::RIGHT, layouts[1].position); + EXPECT_EQ(0, layouts[1].offset); } TEST_F(CrosDisplayConfigTest, FailToSetLayoutUnifiedWithOneDisplay) { @@ -253,11 +242,10 @@ // Enable unified desktop and expect to fail due to not enough connected // displays. - auto properties = crosapi::mojom::DisplayLayoutInfo::New(); - properties->layout_mode = crosapi::mojom::DisplayLayoutMode::kUnified; - crosapi::mojom::DisplayConfigResult result = - SetDisplayLayoutInfo(std::move(properties)); - EXPECT_EQ(crosapi::mojom::DisplayConfigResult::kSingleDisplayError, result); + ash::DisplayLayoutInfo properties; + properties.layout_mode = ash::DisplayLayoutMode::kUnified; + DisplayConfigResult result = SetDisplayLayoutInfo(std::move(properties)); + EXPECT_EQ(DisplayConfigResult::kSingleDisplayError, result); EXPECT_FALSE(display_manager()->IsInUnifiedMode()); } @@ -271,19 +259,22 @@ EXPECT_TRUE(display_manager()->IsInUnifiedMode()); // Disable unified mode. - auto properties = crosapi::mojom::DisplayLayoutInfo::New(); - properties->layout_mode = crosapi::mojom::DisplayLayoutMode::kNormal; - crosapi::mojom::DisplayConfigResult result = - SetDisplayLayoutInfo(std::move(properties)); - EXPECT_EQ(crosapi::mojom::DisplayConfigResult::kSuccess, result); - EXPECT_FALSE(display_manager()->IsInUnifiedMode()); + { + ash::DisplayLayoutInfo properties; + properties.layout_mode = ash::DisplayLayoutMode::kNormal; + DisplayConfigResult result = SetDisplayLayoutInfo(std::move(properties)); + EXPECT_EQ(DisplayConfigResult::kSuccess, result); + EXPECT_FALSE(display_manager()->IsInUnifiedMode()); + } // Enable unified mode. - properties = crosapi::mojom::DisplayLayoutInfo::New(); - properties->layout_mode = crosapi::mojom::DisplayLayoutMode::kUnified; - result = SetDisplayLayoutInfo(std::move(properties)); - EXPECT_EQ(crosapi::mojom::DisplayConfigResult::kSuccess, result); - EXPECT_TRUE(display_manager()->IsInUnifiedMode()); + { + ash::DisplayLayoutInfo properties; + properties.layout_mode = ash::DisplayLayoutMode::kUnified; + DisplayConfigResult result = SetDisplayLayoutInfo(std::move(properties)); + EXPECT_EQ(DisplayConfigResult::kSuccess, result); + EXPECT_TRUE(display_manager()->IsInUnifiedMode()); + } // Restore extended mode. cros_display_config()->SetUnifiedDesktopEnabled(false); @@ -311,11 +302,11 @@ auto primary_id = display::Screen::Get()->GetPrimaryDisplay().id(); for (auto zoom_factor : zoom_factors) { - auto properties = crosapi::mojom::DisplayConfigProperties::New(); - properties->display_zoom_factor = zoom_factor; - crosapi::mojom::DisplayConfigResult result = SetDisplayProperties( - base::NumberToString(primary_id), std::move(properties)); - EXPECT_EQ(crosapi::mojom::DisplayConfigResult::kSuccess, result); + DisplayConfigProperties properties; + properties.display_zoom_factor = zoom_factor; + DisplayConfigResult result = + SetDisplayProperties(base::NumberToString(primary_id), properties); + EXPECT_EQ(DisplayConfigResult::kSuccess, result); EXPECT_TRUE(display_manager()->IsInUnifiedMode()); EXPECT_EQ(zoom_factor, display_manager()->GetDisplayInfo(primary_id).zoom_factor()); @@ -328,11 +319,10 @@ // Enable default mirror mode and expect to fail due to not enough connected // displays. - auto properties = crosapi::mojom::DisplayLayoutInfo::New(); - properties->layout_mode = crosapi::mojom::DisplayLayoutMode::kMirrored; - crosapi::mojom::DisplayConfigResult result = - SetDisplayLayoutInfo(std::move(properties)); - EXPECT_EQ(crosapi::mojom::DisplayConfigResult::kSingleDisplayError, result); + ash::DisplayLayoutInfo properties; + properties.layout_mode = ash::DisplayLayoutMode::kMirrored; + DisplayConfigResult result = SetDisplayLayoutInfo(std::move(properties)); + EXPECT_EQ(DisplayConfigResult::kSingleDisplayError, result); EXPECT_FALSE(display_manager()->IsInMirrorMode()); display::DisplayIdList id_list = @@ -343,21 +333,24 @@ TEST_F(CrosDisplayConfigTest, SetLayoutMirroredDefault) { UpdateDisplay("500x400,500x400,500x400"); - auto properties = crosapi::mojom::DisplayLayoutInfo::New(); - properties->layout_mode = crosapi::mojom::DisplayLayoutMode::kMirrored; - crosapi::mojom::DisplayConfigResult result = - SetDisplayLayoutInfo(std::move(properties)); - EXPECT_EQ(crosapi::mojom::DisplayConfigResult::kSuccess, result); - EXPECT_TRUE(display_manager()->IsInMirrorMode()); - display::DisplayIdList id_list = - display_manager()->GetMirroringDestinationDisplayIdList(); - ASSERT_EQ(2u, id_list.size()); + { + ash::DisplayLayoutInfo properties; + properties.layout_mode = ash::DisplayLayoutMode::kMirrored; + DisplayConfigResult result = SetDisplayLayoutInfo(std::move(properties)); + EXPECT_EQ(DisplayConfigResult::kSuccess, result); + EXPECT_TRUE(display_manager()->IsInMirrorMode()); + display::DisplayIdList id_list = + display_manager()->GetMirroringDestinationDisplayIdList(); + ASSERT_EQ(2u, id_list.size()); + } - properties = crosapi::mojom::DisplayLayoutInfo::New(); - properties->layout_mode = crosapi::mojom::DisplayLayoutMode::kNormal; - result = SetDisplayLayoutInfo(std::move(properties)); - EXPECT_EQ(crosapi::mojom::DisplayConfigResult::kSuccess, result); - EXPECT_FALSE(display_manager()->IsInMirrorMode()); + { + ash::DisplayLayoutInfo properties; + properties.layout_mode = ash::DisplayLayoutMode::kNormal; + DisplayConfigResult result = SetDisplayLayoutInfo(std::move(properties)); + EXPECT_EQ(DisplayConfigResult::kSuccess, result); + EXPECT_FALSE(display_manager()->IsInMirrorMode()); + } } TEST_F(CrosDisplayConfigTest, FailToSetLayoutMirroredMixedWithOneDisplay) { @@ -370,15 +363,13 @@ // Enable mixed mirror mode and expect to fail due to not enough connected // displays. - auto properties = crosapi::mojom::DisplayLayoutInfo::New(); - properties->layout_mode = crosapi::mojom::DisplayLayoutMode::kMirrored; - properties->mirror_source_id = base::NumberToString(displays[0].id()); - properties->mirror_destination_ids = - std::make_optional<std::vector<std::string>>(); + ash::DisplayLayoutInfo properties; + properties.layout_mode = ash::DisplayLayoutMode::kMirrored; + properties.mirror_source_id = displays[0].id(); + properties.mirror_destination_ids.emplace(); - crosapi::mojom::DisplayConfigResult result = - SetDisplayLayoutInfo(std::move(properties)); - EXPECT_EQ(crosapi::mojom::DisplayConfigResult::kSingleDisplayError, result); + DisplayConfigResult result = SetDisplayLayoutInfo(std::move(properties)); + EXPECT_EQ(DisplayConfigResult::kSingleDisplayError, result); EXPECT_FALSE(display_manager()->IsInMirrorMode()); display::DisplayIdList id_list = @@ -393,16 +384,13 @@ display::Screen::Get()->GetAllDisplays(); ASSERT_EQ(4u, displays.size()); - auto properties = crosapi::mojom::DisplayLayoutInfo::New(); - properties->layout_mode = crosapi::mojom::DisplayLayoutMode::kMirrored; - properties->mirror_source_id = base::NumberToString(displays[0].id()); - properties->mirror_destination_ids = - std::make_optional<std::vector<std::string>>( - {base::NumberToString(displays[1].id()), - base::NumberToString(displays[3].id())}); - crosapi::mojom::DisplayConfigResult result = - SetDisplayLayoutInfo(std::move(properties)); - EXPECT_EQ(crosapi::mojom::DisplayConfigResult::kSuccess, result); + ash::DisplayLayoutInfo properties; + properties.layout_mode = ash::DisplayLayoutMode::kMirrored; + properties.mirror_source_id = displays[0].id(); + properties.mirror_destination_ids.emplace( + {displays[1].id(), displays[3].id()}); + DisplayConfigResult result = SetDisplayLayoutInfo(std::move(properties)); + EXPECT_EQ(DisplayConfigResult::kSuccess, result); EXPECT_TRUE(display_manager()->IsInMirrorMode()); display::DisplayIdList id_list = display_manager()->GetMirroringDestinationDisplayIdList(); @@ -480,11 +468,11 @@ .id(); ASSERT_NE(primary_id, secondary_id); - auto properties = crosapi::mojom::DisplayConfigProperties::New(); - properties->set_primary = true; - crosapi::mojom::DisplayConfigResult result = SetDisplayProperties( - base::NumberToString(secondary_id), std::move(properties)); - EXPECT_EQ(crosapi::mojom::DisplayConfigResult::kSuccess, result); + DisplayConfigProperties properties; + properties.set_primary = true; + DisplayConfigResult result = + SetDisplayProperties(base::NumberToString(secondary_id), properties); + EXPECT_EQ(DisplayConfigResult::kSuccess, result); // secondary display should now be primary. primary_id = display::Screen::Get()->GetPrimaryDisplay().id(); @@ -497,11 +485,11 @@ display::test::DisplayManagerTestApi(display_manager()) .GetSecondaryDisplay(); - auto properties = crosapi::mojom::DisplayConfigProperties::New(); - properties->overscan = gfx::Insets::TLBR(199, 20, 51, 130); - crosapi::mojom::DisplayConfigResult result = SetDisplayProperties( - base::NumberToString(secondary.id()), std::move(properties)); - EXPECT_EQ(crosapi::mojom::DisplayConfigResult::kSuccess, result); + DisplayConfigProperties properties; + properties.overscan = gfx::Insets::TLBR(199, 20, 51, 130); + DisplayConfigResult result = + SetDisplayProperties(base::NumberToString(secondary.id()), properties); + EXPECT_EQ(DisplayConfigResult::kSuccess, result); EXPECT_EQ(gfx::Rect(1200, 0, 150, 250), secondary.bounds()); const gfx::Insets overscan = display_manager()->GetOverscanInsets(secondary.id()); @@ -517,38 +505,40 @@ display::test::DisplayManagerTestApi(display_manager()) .GetSecondaryDisplay(); - crosapi::mojom::DisplayConfigResult result; + { + DisplayConfigProperties properties; + properties.rotation = crosapi::mojom::DisplayRotationOptions::k90Degrees; + auto result = + SetDisplayProperties(base::NumberToString(secondary.id()), properties); + EXPECT_EQ(DisplayConfigResult::kSuccess, result); + EXPECT_EQ(gfx::Rect(1200, 0, 500, 300), secondary.bounds()); + EXPECT_EQ(display::Display::ROTATE_90, secondary.rotation()); + } - auto properties = crosapi::mojom::DisplayConfigProperties::New(); - properties->rotation = crosapi::mojom::DisplayRotation::New( - crosapi::mojom::DisplayRotationOptions::k90Degrees); - result = SetDisplayProperties(base::NumberToString(secondary.id()), - std::move(properties)); - EXPECT_EQ(crosapi::mojom::DisplayConfigResult::kSuccess, result); - EXPECT_EQ(gfx::Rect(1200, 0, 500, 300), secondary.bounds()); - EXPECT_EQ(display::Display::ROTATE_90, secondary.rotation()); - - properties = crosapi::mojom::DisplayConfigProperties::New(); - properties->rotation = crosapi::mojom::DisplayRotation::New( - crosapi::mojom::DisplayRotationOptions::k270Degrees); - result = SetDisplayProperties(base::NumberToString(secondary.id()), - std::move(properties)); - EXPECT_EQ(crosapi::mojom::DisplayConfigResult::kSuccess, result); - EXPECT_EQ(gfx::Rect(1200, 0, 500, 300), secondary.bounds()); - EXPECT_EQ(display::Display::ROTATE_270, secondary.rotation()); + { + DisplayConfigProperties properties; + properties.rotation = crosapi::mojom::DisplayRotationOptions::k270Degrees; + auto result = + SetDisplayProperties(base::NumberToString(secondary.id()), properties); + EXPECT_EQ(DisplayConfigResult::kSuccess, result); + EXPECT_EQ(gfx::Rect(1200, 0, 500, 300), secondary.bounds()); + EXPECT_EQ(display::Display::ROTATE_270, secondary.rotation()); + } // Test setting primary and rotating. - properties = crosapi::mojom::DisplayConfigProperties::New(); - properties->set_primary = true; - properties->rotation = crosapi::mojom::DisplayRotation::New( - crosapi::mojom::DisplayRotationOptions::k180Degrees); - result = SetDisplayProperties(base::NumberToString(secondary.id()), - std::move(properties)); - EXPECT_EQ(crosapi::mojom::DisplayConfigResult::kSuccess, result); - const display::Display& primary = display::Screen::Get()->GetPrimaryDisplay(); - EXPECT_EQ(secondary.id(), primary.id()); - EXPECT_EQ(gfx::Rect(0, 0, 300, 500), primary.bounds()); - EXPECT_EQ(display::Display::ROTATE_180, primary.rotation()); + { + DisplayConfigProperties properties; + properties.set_primary = true; + properties.rotation = crosapi::mojom::DisplayRotationOptions::k180Degrees; + auto result = + SetDisplayProperties(base::NumberToString(secondary.id()), properties); + EXPECT_EQ(DisplayConfigResult::kSuccess, result); + const display::Display& primary = + display::Screen::Get()->GetPrimaryDisplay(); + EXPECT_EQ(secondary.id(), primary.id()); + EXPECT_EQ(gfx::Rect(0, 0, 300, 500), primary.bounds()); + EXPECT_EQ(display::Display::ROTATE_180, primary.rotation()); + } } TEST_F(CrosDisplayConfigTest, SetDisplayPropertiesBoundsOrigin) { @@ -557,35 +547,41 @@ display::test::DisplayManagerTestApi(display_manager()) .GetSecondaryDisplay(); - crosapi::mojom::DisplayConfigResult result; + { + DisplayConfigProperties properties; + properties.bounds_origin = gfx::Point({-520, 50}); + auto result = + SetDisplayProperties(base::NumberToString(secondary.id()), properties); + EXPECT_EQ(DisplayConfigResult::kSuccess, result); + EXPECT_EQ(gfx::Rect(-520, 50, 520, 400), secondary.bounds()); + } - auto properties = crosapi::mojom::DisplayConfigProperties::New(); - properties->bounds_origin = gfx::Point({-520, 50}); - result = SetDisplayProperties(base::NumberToString(secondary.id()), - std::move(properties)); - EXPECT_EQ(crosapi::mojom::DisplayConfigResult::kSuccess, result); - EXPECT_EQ(gfx::Rect(-520, 50, 520, 400), secondary.bounds()); + { + DisplayConfigProperties properties; + properties.bounds_origin = gfx::Point({1200, 100}); + auto result = + SetDisplayProperties(base::NumberToString(secondary.id()), properties); + EXPECT_EQ(DisplayConfigResult::kSuccess, result); + EXPECT_EQ(gfx::Rect(1200, 100, 520, 400), secondary.bounds()); + } - properties = crosapi::mojom::DisplayConfigProperties::New(); - properties->bounds_origin = gfx::Point({1200, 100}); - result = SetDisplayProperties(base::NumberToString(secondary.id()), - std::move(properties)); - EXPECT_EQ(crosapi::mojom::DisplayConfigResult::kSuccess, result); - EXPECT_EQ(gfx::Rect(1200, 100, 520, 400), secondary.bounds()); + { + DisplayConfigProperties properties; + properties.bounds_origin = gfx::Point({1100, -400}); + auto result = + SetDisplayProperties(base::NumberToString(secondary.id()), properties); + EXPECT_EQ(DisplayConfigResult::kSuccess, result); + EXPECT_EQ(gfx::Rect(1100, -400, 520, 400), secondary.bounds()); + } - properties = crosapi::mojom::DisplayConfigProperties::New(); - properties->bounds_origin = gfx::Point({1100, -400}); - result = SetDisplayProperties(base::NumberToString(secondary.id()), - std::move(properties)); - EXPECT_EQ(crosapi::mojom::DisplayConfigResult::kSuccess, result); - EXPECT_EQ(gfx::Rect(1100, -400, 520, 400), secondary.bounds()); - - properties = crosapi::mojom::DisplayConfigProperties::New(); - properties->bounds_origin = gfx::Point({-350, 600}); - result = SetDisplayProperties(base::NumberToString(secondary.id()), - std::move(properties)); - EXPECT_EQ(crosapi::mojom::DisplayConfigResult::kSuccess, result); - EXPECT_EQ(gfx::Rect(-350, 600, 520, 400), secondary.bounds()); + { + DisplayConfigProperties properties; + properties.bounds_origin = gfx::Point({-350, 600}); + auto result = + SetDisplayProperties(base::NumberToString(secondary.id()), properties); + EXPECT_EQ(DisplayConfigResult::kSuccess, result); + EXPECT_EQ(gfx::Rect(-350, 600, 520, 400), secondary.bounds()); + } } TEST_F(CrosDisplayConfigTest, SetDisplayPropertiesDisplayZoomFactor) { @@ -613,43 +609,47 @@ display_manager()->GetDisplayInfo(display_id_list[1]).zoom_factor()); // Set zoom factor for display 0, should not affect display 1. - auto properties = crosapi::mojom::DisplayConfigProperties::New(); - properties->display_zoom_factor = zoom_factor_1; - crosapi::mojom::DisplayConfigResult result = SetDisplayProperties( - base::NumberToString(display_id_list[0]), std::move(properties)); - EXPECT_EQ(crosapi::mojom::DisplayConfigResult::kSuccess, result); - EXPECT_EQ( - zoom_factor_1, - display_manager()->GetDisplayInfo(display_id_list[0]).zoom_factor()); - EXPECT_EQ( - zoom_factor_1, - display_manager()->GetDisplayInfo(display_id_list[1]).zoom_factor()); + { + DisplayConfigProperties properties; + properties.display_zoom_factor = zoom_factor_1; + auto result = SetDisplayProperties( + base::NumberToString(display_id_list[0]), properties); + EXPECT_EQ(DisplayConfigResult::kSuccess, result); + EXPECT_EQ( + zoom_factor_1, + display_manager()->GetDisplayInfo(display_id_list[0]).zoom_factor()); + EXPECT_EQ( + zoom_factor_1, + display_manager()->GetDisplayInfo(display_id_list[1]).zoom_factor()); + } // Set zoom factor for display 1. - properties = crosapi::mojom::DisplayConfigProperties::New(); - properties->display_zoom_factor = zoom_factor_2; - result = SetDisplayProperties(base::NumberToString(display_id_list[1]), - std::move(properties)); - EXPECT_EQ(crosapi::mojom::DisplayConfigResult::kSuccess, result); - EXPECT_EQ( - zoom_factor_1, - display_manager()->GetDisplayInfo(display_id_list[0]).zoom_factor()); - EXPECT_EQ( - zoom_factor_2, - display_manager()->GetDisplayInfo(display_id_list[1]).zoom_factor()); + { + DisplayConfigProperties properties; + properties.display_zoom_factor = zoom_factor_2; + auto result = SetDisplayProperties( + base::NumberToString(display_id_list[1]), properties); + EXPECT_EQ(DisplayConfigResult::kSuccess, result); + EXPECT_EQ( + zoom_factor_1, + display_manager()->GetDisplayInfo(display_id_list[0]).zoom_factor()); + EXPECT_EQ( + zoom_factor_2, + display_manager()->GetDisplayInfo(display_id_list[1]).zoom_factor()); + } // Invalid zoom factor should fail. - const float invalid_zoom_factor = 0.01f; - properties = crosapi::mojom::DisplayConfigProperties::New(); - properties->display_zoom_factor = invalid_zoom_factor; - result = SetDisplayProperties(base::NumberToString(display_id_list[1]), - std::move(properties)); - EXPECT_EQ( - crosapi::mojom::DisplayConfigResult::kPropertyValueOutOfRangeError, - result); - EXPECT_EQ( - zoom_factor_2, - display_manager()->GetDisplayInfo(display_id_list[1]).zoom_factor()); + { + const float invalid_zoom_factor = 0.01f; + DisplayConfigProperties properties; + properties.display_zoom_factor = invalid_zoom_factor; + auto result = SetDisplayProperties( + base::NumberToString(display_id_list[1]), properties); + EXPECT_EQ(DisplayConfigResult::kPropertyValueOutOfRangeError, result); + EXPECT_EQ( + zoom_factor_2, + display_manager()->GetDisplayInfo(display_id_list[1]).zoom_factor()); + } } } @@ -662,11 +662,11 @@ EXPECT_EQ(0, result[0]->selected_display_mode_index); ASSERT_EQ(1u, result[0]->available_display_modes.size()); - auto properties = crosapi::mojom::DisplayConfigProperties::New(); + DisplayConfigProperties properties; auto display_mode = result[0]->available_display_modes[0].Clone(); - properties->display_mode = std::move(display_mode); - ASSERT_EQ(crosapi::mojom::DisplayConfigResult::kSuccess, - SetDisplayProperties(result[0]->id, std::move(properties))); + properties.display_mode = std::move(display_mode); + ASSERT_EQ(DisplayConfigResult::kSuccess, + SetDisplayProperties(result[0]->id, properties)); result = GetDisplayUnitInfoList(); ASSERT_EQ(2u, result.size()); @@ -779,16 +779,20 @@ std::string id = base::NumberToString(display_id); - EXPECT_TRUE(StartTouchCalibration(id)); - crosapi::mojom::TouchCalibrationPtr calibration = GetDefaultCalibration(); - calibration->pairs[0]->display_point.set_x(-1); - EXPECT_FALSE(CompleteCustomTouchCalibration(id, std::move(calibration))); + { + EXPECT_TRUE(StartTouchCalibration(id)); + display::TouchCalibrationData calibration; + calibration.point_pairs[0].first.set_x(-1); + EXPECT_FALSE(CompleteCustomTouchCalibration(id, calibration)); + } - EXPECT_TRUE(StartTouchCalibration(id)); - calibration = GetDefaultCalibration(); - calibration->bounds.set_width(1); - calibration->pairs[0]->display_point.set_x(2); - EXPECT_FALSE(CompleteCustomTouchCalibration(id, std::move(calibration))); + { + EXPECT_TRUE(StartTouchCalibration(id)); + display::TouchCalibrationData calibration; + calibration.bounds.set_width(1); + calibration.point_pairs[0].first.set_x(2); + EXPECT_FALSE(CompleteCustomTouchCalibration(id, calibration)); + } } TEST_F(CrosDisplayConfigTest, CustomTouchCalibrationSuccess) { @@ -812,8 +816,8 @@ EXPECT_TRUE(StartTouchCalibration(id)); EXPECT_TRUE(IsTouchCalibrationActive()); - crosapi::mojom::TouchCalibrationPtr calibration = GetDefaultCalibration(); - EXPECT_TRUE(CompleteCustomTouchCalibration(id, std::move(calibration))); + display::TouchCalibrationData calibration; + EXPECT_TRUE(CompleteCustomTouchCalibration(id, calibration)); } TEST_F(CrosDisplayConfigTest, TabletModeAutoRotationInternalOnly) { @@ -855,84 +859,88 @@ display::test::DisplayManagerTestApi(display_manager()) .SetFirstDisplayAsInternalDisplay(); - - // Setting the rotation to kAutoRotate from outside the physical tablet state - // is treated as a request to set the rotation to 0. const display::Display& display = display_manager()->GetPrimaryDisplayCandidate(); - auto properties = crosapi::mojom::DisplayConfigProperties::New(); - properties->rotation = crosapi::mojom::DisplayRotation::New( - crosapi::mojom::DisplayRotationOptions::kAutoRotate); - auto result = SetDisplayProperties(base::NumberToString(display.id()), - std::move(properties)); - EXPECT_EQ(crosapi::mojom::DisplayConfigResult::kSuccess, result); auto* screen_orientation_controller = Shell::Get()->screen_orientation_controller(); - EXPECT_FALSE(screen_orientation_controller->user_rotation_locked()); - EXPECT_EQ(display::Display::ROTATE_0, display.rotation()); - TabletModeControllerTestApi tablet_mode_controller_test_api; ScreenOrientationControllerTestApi screen_orientation_controller_test_api( screen_orientation_controller); - tablet_mode_controller_test_api.EnterTabletMode(); - EXPECT_TRUE(tablet_mode_controller_test_api.IsInPhysicalTabletState()); - EXPECT_TRUE(screen_orientation_controller_test_api.IsAutoRotationAllowed()); - EXPECT_TRUE(display::Screen::Get()->InTabletMode()); - // Clear out any pending observer calls. - base::RunLoop().RunUntilIdle(); - observer.reset_display_changes(); + // Setting the rotation to kAutoRotate from outside the physical tablet state + // is treated as a request to set the rotation to 0. + { + DisplayConfigProperties properties; + properties.rotation = crosapi::mojom::DisplayRotationOptions::kAutoRotate; + auto result = + SetDisplayProperties(base::NumberToString(display.id()), properties); + EXPECT_EQ(DisplayConfigResult::kSuccess, result); + EXPECT_FALSE(screen_orientation_controller->user_rotation_locked()); + EXPECT_EQ(display::Display::ROTATE_0, display.rotation()); - properties = crosapi::mojom::DisplayConfigProperties::New(); - properties->rotation = crosapi::mojom::DisplayRotation::New( - crosapi::mojom::DisplayRotationOptions::k90Degrees); - result = SetDisplayProperties(base::NumberToString(display.id()), - std::move(properties)); - EXPECT_EQ(crosapi::mojom::DisplayConfigResult::kSuccess, result); - EXPECT_TRUE(screen_orientation_controller->user_rotation_locked()); - EXPECT_EQ(display::Display::ROTATE_90, display.rotation()); - // OnDisplayConfigChanged() will be called twice, once as a result of the - // user rotation lock change, and another due to the actual display rotation - // change. - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(2, observer.display_changes()); + tablet_mode_controller_test_api.EnterTabletMode(); + EXPECT_TRUE(tablet_mode_controller_test_api.IsInPhysicalTabletState()); + EXPECT_TRUE(screen_orientation_controller_test_api.IsAutoRotationAllowed()); + EXPECT_TRUE(display::Screen::Get()->InTabletMode()); - // Hooking up an external mouse device, should exit UI tablet mode, but the - // device is still in a tablet physical state, the API should still be valid - // for use. - tablet_mode_controller_test_api.AttachExternalMouse(); - EXPECT_TRUE(tablet_mode_controller_test_api.IsInPhysicalTabletState()); - EXPECT_TRUE(screen_orientation_controller_test_api.IsAutoRotationAllowed()); - EXPECT_FALSE(display::Screen::Get()->InTabletMode()); + // Clear out any pending observer calls. + base::RunLoop().RunUntilIdle(); + observer.reset_display_changes(); + } - // Clear out any pending observer calls. - base::RunLoop().RunUntilIdle(); - observer.reset_display_changes(); + { + DisplayConfigProperties properties; + properties.rotation = crosapi::mojom::DisplayRotationOptions::k90Degrees; + auto result = + SetDisplayProperties(base::NumberToString(display.id()), properties); + EXPECT_EQ(DisplayConfigResult::kSuccess, result); + EXPECT_TRUE(screen_orientation_controller->user_rotation_locked()); + EXPECT_EQ(display::Display::ROTATE_90, display.rotation()); + // OnDisplayConfigChanged() will be called twice, once as a result of the + // user rotation lock change, and another due to the actual display rotation + // change. + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(2, observer.display_changes()); - properties = crosapi::mojom::DisplayConfigProperties::New(); - properties->rotation = crosapi::mojom::DisplayRotation::New( - crosapi::mojom::DisplayRotationOptions::kAutoRotate); - result = SetDisplayProperties(base::NumberToString(display.id()), - std::move(properties)); - EXPECT_EQ(crosapi::mojom::DisplayConfigResult::kSuccess, result); - EXPECT_FALSE(screen_orientation_controller->user_rotation_locked()); - // Unlocking auto-rotate doesn't actually change the display rotation. It - // simply allows it to auto-rotate in response to accelerometer updates. - EXPECT_EQ(display::Display::ROTATE_90, display.rotation()); - // This time, OnDisplayConfigChanged() will be called only once as a result of - // the user rotation lock change. - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(1, observer.display_changes()); + // Hooking up an external mouse device, should exit UI tablet mode, but the + // device is still in a tablet physical state, the API should still be valid + // for use. + tablet_mode_controller_test_api.AttachExternalMouse(); + EXPECT_TRUE(tablet_mode_controller_test_api.IsInPhysicalTabletState()); + EXPECT_TRUE(screen_orientation_controller_test_api.IsAutoRotationAllowed()); + EXPECT_FALSE(display::Screen::Get()->InTabletMode()); - // Once the device is no longer in a physical tablet state, the rotation is - // restored. - tablet_mode_controller_test_api.LeaveTabletMode(); - EXPECT_FALSE(tablet_mode_controller_test_api.IsInPhysicalTabletState()); - EXPECT_FALSE(screen_orientation_controller_test_api.IsAutoRotationAllowed()); - EXPECT_FALSE(display::Screen::Get()->InTabletMode()); - EXPECT_EQ(display::Display::ROTATE_0, display.rotation()); + // Clear out any pending observer calls. + base::RunLoop().RunUntilIdle(); + observer.reset_display_changes(); + } - cros_display_config()->RemoveObserver(&observer); + { + DisplayConfigProperties properties; + properties.rotation = crosapi::mojom::DisplayRotationOptions::kAutoRotate; + auto result = + SetDisplayProperties(base::NumberToString(display.id()), properties); + EXPECT_EQ(DisplayConfigResult::kSuccess, result); + EXPECT_FALSE(screen_orientation_controller->user_rotation_locked()); + // Unlocking auto-rotate doesn't actually change the display rotation. It + // simply allows it to auto-rotate in response to accelerometer updates. + EXPECT_EQ(display::Display::ROTATE_90, display.rotation()); + // This time, OnDisplayConfigChanged() will be called only once as a result + // of the user rotation lock change. + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(1, observer.display_changes()); + + // Once the device is no longer in a physical tablet state, the rotation is + // restored. + tablet_mode_controller_test_api.LeaveTabletMode(); + EXPECT_FALSE(tablet_mode_controller_test_api.IsInPhysicalTabletState()); + EXPECT_FALSE( + screen_orientation_controller_test_api.IsAutoRotationAllowed()); + EXPECT_FALSE(display::Screen::Get()->InTabletMode()); + EXPECT_EQ(display::Display::ROTATE_0, display.rotation()); + + cros_display_config()->RemoveObserver(&observer); + } } TEST_F(CrosDisplayConfigTest, HighlightDisplayValid) {
diff --git a/ash/events/accessibility_event_rewriter.cc b/ash/events/accessibility_event_rewriter.cc index 22d7362..7da1a50 100644 --- a/ash/events/accessibility_event_rewriter.cc +++ b/ash/events/accessibility_event_rewriter.cc
@@ -333,11 +333,17 @@ return true; } + // Try to forward the key event to the ChromeVox service worker. + if (!delegate_->DispatchKeyEventToChromeVoxMv3( + next_pending_event_id_, rewritten_key_event->Clone())) { + // Unable to send to the service worker. ChromeVox has probably crashed. + // Do not further forward this event, or enqueue it. + return false; + } + pending_key_events_.emplace(next_pending_event_id_, rewritten_key_event->Clone(), continuation); - // Forward the key event to the ChromeVox service worker. - delegate_->DispatchKeyEventToChromeVoxMv3(next_pending_event_id_, - rewritten_key_event->Clone()); + // Forward the key event to other ChromeVox extension contexts, like learn // mode and the panel. delegate_->DispatchKeyEventToChromeVox(rewritten_key_event->Clone(), true);
diff --git a/ash/events/accessibility_event_rewriter_unittest.cc b/ash/events/accessibility_event_rewriter_unittest.cc index a696ffc8..ddd2993 100644 --- a/ash/events/accessibility_event_rewriter_unittest.cc +++ b/ash/events/accessibility_event_rewriter_unittest.cc
@@ -75,6 +75,8 @@ // Count of captured events sent to the delegate in mv3. size_t chromevox_captured_event_count_mv3_ = 0; + bool should_fail_mv3_dispatch_ = false; + // Last key event sent to ChromeVox. ui::Event* GetLastChromeVoxKeyEvent() { return last_chromevox_key_event_.get(); @@ -100,12 +102,16 @@ } last_chromevox_key_event_ = std::move(event); } - void DispatchKeyEventToChromeVoxMv3( + bool DispatchKeyEventToChromeVoxMv3( unsigned int id, std::unique_ptr<ui::Event> event) override { + if (should_fail_mv3_dispatch_) { + return false; + } chromevox_recorded_event_count_mv3_++; chromevox_captured_event_count_mv3_++; last_chromevox_key_event_ = std::move(event); + return true; } void DispatchMouseEvent(std::unique_ptr<ui::Event> event) override { chromevox_recorded_event_count_++; @@ -288,6 +294,11 @@ .chromevox_captured_event_count_mv3_; } + void set_delegate_should_fail_mv3_dispatch(bool should_fail) { + accessibility_event_rewriter_delegate().should_fail_mv3_dispatch_ = + should_fail; + } + void SetDelegateChromeVoxCaptureAllKeys(bool value) { accessibility_event_rewriter().set_chromevox_capture_all_keys(value); } @@ -588,6 +599,39 @@ base::test::ScopedFeatureList scoped_feature_list_; }; +TEST_F(ChromeVoxMv3AccessibilityEventRewriterTest, + KeysNotEatenWhenDelegateFailsToSendEventsToMv3) { + set_delegate_should_fail_mv3_dispatch(true); + AccessibilityController* controller = GetAccessibilityController(); + controller->SetSpokenFeedbackEnabled(true, A11Y_NOTIFICATION_NONE); + EXPECT_TRUE(controller->spoken_feedback().enabled()); + accessibility_event_rewriter().SetSpokenFeedbackMv3KeyHandlingEnabled( + true, /*session_id=*/1); + + // Send Search+Shift+Right. + generator().PressKey(ui::VKEY_LWIN, ui::EF_COMMAND_DOWN); + EXPECT_EQ(1, event_recorder().events_seen()); + generator().PressKey(ui::VKEY_SHIFT, ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN); + EXPECT_EQ(2, event_recorder().events_seen()); + + // Nothing was enqueued. + EXPECT_EQ(0u, next_pending_event_id()); + EXPECT_EQ(0U, GetPendingKeyEventsSize()); + + // Pretend the service worker comes back online. + set_delegate_should_fail_mv3_dispatch(false); + + // Now the events should be captured, so event_recorder sees no more events. + generator().PressKey(ui::VKEY_LWIN, ui::EF_COMMAND_DOWN); + generator().PressKey(ui::VKEY_SHIFT, ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN); + + EXPECT_EQ(2, event_recorder().events_seen()); + + // These events were enqueued. + EXPECT_EQ(2u, next_pending_event_id()); + EXPECT_EQ(2U, GetPendingKeyEventsSize()); +} + TEST_F(ChromeVoxMv3AccessibilityEventRewriterTest, NextPendingEventId) { AccessibilityController* controller = GetAccessibilityController(); controller->SetSpokenFeedbackEnabled(true, A11Y_NOTIFICATION_NONE);
diff --git a/ash/public/cpp/accessibility_event_rewriter_delegate.h b/ash/public/cpp/accessibility_event_rewriter_delegate.h index 3858cb4..0cd5f11 100644 --- a/ash/public/cpp/accessibility_event_rewriter_delegate.h +++ b/ash/public/cpp/accessibility_event_rewriter_delegate.h
@@ -30,8 +30,9 @@ bool capture) = 0; // Used to send key events to the ChromeVox extension in manifest v3 via the - // accessibility private extension API. - virtual void DispatchKeyEventToChromeVoxMv3( + // accessibility private extension API. Returns `true` if the key event was + // sent, and `false` otherwise. + virtual bool DispatchKeyEventToChromeVoxMv3( unsigned int id, std::unique_ptr<ui::Event> event) = 0;
diff --git a/ash/system/human_presence/human_presence_orientation_controller_unittest.cc b/ash/system/human_presence/human_presence_orientation_controller_unittest.cc index bb9d123..c4029c7 100644 --- a/ash/system/human_presence/human_presence_orientation_controller_unittest.cc +++ b/ash/system/human_presence/human_presence_orientation_controller_unittest.cc
@@ -72,6 +72,14 @@ .SetFirstDisplayAsInternalDisplay(); } + void TearDown() override { + power_manager_client_ = nullptr; + display_manager_ = nullptr; + tablet_mode_controller_ = nullptr; + orientation_controller_ = nullptr; + AshTestBase::TearDown(); + } + protected: void RotateDisplay(int display_index, int degrees) { const int64_t id = display_manager_->GetDisplayAt(display_index).id(); @@ -80,14 +88,10 @@ display::Display::RotationSource::ACTIVE); } - raw_ptr<HumanPresenceOrientationController, DanglingUntriaged> - orientation_controller_ = nullptr; - raw_ptr<TabletModeController, DanglingUntriaged> tablet_mode_controller_ = - nullptr; - raw_ptr<display::DisplayManager, DanglingUntriaged> display_manager_ = - nullptr; - raw_ptr<chromeos::FakePowerManagerClient, DanglingUntriaged> - power_manager_client_ = nullptr; + raw_ptr<HumanPresenceOrientationController> orientation_controller_ = nullptr; + raw_ptr<TabletModeController> tablet_mode_controller_ = nullptr; + raw_ptr<display::DisplayManager> display_manager_ = nullptr; + raw_ptr<chromeos::FakePowerManagerClient> power_manager_client_ = nullptr; private: base::test::ScopedFeatureList scoped_feature_list_;
diff --git a/ash/system/night_light/night_light_controller_unittest.cc b/ash/system/night_light/night_light_controller_unittest.cc index 127a5dc..9b02f5f 100644 --- a/ash/system/night_light/night_light_controller_unittest.cc +++ b/ash/system/night_light/night_light_controller_unittest.cc
@@ -1230,6 +1230,7 @@ // DisplayChangeObserver access DeviceDataManager in its destructor, so // destroy it first. display_change_observer_ = nullptr; + native_display_delegate_ = nullptr; NightLightTest::TearDown(); } @@ -1293,8 +1294,7 @@ private: std::unique_ptr<display::test::ActionLogger> logger_; // Not owned. - raw_ptr<display::test::TestNativeDisplayDelegate, DanglingUntriaged> - native_display_delegate_; + raw_ptr<display::test::TestNativeDisplayDelegate> native_display_delegate_; std::unique_ptr<display::DisplayChangeObserver> display_change_observer_; std::unique_ptr<display::DisplayConfigurator::TestApi> test_api_; }; @@ -1782,6 +1782,8 @@ // DisplayChangeObserver access DeviceDataManager in its destructor, so // destroy it first. display_change_observer_ = nullptr; + native_display_delegate_ = nullptr; + controller_ = nullptr; NightLightTest::TearDown(); } @@ -1790,9 +1792,8 @@ std::unique_ptr<display::test::ActionLogger> logger_; // Not owned. - raw_ptr<NightLightControllerImpl, DanglingUntriaged> controller_; - raw_ptr<display::test::TestNativeDisplayDelegate, DanglingUntriaged> - native_display_delegate_; + raw_ptr<NightLightControllerImpl> controller_; + raw_ptr<display::test::TestNativeDisplayDelegate> native_display_delegate_; std::unique_ptr<display::DisplayChangeObserver> display_change_observer_; std::unique_ptr<display::DisplayConfigurator::TestApi> test_api_; };
diff --git a/ash/webui/common/resources/auth_setup/OWNERS b/ash/webui/common/resources/auth_setup/OWNERS new file mode 100644 index 0000000..20e41d6 --- /dev/null +++ b/ash/webui/common/resources/auth_setup/OWNERS
@@ -0,0 +1 @@ +file://ash/login/LOGIN_LOCK_OWNERS
diff --git a/ash/webui/common/resources/quick_unlock/OWNERS b/ash/webui/common/resources/quick_unlock/OWNERS new file mode 100644 index 0000000..20e41d6 --- /dev/null +++ b/ash/webui/common/resources/quick_unlock/OWNERS
@@ -0,0 +1 @@ +file://ash/login/LOGIN_LOCK_OWNERS
diff --git a/base/BUILD.gn b/base/BUILD.gn index bc18a7e..17b0a94 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn
@@ -379,6 +379,7 @@ "memory/available_memory_monitor.cc", "memory/available_memory_monitor.h", "memory/free_deleter.h", + "memory/index_pointer.h", "memory/memory_pressure_level.h", "memory/memory_pressure_listener.cc", "memory/memory_pressure_listener.h", @@ -1438,7 +1439,10 @@ ":metrics_jni($default_toolchain)", ":tasks_minimal_jni($default_toolchain)", ] - public_deps += [ "//third_party/jni_zero" ] + public_deps += [ + ":uuid_jni($default_toolchain)", + "//third_party/jni_zero", + ] } # is_android || is_robolectric # Chromeos. @@ -4662,6 +4666,10 @@ ] } + generate_jar_jni("uuid_jni") { + classes = [ "java/util/UUID.class" ] + } + java_cpp_features("java_features_srcjar") { # External code should depend on ":base_java" instead. visibility = [ ":*" ]
diff --git a/base/OWNERS b/base/OWNERS index e4a908d..8bcdea9 100644 --- a/base/OWNERS +++ b/base/OWNERS
@@ -28,7 +28,8 @@ # For Windows-specific changes: per-file ..._win*=file://base/win/OWNERS -per-file feature_list*=asvitkine@chromium.org +# For base::Feature and base::FeatureList changes: +per-file feature*=asvitkine@chromium.org # Logging-related changes: per-file check*=olivierli@chromium.org
diff --git a/base/android/command_line_android.cc b/base/android/command_line_android.cc index 79824e8..e631c51 100644 --- a/base/android/command_line_android.cc +++ b/base/android/command_line_android.cc
@@ -72,6 +72,10 @@ CommandLine::Init(0, nullptr); AppendToCommandLine(command_line, true); } + +bool WasFlagsLoadedFromFile(JNIEnv* env) { + return static_cast<bool>(Java_CommandLine_wasFlagsLoadedFromFile(env)); +} } // namespace base::android DEFINE_JNI(CommandLine)
diff --git a/base/android/command_line_android.h b/base/android/command_line_android.h index 58b54f8d2..6943cd90 100644 --- a/base/android/command_line_android.h +++ b/base/android/command_line_android.h
@@ -5,6 +5,7 @@ #ifndef BASE_ANDROID_COMMAND_LINE_ANDROID_H_ #define BASE_ANDROID_COMMAND_LINE_ANDROID_H_ +#include <jni.h> #include <string> #include <vector> @@ -12,6 +13,9 @@ namespace base::android { BASE_EXPORT void CommandLineInit(std::vector<std::string>& command_line); + +BASE_EXPORT bool WasFlagsLoadedFromFile(JNIEnv* env); + } // namespace base::android #endif // BASE_ANDROID_COMMAND_LINE_ANDROID_H_
diff --git a/base/android/java/src/org/chromium/base/CommandLine.java b/base/android/java/src/org/chromium/base/CommandLine.java index 16f604f5..9a5b2386 100644 --- a/base/android/java/src/org/chromium/base/CommandLine.java +++ b/base/android/java/src/org/chromium/base/CommandLine.java
@@ -10,6 +10,7 @@ import androidx.annotation.VisibleForTesting; +import org.jni_zero.CalledByNative; import org.jni_zero.JniType; import org.jni_zero.NativeMethods; @@ -49,6 +50,7 @@ private static final String SWITCH_TERMINATOR = SWITCH_PREFIX; private static final String SWITCH_VALUE_SEPARATOR = "="; private static final CommandLine sInstance = new CommandLine(); + private static boolean sFlagsLoadedFromFile; // Fields are initialized by initInternal() and set to null upon switching to native impl. private @Nullable Map<String, String> mSwitches; @@ -110,6 +112,7 @@ // The file existed, which should never be the case under normal operation. // Use a log message to help with debugging if it's the flags that are causing issues. if (tokenized != null) { + sFlagsLoadedFromFile = true; Log.i(TAG, "COMMAND-LINE FLAGS: %s (from %s)", Arrays.toString(tokenized), file); } } @@ -385,6 +388,12 @@ } } + /** Called from native C++ to check if the flags were loaded from a file. */ + @CalledByNative + private static boolean wasFlagsLoadedFromFile() { + return sFlagsLoadedFromFile; + } + @NativeMethods interface Natives { void init(@JniType("std::vector<std::string>") List<String> args);
diff --git a/base/containers/auto_spanification_helper.h b/base/containers/auto_spanification_helper.h index a8372d7..407fd2a 100644 --- a/base/containers/auto_spanification_helper.h +++ b/base/containers/auto_spanification_helper.h
@@ -209,6 +209,28 @@ return UNSAFE_TODO(base::span<uint8_t>(row, size)); \ }(::base::spanification_internal::ToPointer(arg_self))) +// https://source.chromium.org/chromium/chromium/src/+/main:third_party/skia/include/core/SkPixmap.h;l=537;drc=f72bd467feb15edd9323e46eab1b74ab6025bc5b;bpv=1;bpt=1 +#define UNSAFE_SKPIXMAP_GET_WRITABLE_ADDR32(arg_self, arg_x, arg_y) \ + ([](auto&& self, int x, int y) { \ + uint32_t* row = static_cast<uint32_t*>(self->writable_addr32(x, y)); \ + ::base::CheckedNumeric<size_t> width = self->width(); \ + size_t size = (width - x).ValueOrDie(); \ + CHECK(row || size == 0); \ + CHECK_NE(size, SIZE_MAX); \ + return UNSAFE_TODO(base::span<uint32_t>(row, size)); \ + }(::base::spanification_internal::ToPointer(arg_self), arg_x, arg_y)) + +// https://source.chromium.org/chromium/chromium/src/+/main:third_party/skia/include/core/SkPixmap.h;l=434;drc=f72bd467feb15edd9323e46eab1b74ab6025bc5b;bpv=1;bpt=1 +#define UNSAFE_SKPIXMAP_GET_ADDR32(arg_self, arg_x, arg_y) \ + ([](auto&& self, int x, int y) { \ + const uint32_t* row = static_cast<const uint32_t*>(self->addr32(x, y)); \ + ::base::CheckedNumeric<size_t> width = self->width(); \ + size_t size = (width - x).ValueOrDie(); \ + CHECK(row || size == 0); \ + CHECK_NE(size, SIZE_MAX); \ + return UNSAFE_TODO(base::span<const uint32_t>(row, size)); \ + }(::base::spanification_internal::ToPointer(arg_self), arg_x, arg_y)) + // https://source.chromium.org/chromium/chromium/src/+/main:cc/paint/paint_canvas.h;l=66;drc=c76e4f83a8c5786b463c3e55c070a21ac751b96b // https://source.chromium.org/chromium/chromium/src/+/main:third_party/skia/src/core/SkCanvas.cpp;l=1264;drc=6c24069ae3996c883ea5d5886d0c013cb78f8394;bpv=1;bpt=1 #define UNSAFE_PAINTCANVAS_TOP_LAYER_TO_BYTES_SPAN(arg_self, arg_info, \
diff --git a/base/containers/span.h b/base/containers/span.h index 31101d83..e6eee30e 100644 --- a/base/containers/span.h +++ b/base/containers/span.h
@@ -34,6 +34,12 @@ #include "base/numerics/safe_conversions.h" #include "base/types/to_address.h" +// nogncheck: When `use_partition_alloc` is false, +// `IsExtentOutOfBounds()` is made into a trivial, always-inlined +// function (that doesn't actually depend on the rest of +// PartitionAlloc). +#include "partition_alloc/bounds_checks.h" // nogncheck + // A span is a view of contiguous elements that can be accessed like an array, // intended for use as a parameter or local. Unlike direct use of pointers and // sizes, it enforces safe usage (and simplifies callers); unlike container @@ -315,6 +321,15 @@ }; inline constexpr allow_nonunique_obj_t allow_nonunique_obj{}; +// Tag struct used in the vein of `std::from_range_t`. +// +// Used in span constructors to elide the PartitionAlloc bounds check. +// See: https://crbug.com/484171909 +struct unchecked_t { + unchecked_t() = default; +}; +inline constexpr unchecked_t unchecked; + namespace internal { // Exposition-only concept from [span.syn] @@ -437,7 +452,7 @@ // of 1 byte, the resulting pointer has no alignment concerns, and it is not // UB to access memory contents inside the allocation through it. return UNSAFE_BUFFERS(span<ByteType, kByteExtent>( - reinterpret_cast<ByteType*>(s.data()), s.size_bytes())); + unchecked, reinterpret_cast<ByteType*>(s.data()), s.size_bytes())); } } // namespace internal @@ -474,6 +489,23 @@ // PRECONDITIONS: `first` must point to the first of at least `count` // contiguous valid elements. UNSAFE_BUFFER_USAGE constexpr span(It first, StrictNumeric<size_type> count) + : span(unchecked, first, count) { + if (!std::is_constant_evaluated()) { + if (data() || size()) { + CHECK(!partition_alloc::IsExtentOutOfBounds(data(), size_bytes(), + sizeof(element_type))); + } + } + } + + // Iterator + count, skipping PartitionAlloc bounds check. + template <typename It> + requires(internal::CompatibleIter<element_type, It>) + // PRECONDITIONS: `first` must point to the first of at least `count` + // contiguous valid elements. + UNSAFE_BUFFER_USAGE constexpr span(unchecked_t tag, + It first, + StrictNumeric<size_type> count) : data_(to_address(first)) { CHECK(size_type{count} == extent); @@ -490,6 +522,24 @@ // PRECONDITIONS: `first` and `last` must be for the same allocation and all // elements in the range [first, last) must be valid. UNSAFE_BUFFER_USAGE constexpr span(It first, End last) + // SAFETY: See comments in the unchecked constructor. + : UNSAFE_BUFFERS(span(unchecked, first, last)) { + if (!std::is_constant_evaluated()) { + if (data() || size()) { + CHECK(!partition_alloc::IsExtentOutOfBounds(data(), size_bytes(), + sizeof(element_type))); + } + } + } + + // Iterator + sentinel, skipping the PartitionAlloc bounds check. + template <typename It, typename End> + requires(internal::CompatibleIter<element_type, It> && + std::sized_sentinel_for<End, It> && + !std::is_convertible_v<End, size_t>) + // PRECONDITIONS: `first` and `last` must be for the same allocation and all + // elements in the range [first, last) must be valid. + UNSAFE_BUFFER_USAGE constexpr span(unchecked_t tag, It first, End last) // SAFETY: The caller must guarantee that `first` and `last` point into // the same allocation. In this case, the extent will be the number of // elements between the iterators and thus a valid size for the pointer to @@ -498,7 +548,8 @@ // It is safe to check for underflow after subtraction because the // underflow itself is not UB and `size_` is not converted to an invalid // pointer (which would be UB) before the check. - : UNSAFE_BUFFERS(span(first, static_cast<size_type>(last - first))) { + : UNSAFE_BUFFERS( + span(unchecked, first, static_cast<size_type>(last - first))) { // Verify `last - first` did not underflow. CHECK(first <= last); } @@ -507,7 +558,7 @@ // NOLINTNEXTLINE(google-explicit-constructor) constexpr span(element_type (&arr LIFETIME_BOUND)[extent]) noexcept // SAFETY: The type signature guarantees `arr` contains `extent` elements. - : UNSAFE_BUFFERS(span(arr, extent)) {} + : UNSAFE_BUFFERS(span(unchecked, arr, extent)) {} // Range. template <typename R, size_t N = internal::kComputedExtent<R>> @@ -518,8 +569,9 @@ // SAFETY: `std::ranges::size()` returns the number of elements // `std::ranges::data()` will point to, so accessing those elements will // be safe. - : UNSAFE_BUFFERS( - span(std::ranges::data(range), std::ranges::size(range))) {} + : UNSAFE_BUFFERS(span(unchecked, + std::ranges::data(range), + std::ranges::size(range))) {} template <typename R, size_t N = internal::kComputedExtent<R>> requires(internal::CompatibleRange<element_type, R> && internal::FixedExtentConstructibleFromExtent<extent, N> && @@ -529,8 +581,9 @@ // SAFETY: `std::ranges::size()` returns the number of elements // `std::ranges::data()` will point to, so accessing those elements will // be safe. - : UNSAFE_BUFFERS( - span(std::ranges::data(range), std::ranges::size(range))) {} + : UNSAFE_BUFFERS(span(unchecked, + std::ranges::data(range), + std::ranges::size(range))) {} // Initializer list. // NOLINTNEXTLINE(google-explicit-constructor) @@ -538,7 +591,7 @@ requires(std::is_const_v<element_type>) // SAFETY: `size()` is exactly the number of elements in the initializer // list, so accessing that many will be safe. - : UNSAFE_BUFFERS(span(il.begin(), il.size())) {} + : UNSAFE_BUFFERS(span(unchecked, il.begin(), il.size())) {} // Copy and move. constexpr span(const span& other) noexcept = default; @@ -552,7 +605,7 @@ other) noexcept // SAFETY: `size()` is the number of elements that can be safely accessed // at `data()`. - : UNSAFE_BUFFERS(span(other.data(), other.size())) {} + : UNSAFE_BUFFERS(span(unchecked, other.data(), other.size())) {} constexpr span(span&& other) noexcept = default; // Copy and move assignment. @@ -714,13 +767,13 @@ { // SAFETY: `data()` points to at least `extent` elements, so the new data // scope is a strict subset of the old. - return UNSAFE_BUFFERS(span<element_type, Count>(data(), Count)); + return UNSAFE_BUFFERS(span<element_type, Count>(unchecked, data(), Count)); } constexpr auto first(StrictNumeric<size_type> count) const { CHECK(size_type{count} <= extent); // SAFETY: `data()` points to at least `extent` elements, so the new data // scope is a strict subset of the old. - return UNSAFE_BUFFERS(span<element_type>(data(), count)); + return UNSAFE_BUFFERS(span<element_type>(unchecked, data(), count)); } // Last `count` elements. @@ -731,14 +784,14 @@ // SAFETY: `data()` points to at least `extent` elements, so the new data // scope is a strict subset of the old. return UNSAFE_BUFFERS( - span<element_type, Count>(data() + (extent - Count), Count)); + span<element_type, Count>(unchecked, data() + (extent - Count), Count)); } constexpr auto last(StrictNumeric<size_type> count) const { CHECK(size_type{count} <= extent); // SAFETY: `data()` points to at least `extent` elements, so the new data // scope is a strict subset of the old. - return UNSAFE_BUFFERS( - span<element_type>(data() + (extent - size_type{count}), count)); + return UNSAFE_BUFFERS(span<element_type>( + unchecked, data() + (extent - size_type{count}), count)); } // `count` elements beginning at `offset`. @@ -752,13 +805,14 @@ // SAFETY: `data()` points to at least `extent` elements, so `Offset` // specifies a valid element index or the past-the-end index, and // `kRemaining` cannot index past-the-end elements. - return UNSAFE_BUFFERS( - span<element_type, kRemaining>(data() + Offset, kRemaining)); + return UNSAFE_BUFFERS(span<element_type, kRemaining>( + unchecked, data() + Offset, kRemaining)); } else { // SAFETY: `data()` points to at least `extent` elements, so `Offset` // specifies a valid element index or the past-the-end index, and `Count` // is no larger than the number of remaining valid elements. - return UNSAFE_BUFFERS(span<element_type, Count>(data() + Offset, Count)); + return UNSAFE_BUFFERS( + span<element_type, Count>(unchecked, data() + Offset, Count)); } } constexpr auto subspan(StrictNumeric<size_type> offset) const { @@ -768,7 +822,7 @@ // specifies a valid element index or the past-the-end index, and // `remaining` cannot index past-the-end elements. return UNSAFE_BUFFERS( - span<element_type>(data() + size_type{offset}, remaining)); + span<element_type>(unchecked, data() + size_type{offset}, remaining)); } constexpr auto subspan(StrictNumeric<size_type> offset, StrictNumeric<size_type> count) const { @@ -781,7 +835,7 @@ // specifies a valid element index or the past-the-end index, and `count` is // no larger than the number of remaining valid elements. return UNSAFE_BUFFERS( - span<element_type>(data() + size_type{offset}, count)); + span<element_type>(unchecked, data() + size_type{offset}, count)); } // Splits a span a given offset, returning a pair of spans that cover the @@ -1016,6 +1070,23 @@ // PRECONDITIONS: `first` must point to the first of at least `count` // contiguous valid elements. UNSAFE_BUFFER_USAGE constexpr span(It first, StrictNumeric<size_type> count) + : span(unchecked, first, count) { + if (!std::is_constant_evaluated()) { + if (data() || size()) { + CHECK(!partition_alloc::IsExtentOutOfBounds(data(), size_bytes(), + sizeof(element_type))); + } + } + } + + // Iterator + count, skipping PartitionAlloc bounds check. + template <typename It> + requires(internal::CompatibleIter<element_type, It>) + // PRECONDITIONS: `first` must point to the first of at least `count` + // contiguous valid elements. + UNSAFE_BUFFER_USAGE constexpr span(unchecked_t tag, + It first, + StrictNumeric<size_type> count) : data_(to_address(first)), size_(count) { // Non-zero `count` implies non-null `data_`. Use `SpanOrSize<T>` to // represent a size that might not be accompanied by the actual data. @@ -1030,6 +1101,24 @@ // PRECONDITIONS: `first` and `last` must be for the same allocation and all // elements in the range [first, last) must be valid. UNSAFE_BUFFER_USAGE constexpr span(It first, End last) + // SAFETY: See comments in the unchecked constructor. + : UNSAFE_BUFFERS(span(unchecked, first, last)) { + if (!std::is_constant_evaluated()) { + if (data() || size()) { + CHECK(!partition_alloc::IsExtentOutOfBounds(data(), size_bytes(), + sizeof(element_type))); + } + } + } + + // Iterator + sentinel, skipping the PartitionAlloc bounds check. + template <typename It, typename End> + requires(internal::CompatibleIter<element_type, It> && + std::sized_sentinel_for<End, It> && + !std::is_convertible_v<End, size_t>) + // PRECONDITIONS: `first` and `last` must be for the same allocation and all + // elements in the range [first, last) must be valid. + UNSAFE_BUFFER_USAGE constexpr span(unchecked_t tag, It first, End last) // SAFETY: The caller must guarantee that `first` and `last` point into // the same allocation. In this case, `size_` will be the number of // elements between the iterators and thus a valid size for the pointer to @@ -1038,7 +1127,8 @@ // It is safe to check for underflow after subtraction because the // underflow itself is not UB and `size_` is not converted to an invalid // pointer (which would be UB) before the check. - : UNSAFE_BUFFERS(span(first, static_cast<size_type>(last - first))) { + : UNSAFE_BUFFERS( + span(unchecked, first, static_cast<size_type>(last - first))) { // Verify `last - first` did not underflow. CHECK(first <= last); } @@ -1048,7 +1138,7 @@ // NOLINTNEXTLINE(google-explicit-constructor) constexpr span(element_type (&arr LIFETIME_BOUND)[N]) noexcept // SAFETY: The type signature guarantees `arr` contains `N` elements. - : UNSAFE_BUFFERS(span(arr, N)) {} + : UNSAFE_BUFFERS(span(unchecked, arr, N)) {} // Range. template <typename R> @@ -1058,8 +1148,9 @@ // SAFETY: `std::ranges::size()` returns the number of elements // `std::ranges::data()` will point to, so accessing those elements will // be safe. - : UNSAFE_BUFFERS( - span(std::ranges::data(range), std::ranges::size(range))) {} + : UNSAFE_BUFFERS(span(unchecked, + std::ranges::data(range), + std::ranges::size(range))) {} template <typename R> requires(internal::CompatibleRange<element_type, R> && std::ranges::borrowed_range<R>) @@ -1068,15 +1159,16 @@ // SAFETY: `std::ranges::size()` returns the number of elements // `std::ranges::data()` will point to, so accessing those elements will // be safe. - : UNSAFE_BUFFERS( - span(std::ranges::data(range), std::ranges::size(range))) {} + : UNSAFE_BUFFERS(span(unchecked, + std::ranges::data(range), + std::ranges::size(range))) {} // Initializer list. constexpr span(std::initializer_list<value_type> il LIFETIME_BOUND) requires(std::is_const_v<element_type>) // SAFETY: `size()` is exactly the number of elements in the initializer // list, so accessing that many will be safe. - : UNSAFE_BUFFERS(span(il.begin(), il.size())) {} + : UNSAFE_BUFFERS(span(unchecked, il.begin(), il.size())) {} // Copy and move. constexpr span(const span& other) noexcept = default; @@ -1201,13 +1293,13 @@ CHECK(Count <= size()); // SAFETY: `data()` points to at least `size()` elements, so the new data // scope is a strict subset of the old. - return UNSAFE_BUFFERS(span<element_type, Count>(data(), Count)); + return UNSAFE_BUFFERS(span<element_type, Count>(unchecked, data(), Count)); } constexpr auto first(StrictNumeric<size_t> count) const { CHECK(size_type{count} <= size()); // SAFETY: `data()` points to at least `size()` elements, so the new data // scope is a strict subset of the old. - return UNSAFE_BUFFERS(span<element_type>(data(), count)); + return UNSAFE_BUFFERS(span<element_type>(unchecked, data(), count)); } // Last `count` elements. @@ -1217,14 +1309,14 @@ // SAFETY: `data()` points to at least `size()` elements, so the new data // scope is a strict subset of the old. return UNSAFE_BUFFERS( - span<element_type, Count>(data() + (size() - Count), Count)); + span<element_type, Count>(unchecked, data() + (size() - Count), Count)); } constexpr auto last(StrictNumeric<size_type> count) const { CHECK(size_type{count} <= size()); // SAFETY: `data()` points to at least `size()` elements, so the new data // scope is a strict subset of the old. - return UNSAFE_BUFFERS( - span<element_type>(data() + (size() - size_type{count}), count)); + return UNSAFE_BUFFERS(span<element_type>( + unchecked, data() + (size() - size_type{count}), count)); } // `count` elements beginning at `offset`. @@ -1237,13 +1329,14 @@ // specifies a valid element index or the past-the-end index, and // `remaining` cannot index past-the-end elements. return UNSAFE_BUFFERS( - span<element_type, Count>(data() + Offset, remaining)); + span<element_type, Count>(unchecked, data() + Offset, remaining)); } CHECK(Count <= remaining); // SAFETY: `data()` points to at least `size()` elements, so `Offset` // specifies a valid element index or the past-the-end index, and `Count` is // no larger than the number of remaining valid elements. - return UNSAFE_BUFFERS(span<element_type, Count>(data() + Offset, Count)); + return UNSAFE_BUFFERS( + span<element_type, Count>(unchecked, data() + Offset, Count)); } constexpr auto subspan(StrictNumeric<size_type> offset) const { CHECK(size_type{offset} <= size()); @@ -1252,7 +1345,7 @@ // specifies a valid element index or the past-the-end index, and // `remaining` cannot index past-the-end elements. return UNSAFE_BUFFERS( - span<element_type>(data() + size_type{offset}, remaining)); + span<element_type>(unchecked, data() + size_type{offset}, remaining)); } constexpr auto subspan(StrictNumeric<size_type> offset, StrictNumeric<size_type> count) const { @@ -1265,7 +1358,7 @@ // specifies a valid element index or the past-the-end index, and `count` is // no larger than the number of remaining valid elements. return UNSAFE_BUFFERS( - span<element_type>(data() + size_type{offset}, count)); + span<element_type>(unchecked, data() + size_type{offset}, count)); } // Splits a span a given offset, returning a pair of spans that cover the @@ -1496,6 +1589,12 @@ span(It, EndOrSize) -> span<std::remove_reference_t<std::iter_reference_t<It>>, internal::MaybeStaticExt<EndOrSize>>; +template <typename It, typename EndOrSize> + requires(std::contiguous_iterator<It>) +span(unchecked_t, It, EndOrSize) + -> span<std::remove_reference_t<std::iter_reference_t<It>>, + internal::MaybeStaticExt<EndOrSize>>; + template <typename R> requires(std::ranges::contiguous_range<R>) span(R&&) -> span<std::remove_reference_t<std::ranges::range_reference_t<R>>, @@ -1576,13 +1675,13 @@ constexpr auto span_from_ref(const T& t LIFETIME_BOUND) { // SAFETY: It's safe to read the memory at `t`'s address as long as the // provided reference is valid. - return UNSAFE_BUFFERS(span<const T, 1>(std::addressof(t), 1u)); + return UNSAFE_BUFFERS(span<const T, 1>(unchecked, std::addressof(t), 1u)); } template <typename T> constexpr auto span_from_ref(T& t LIFETIME_BOUND) { // SAFETY: It's safe to read the memory at `t`'s address as long as the // provided reference is valid. - return UNSAFE_BUFFERS(span<T, 1>(std::addressof(t), 1u)); + return UNSAFE_BUFFERS(span<T, 1>(unchecked, std::addressof(t), 1u)); } // Converts a `T&` to a `span<[const] uint8_t, sizeof(T)>`.
diff --git a/base/memory/index_pointer.h b/base/memory/index_pointer.h new file mode 100644 index 0000000..2eb51b6 --- /dev/null +++ b/base/memory/index_pointer.h
@@ -0,0 +1,52 @@ +// Copyright 2026 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_MEMORY_INDEX_POINTER_H_ +#define BASE_MEMORY_INDEX_POINTER_H_ + +namespace base::subtle { + +// An IndexPointer stores a pointer in the form of an index from a base object. +// This is intended only for use in generated code for now. +// +// See StringSlice for a similar type that is specifically for strings +// represented as slices (which needs a few more bytes than a C-style string but +// could be faster to access in some contexts). +// +// This should only be used for pointers which are: +// +// - constant +// - stored in statically-allocated objects +// - accessed rarely +// +// Storing pointers in this form avoids relocations, which saves disk space and +// allows storing data structures containing them in .rodata (which is truly a +// straight read-only mapping of clean file pages that the OS can discard +// anytime) instead of in .data.rel.ro (which has copy-on-write contents because +// the runtime linker writes into it). +// +// This is inspired by how the Linux kernel stores its kallsyms symbol table to +// avoid processing lots of relocations on boot and bloating the kernel image, +// though Linux implements it with a code generator that emits a data-only +// assembly file: +// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/scripts/kallsyms.c +// (See in particular write_src(), which emits some values as subtractions +// between two labels.) +template <typename T, const T base[]> +class IndexPointer { + public: + explicit constexpr IndexPointer(unsigned int offset) : offset_(offset) {} + // NOLINTNEXTLINE(google-explicit-constructor) + inline operator const T*() const { + // SAFETY: offset_ is always an in-bounds compile-time constant. + return UNSAFE_BUFFERS(&base[offset_]); + } + + private: + unsigned int offset_; +}; + +} // namespace base::subtle + +#endif // BASE_MEMORY_INDEX_POINTER_H_
diff --git a/base/metrics/field_trial.cc b/base/metrics/field_trial.cc index 1dd30e5..ce647938 100644 --- a/base/metrics/field_trial.cc +++ b/base/metrics/field_trial.cc
@@ -648,15 +648,13 @@ global_->create_trials_in_child_process_called_ = true; #if BUILDFLAG(USE_BLINK) - // TODO(crbug.com/41403903): Change to a CHECK. - if (cmd_line.HasSwitch(switches::kFieldTrialHandle)) { - std::string switch_value = - cmd_line.GetSwitchValueASCII(switches::kFieldTrialHandle); - SharedMemoryError result = CreateTrialsFromSwitchValue(switch_value); - SCOPED_CRASH_KEY_NUMBER("FieldTrialList", "SharedMemoryError", - static_cast<int>(result)); - CHECK_EQ(result, SharedMemoryError::kNoError); - } + std::string switch_value = + cmd_line.GetSwitchValueASCII(switches::kFieldTrialHandle); + CHECK(!switch_value.empty(), base::NotFatalUntil::M150); + SharedMemoryError result = CreateTrialsFromSwitchValue(switch_value); + SCOPED_CRASH_KEY_NUMBER("FieldTrialList", "SharedMemoryError", + static_cast<int>(result)); + CHECK_EQ(result, SharedMemoryError::kNoError); #endif // BUILDFLAG(USE_BLINK) } @@ -664,10 +662,8 @@ void FieldTrialList::ApplyFeatureOverridesInChildProcess( FeatureList* feature_list) { CHECK(global_->create_trials_in_child_process_called_); - // TODO(crbug.com/41403903): Change to a CHECK. - if (global_->field_trial_allocator_) { - feature_list->InitFromSharedMemory(global_->field_trial_allocator_.get()); - } + CHECK(global_->field_trial_allocator_, base::NotFatalUntil::M150); + feature_list->InitFromSharedMemory(global_->field_trial_allocator_.get()); } #if BUILDFLAG(USE_BLINK)
diff --git a/base/nix/xdg_util.cc b/base/nix/xdg_util.cc index e03d7f7..d08471b3 100644 --- a/base/nix/xdg_util.cc +++ b/base/nix/xdg_util.cc
@@ -312,7 +312,7 @@ std::string token) { base::LaunchOptions options; if (!token.empty()) { - options.environment[kXdgActivationTokenEnvVar] = token; + options.environment[kXdgActivationTokenEnvVar] = std::move(token); } std::move(launch_options_cb).Run(options); };
diff --git a/base/strings/string_slice.h b/base/strings/string_slice.h index 510cabc7..1b8ad1a 100644 --- a/base/strings/string_slice.h +++ b/base/strings/string_slice.h
@@ -75,6 +75,9 @@ // // While this has a small runtime cost (typically a PC-relative load), modern // CPUs are quite good at this sort of math. +// +// See also IndexPointer, which can be used as IndexPointer<char, ...> for +// C-style strings without an explicitly stored length. template <size_t N, const char (&kData)[N]> struct StringSlice { using IndexType = typename internal::IndexTypeForSize<N>::Type;
diff --git a/base/trace_event/memory_allocator_dump.cc b/base/trace_event/memory_allocator_dump.cc index d80f704..078c1e1 100644 --- a/base/trace_event/memory_allocator_dump.cc +++ b/base/trace_event/memory_allocator_dump.cc
@@ -158,11 +158,17 @@ MemoryAllocatorDump::Entry::Entry(std::string name, std::string units, uint64_t value) - : name(name), units(units), entry_type(kUint64), value_uint64(value) {} + : name(std::move(name)), + units(std::move(units)), + entry_type(kUint64), + value_uint64(value) {} MemoryAllocatorDump::Entry::Entry(std::string name, std::string units, std::string value) - : name(name), units(units), entry_type(kString), value_string(value) {} + : name(std::move(name)), + units(std::move(units)), + entry_type(kString), + value_string(std::move(value)) {} bool MemoryAllocatorDump::Entry::operator==(const Entry& rhs) const { if (!(name == rhs.name && units == rhs.units &&
diff --git a/base/trace_event/trace_config.cc b/base/trace_event/trace_config.cc index 6c09341e..cc3d1090 100644 --- a/base/trace_event/trace_config.cc +++ b/base/trace_event/trace_config.cc
@@ -543,10 +543,10 @@ continue; } enable_systrace_ = true; - const std::vector<std::string> split_systrace_events = SplitString( + std::vector<std::string> split_systrace_events = SplitString( system_events.substr(1), " ", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY); - for (const std::string& systrace_event : split_systrace_events) { - systrace_events_.insert(systrace_event); + for (std::string& systrace_event : split_systrace_events) { + systrace_events_.insert(std::move(systrace_event)); } } else if (token == kEnableArgumentFilter) { enable_argument_filter_ = true;
diff --git a/base/uuid.h b/base/uuid.h index afa15e8b..d5bc3d337 100644 --- a/base/uuid.h +++ b/base/uuid.h
@@ -20,6 +20,7 @@ #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_ROBOLECTRIC) #include "base/android/jni_string.h" +#include "base/uuid_jni/UUID_jni.h" #include "third_party/jni_zero/jni_zero.h" #endif @@ -106,22 +107,31 @@ } // namespace base #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_ROBOLECTRIC) + namespace jni_zero { -// TODO(agrieve): We map base::Uuid to String. Might be nicer to map it to -// android.util.UUID instead. template <> inline base::Uuid FromJniType<base::Uuid>( JNIEnv* env, const jni_zero::JavaRef<jobject>& obj) { - return base::Uuid::ParseLowercase(FromJniType<std::string>(env, obj)); + if (!obj) { + return base::Uuid(); + } + return base::Uuid::ParseLowercase( + FromJniType<std::string>(env, JNI_UUID::Java_UUID_toString(env, obj))); } template <> inline ScopedJavaLocalRef<jobject> ToJniType<base::Uuid>( JNIEnv* env, const base::Uuid& uuid) { - return ToJniType(env, uuid.AsLowercaseString()); + if (!uuid.is_valid()) { + return nullptr; + } + absl::uint128 value = uuid.AsInteger(); + return JNI_UUID::Java_UUID_Constructor( + env, static_cast<jlong>(absl::Uint128High64(value)), + static_cast<jlong>(absl::Uint128Low64(value))); } } // namespace jni_zero
diff --git a/build/config/chromeos/rules.gni b/build/config/chromeos/rules.gni index 3d2d6e5..f15e5ed 100644 --- a/build/config/chromeos/rules.gni +++ b/build/config/chromeos/rules.gni
@@ -536,7 +536,11 @@ "//third_party/breakpad:minidump_dump", "//third_party/breakpad:minidump_stackwalk", ] - _data = [ "//components/crash/content/tools/generate_breakpad_symbols.py" ] + _data = [ + "//components/crash/content/tools/generate_breakpad_symbols.py", + "//chromeos/tast_control_disabled_tests_public_builders.txt", + "//chromeos/tast_control_disabled_tests.txt", + ] if (is_skylab) { generate_skylab_tast_filter(target_name) {
diff --git a/build/rust/gni_impl/clippy_wrapper.py b/build/rust/gni_impl/clippy_wrapper.py index 70133ef..89f9e17 100755 --- a/build/rust/gni_impl/clippy_wrapper.py +++ b/build/rust/gni_impl/clippy_wrapper.py
@@ -11,7 +11,7 @@ import tempfile from rustc_wrapper import (ConvertPathsToAbsolute, LoadRustEnvAndFlags, - RecommendApplyFixesScript) + HandleReturnCode) def main(): @@ -41,13 +41,14 @@ rustflags += ["--emit=metadata"] r = subprocess.run([args.clippy_driver, *rustflags], env=rustenv, check=False) - if r.returncode == 0: - args.build_stamp_file.touch() - else: + if r.returncode != 0: print("NOTE: See `//docs/rust/clippy.md` for more Clippy info.", file=sys.stderr) - RecommendApplyFixesScript(args.clippy_driver, args.rustc_env_and_flags) - return r.returncode + HandleReturnCode(r, args.rustc_env_and_flags) + assert False # `HandleReturnCode` should call `sys.exit` for non-0 code. + + args.build_stamp_file.touch() + return 0 if __name__ == '__main__':
diff --git a/build/rust/gni_impl/cpp_api_from_rust_wrapper.py b/build/rust/gni_impl/cpp_api_from_rust_wrapper.py index 2001b0d..d66fd075 100755 --- a/build/rust/gni_impl/cpp_api_from_rust_wrapper.py +++ b/build/rust/gni_impl/cpp_api_from_rust_wrapper.py
@@ -10,7 +10,8 @@ import sys import tempfile -from rustc_wrapper import (ConvertPathsToAbsolute, LoadRustEnvAndFlags) +from rustc_wrapper import (ConvertPathsToAbsolute, LoadRustEnvAndFlags, + HandleReturnCode) def main(): @@ -38,7 +39,8 @@ r = subprocess.run([args.cpp_api_from_rust_exe_path, *rustflags], env=rustenv, check=False) - return r.returncode + HandleReturnCode(r) + return 0 if __name__ == '__main__':
diff --git a/build/rust/gni_impl/rustc_wrapper.py b/build/rust/gni_impl/rustc_wrapper.py index 663b4751..42869fd 100755 --- a/build/rust/gni_impl/rustc_wrapper.py +++ b/build/rust/gni_impl/rustc_wrapper.py
@@ -10,6 +10,7 @@ import subprocess import shlex import os +import signal import sys import re @@ -237,7 +238,42 @@ return rustenv, rustflags -def RecommendApplyFixesScript(tool, rustc_env_and_flags): +def HandleReturnCode(completed_process, rustc_env_and_flags=None): + """ Takes `completed_process` returned by `subprocess.run(..., check=False)` + and if `returncode` is non-zero, then prints some diagnostic info and + calls `sys.exit(...)`. This routine helps to avoid confusing signal-based + and exit-code-based failure conditions - see https://crbug.com/493357693. + + If the `returncode` is non-zero and the optional `rustc_env_and_flags` + argument is present, then `_RecommendApplyFixesScript` will be called to + suggest using a script to apply machine-applicable fixes. + """ + if completed_process.returncode == 0: + return + + process_path = completed_process.args[0] + process_name = os.path.basename(process_path) + return_code = completed_process.returncode + if return_code < 0: + signal_code = -return_code + try: + signal_name = signal.Signals(signal_code).name + except: + signal_name = "<unrecognized signal>" + print(f'ERROR: `{process_name}` was terminated by '\ + f'signal {signal_code} ({signal_name})', + file=sys.stderr) + else: + exit_code = return_code + print(f'ERROR: `{process_name}` exited with '\ + f'a non-zero exit code: {exit_code}', + file=sys.stderr) + if rustc_env_and_flags: + _RecommendApplyFixesScript(process_path, rustc_env_and_flags) + sys.exit(return_code if return_code >= 0 else 128 - return_code) + + +def _RecommendApplyFixesScript(tool, rustc_env_and_flags): source_root = os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir, os.pardir, os.pardir) rel_build_dir = os.path.relpath(os.getcwd(), source_root) @@ -343,9 +379,7 @@ print(' '.join(f'{k}={shlex.quote(v)}' for k, v in env.items()), args.rustc, shlex.join(rustc_args)) r = subprocess.run([args.rustc, *rustc_args], env=env, check=False) - if r.returncode != 0: - RecommendApplyFixesScript(args.rustc, args.dump_rustc_env_and_flags) - sys.exit(r.returncode) + HandleReturnCode(r, args.dump_rustc_env_and_flags) final_depfile_lines = [] dirty = False
diff --git a/build/toolchain/apple/toolchain.gni b/build/toolchain/apple/toolchain.gni index dd27220..eb1bdb5 100644 --- a/build/toolchain/apple/toolchain.gni +++ b/build/toolchain/apple/toolchain.gni
@@ -334,6 +334,7 @@ "{{output_dir}}/lib{{target_output_name}}{{output_extension}}" rspfile = rustc_rsp_path depfile = "$rlibname.d" + rmetaname = "{{output_dir}}/lib{{target_output_name}}.rmeta" default_output_extension = ".rlib" @@ -347,13 +348,14 @@ description = "RUST {{output}}" outputs = [ rlibname, + rmetaname, rustc_env_and_flags_path, "${rspfile}.rust", ] rspfile_content = "$rustc_common_args {{rustdeps}} {{externs}} SOURCES {{sources}}" - command = "$rustc_wrapper --depfile=$depfile --emit=dep-info=$depfile,link -o $rlibname -- -Clinker=\"$_cxx\" {{source}} LDFLAGS RUSTENV {{rustenv}}" + command = "$rustc_wrapper --depfile=$depfile --emit=dep-info=$depfile,link,metadata=$rmetaname -o $rlibname -- -Clinker=\"$_cxx\" {{source}} LDFLAGS RUSTENV {{rustenv}}" rust_sysroot = rust_sysroot_relative }
diff --git a/build/toolchain/gcc_toolchain.gni b/build/toolchain/gcc_toolchain.gni index a22678b..3c9fb9d 100644 --- a/build/toolchain/gcc_toolchain.gni +++ b/build/toolchain/gcc_toolchain.gni
@@ -711,6 +711,7 @@ "{{output_dir}}/lib{{target_output_name}}{{output_extension}}" rspfile = rustc_rsp_path depfile = "$rlibname.d" + rmetaname = "{{output_dir}}/lib{{target_output_name}}.rmeta" default_output_extension = ".rlib" @@ -723,13 +724,14 @@ description = "RUST {{output}}" outputs = [ rlibname, + rmetaname, rustc_env_and_flags_path, "${rspfile}.rust", ] rspfile_content = "$rustc_common_args {{rustdeps}} {{externs}} SOURCES {{sources}}" - command = "$rustc_wrapper --depfile=$depfile --emit=dep-info=$depfile,link -o $rlibname -- -Clinker=\"${invoker.cxx}\" {{source}} LDFLAGS RUSTENV {{rustenv}}" + command = "$rustc_wrapper --depfile=$depfile --emit=dep-info=$depfile,link,metadata=$rmetaname -o $rlibname -- -Clinker=\"${invoker.cxx}\" {{source}} LDFLAGS RUSTENV {{rustenv}}" rust_sysroot = rust_sysroot_relative }
diff --git a/build/toolchain/win/toolchain.gni b/build/toolchain/win/toolchain.gni index 8d0b8781..584b17d 100644 --- a/build/toolchain/win/toolchain.gni +++ b/build/toolchain/win/toolchain.gni
@@ -389,6 +389,7 @@ "{{output_dir}}/lib{{target_output_name}}{{output_extension}}" rspfile = rustc_rsp_path depfile = "$rlibname.d" + rmetaname = "{{output_dir}}/lib{{target_output_name}}.rmeta" default_output_extension = ".rlib" @@ -402,13 +403,14 @@ description = "RUST {{output}}" outputs = [ rlibname, + rmetaname, rustc_env_and_flags_path, "${rspfile}.rust", ] rspfile_content = "$rustc_windows_args {{rustdeps}} {{externs}} SOURCES {{sources}}" - command = "$rustc_wrapper --depfile=$depfile --emit=dep-info=$depfile,link -o $rlibname -- {{source}} LDFLAGS RUSTENV {{rustenv}}" + command = "$rustc_wrapper --depfile=$depfile --emit=dep-info=$depfile,link,metadata=$rmetaname -o $rlibname -- {{source}} LDFLAGS RUSTENV {{rustenv}}" rust_sysroot = rust_sysroot_relative }
diff --git a/cc/layers/picture_layer_impl.cc b/cc/layers/picture_layer_impl.cc index f5bcf0e..792043d 100644 --- a/cc/layers/picture_layer_impl.cc +++ b/cc/layers/picture_layer_impl.cc
@@ -362,34 +362,26 @@ } } - const float max_contents_scale = GetMaximumContentsScaleForUseInAppendQuads(); - std::optional<gfx::Rect> scaled_cull_rect = - CalculateScaledCullRect(max_contents_scale); - if (!scaled_cull_rect) { + std::optional<gfx::Rect> cull_rect_in_layer_space = + CalculateCullRectInLayerSpace(); + if (!cull_rect_in_layer_space) { return false; } - const gfx::Transform quad_to_target_transform = - GetScaledDrawTransform(max_contents_scale); - const Occlusion scaled_occlusion = - draw_properties() - .occlusion_in_content_space.GetOcclusionWithGivenDrawTransform( - quad_to_target_transform); - const gfx::Rect scaled_recorded_bounds = - gfx::ScaleToEnclosingRect(RecordedBounds(), max_contents_scale); + // The unoccluded recorded visible rect is what we might want to record. + // We compute this in layer space (unscaled) to avoid unnecessary scaling + // operations and avoid expensive GetOcclusionWithGivenDrawTransform() which + // involves matrix multiplication and inversion. + gfx::Rect recorded_visible_layer_rect = visible_layer_rect(); + recorded_visible_layer_rect.Intersect(gfx::Rect(bounds())); + recorded_visible_layer_rect.Intersect(RecordedBounds()); - gfx::Size scaled_bounds = - gfx::ScaleToCeiledSize(bounds(), max_contents_scale); - gfx::Rect scaled_visible_layer_rect = - gfx::ScaleToEnclosingRect(visible_layer_rect(), max_contents_scale); - scaled_visible_layer_rect.Intersect(gfx::Rect(scaled_bounds)); - - gfx::Rect recorded_visible_layer_rect = scaled_visible_layer_rect; - recorded_visible_layer_rect.Intersect(scaled_recorded_bounds); gfx::Rect unoccluded_recorded_visible_rect = - scaled_occlusion.GetUnoccludedContentRect(recorded_visible_layer_rect); + draw_properties().occlusion_in_content_space.GetUnoccludedContentRect( + recorded_visible_layer_rect); + if (!unoccluded_recorded_visible_rect.IsEmpty() && - !scaled_cull_rect->Contains(unoccluded_recorded_visible_rect)) { + !cull_rect_in_layer_space->Contains(unoccluded_recorded_visible_rect)) { return true; } return false; @@ -762,7 +754,7 @@ bool update_damage) { if (update_damage) { if (layer_tree_impl()->IsActiveTree()) { - damage_rect_.Union(tile->enclosing_layer_rect()); + UnionWithExistingDamage(tile->enclosing_layer_rect()); } if (tile->draw_info().NeedsRaster()) { PictureLayerTiling* tiling = @@ -798,10 +790,6 @@ } } -gfx::Rect PictureLayerImpl::GetDamageRect() const { - return damage_rect_; -} - void PictureLayerImpl::DidDraw(viz::ClientResourceProvider* resource_provider) { LayerImpl::DidDraw(resource_provider); @@ -814,8 +802,7 @@ } void PictureLayerImpl::ResetChangeTracking() { - LayerImpl::ResetChangeTracking(); - damage_rect_.SetRect(0, 0, 0, 0); + TileBasedLayerImpl<PictureLayerTiling>::ResetChangeTracking(); has_animated_image_update_rect_ = false; has_non_animated_image_update_rect_ = false; } @@ -2150,7 +2137,7 @@ if (has_animated_image_update_rect_) { reasons.Put(DamageReason::kAnimatedImage); } - if (has_non_animated_image_update_rect_ || !damage_rect_.IsEmpty()) { + if (has_non_animated_image_update_rect_ || !GetDamageRect().IsEmpty()) { reasons.Put(DamageReason::kUntracked); } return reasons;
diff --git a/cc/layers/picture_layer_impl.h b/cc/layers/picture_layer_impl.h index cb0c5c9..7eacd36 100644 --- a/cc/layers/picture_layer_impl.h +++ b/cc/layers/picture_layer_impl.h
@@ -58,7 +58,6 @@ LayerTreeImpl* tree_impl) const override; void PushPropertiesTo(LayerImpl* layer) override; void NotifyTileStateChanged(const Tile* tile, bool update_damage) override; - gfx::Rect GetDamageRect() const override; void ResetChangeTracking() override; void ResetRasterScale(); void DidBeginTracing() override; @@ -394,10 +393,6 @@ TileSizeCalculator tile_size_calculator_{this}; - // Denotes an area that is damaged and needs redraw. This is in the layer's - // space. - gfx::Rect damage_rect_; - private: class AppendQuadsCustomSharedDataImpl : public AppendQuadsCustomSharedData { public:
diff --git a/cc/layers/picture_layer_impl_unittest.cc b/cc/layers/picture_layer_impl_unittest.cc index ad816bed..a3206b1 100644 --- a/cc/layers/picture_layer_impl_unittest.cc +++ b/cc/layers/picture_layer_impl_unittest.cc
@@ -6527,6 +6527,31 @@ ->scroll_tree_mutable() .SetScrollingContentsCullRect(element_id, gfx::Rect(0, 0, 100, 100)); EXPECT_TRUE(active_layer()->ComputeCheckerboardedNeedsRecord()); + + // Case 9: target_space_transform has translation and scale. + // scaled_cull_rect DOES contain unoccluded_recorded_visible_rect. + gfx::Transform transform; + transform.Translate(10.f, 20.f); + transform.Scale(2.f, 2.f); + active_layer()->picture_layer_tiling_set()->RemoveAllTilings(); + SetupDrawPropertiesAndUpdateTiles(active_layer(), 2.f, 1.f, 1.f); + active_layer()->draw_properties().target_space_transform = transform; + + host_impl() + ->active_tree() + ->property_trees() + ->scroll_tree_mutable() + .SetScrollingContentsCullRect(element_id, gfx::Rect(layer_bounds)); + EXPECT_FALSE(active_layer()->ComputeCheckerboardedNeedsRecord()); + + // Case 10: target_space_transform has translation and scale. + // scaled_cull_rect does NOT contain unoccluded_recorded_visible_rect. + host_impl() + ->active_tree() + ->property_trees() + ->scroll_tree_mutable() + .SetScrollingContentsCullRect(element_id, gfx::Rect(0, 0, 100, 100)); + EXPECT_TRUE(active_layer()->ComputeCheckerboardedNeedsRecord()); } TEST_F(PictureLayerImplTest, @@ -6607,6 +6632,20 @@ // Scroll beyond cull_rect. active_scroll_tree.SetScrollOffset(scroll_element_id, gfx::PointF(1001, 0)); EXPECT_TRUE(active_layer()->ComputeCheckerboardedNeedsRecord()); + + // Test with target_space_transform. + gfx::Transform transform; + transform.Translate(50.f, 100.f); + transform.Scale(1.5f, 1.5f); + active_layer()->draw_properties().target_space_transform = transform; + + // visible_rect is within cull_rect. + active_scroll_tree.SetScrollOffset(scroll_element_id, gfx::PointF(0, 0)); + EXPECT_FALSE(active_layer()->ComputeCheckerboardedNeedsRecord()); + + // Scroll beyond cull_rect. + active_scroll_tree.SetScrollOffset(scroll_element_id, gfx::PointF(1001, 0)); + EXPECT_TRUE(active_layer()->ComputeCheckerboardedNeedsRecord()); } TEST_F(PictureLayerImplTest, ComputeCheckerboardedNeedsRecord_EarlyReturns) {
diff --git a/cc/layers/tile_based_layer_impl.h b/cc/layers/tile_based_layer_impl.h index 6a1acfc1..c34383a 100644 --- a/cc/layers/tile_based_layer_impl.h +++ b/cc/layers/tile_based_layer_impl.h
@@ -63,6 +63,11 @@ void AppendQuads(const AppendQuadsContext& context, viz::CompositorRenderPass* render_pass, AppendQuadsData* append_quads_data) override; + gfx::Rect GetDamageRect() const override { return damage_rect_; } + void ResetChangeTracking() override { + LayerImpl::ResetChangeTracking(); + damage_rect_.SetRect(0, 0, 0, 0); + } gfx::Rect GetEnclosingVisibleRectInTargetSpace() const override { return GetScaledEnclosingVisibleRectInTargetSpace( GetMaximumContentsScaleForUseInAppendQuads()); @@ -90,6 +95,7 @@ std::optional<SkColor4f> solid_color() const { return solid_color_; } std::optional<gfx::Rect> CalculateScaledCullRect( float max_contents_scale) const; + std::optional<gfx::Rect> CalculateCullRectInLayerSpace() const; void ClearLastAppendQuadsScales() { last_append_quads_scales_.clear(); } @@ -100,6 +106,10 @@ } } + void UnionWithExistingDamage(const gfx::Rect& rect) { + damage_rect_.Union(rect); + } + bool LastAppendQuadsScalesContains(float scale) const { return std::ranges::contains(last_append_quads_scales_, scale); } @@ -204,6 +214,10 @@ // drawn. std::vector<float> last_append_quads_scales_; + // Denotes an area that is damaged and needs redraw. This is in the layer's + // space. + gfx::Rect damage_rect_; + bool produced_tile_last_append_quads_ : 1 = true; }; @@ -531,6 +545,24 @@ } template <typename Tiling> +std::optional<gfx::Rect> +TileBasedLayerImpl<Tiling>::CalculateCullRectInLayerSpace() const { + const ScrollTree& scroll_tree = + layer_tree_impl()->property_trees()->scroll_tree(); + if (const ScrollNode* scroll_node = scroll_tree.Node(scroll_tree_index())) { + if (transform_tree_index() == scroll_node->transform_id) { + if (const gfx::Rect* cull_rect = + scroll_tree.ScrollingContentsCullRect(scroll_node->element_id)) { + return gfx::ToEnclosingRect( + // Convert into layer space. + gfx::RectF(*cull_rect) - offset_to_transform_parent()); + } + } + } + return std::nullopt; +} + +template <typename Tiling> std::unique_ptr<AppendQuadsCustomSharedData> TileBasedLayerImpl<Tiling>::WillAppendQuads(float max_contents_scale) { return nullptr;
diff --git a/cc/layers/tile_display_layer_impl.cc b/cc/layers/tile_display_layer_impl.cc index 2f3bf97a..626de3a 100644 --- a/cc/layers/tile_display_layer_impl.cc +++ b/cc/layers/tile_display_layer_impl.cc
@@ -243,21 +243,12 @@ requested_tile_size.height() / resource_size->height()); } -gfx::Rect TileDisplayLayerImpl::GetDamageRect() const { - return damage_rect_; -} - -void TileDisplayLayerImpl::ResetChangeTracking() { - LayerImpl::ResetChangeTracking(); - damage_rect_.SetRect(0, 0, 0, 0); -} - gfx::ContentColorUsage TileDisplayLayerImpl::GetContentColorUsage() const { return content_color_usage_; } void TileDisplayLayerImpl::RecordDamage(const gfx::Rect& damage_rect) { - damage_rect_.Union(damage_rect); + UnionWithExistingDamage(damage_rect); } void TileDisplayLayerImpl::DiscardResource(viz::ResourceId resource) {
diff --git a/cc/layers/tile_display_layer_impl.h b/cc/layers/tile_display_layer_impl.h index 7de7ce3..32117ae 100644 --- a/cc/layers/tile_display_layer_impl.h +++ b/cc/layers/tile_display_layer_impl.h
@@ -200,8 +200,6 @@ void GetContentsResourceId(viz::ResourceId* resource_id, gfx::Size* resource_size, gfx::SizeF* resource_uv_size) const override; - gfx::Rect GetDamageRect() const override; - void ResetChangeTracking() override; gfx::ContentColorUsage GetContentColorUsage() const override; void SetContentColorUsage(gfx::ContentColorUsage content_color_usage) { @@ -246,9 +244,6 @@ gfx::ContentColorUsage content_color_usage_ = gfx::ContentColorUsage::kSRGB; gfx::Rect recorded_bounds_; - // Denotes an area that is damaged and needs redraw. This is in the layer's - // space. - gfx::Rect damage_rect_; std::vector<std::unique_ptr<TileDisplayLayerTiling>> tilings_; // A list of tiling scale keys that the client has nominated for deletion.
diff --git a/chrome/VERSION b/chrome/VERSION index 3f5a27f..d3cd5ab 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=148 MINOR=0 -BUILD=7739 +BUILD=7740 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index ccdc488..2b677c8 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn
@@ -472,7 +472,6 @@ "//chrome/browser/safe_browsing/android:java", "//chrome/browser/safety_check/android:java", "//chrome/browser/safety_hub/android:java", - "//chrome/browser/screenshot_monitor:java", "//chrome/browser/search_engines/android:java", "//chrome/browser/segmentation_platform:client_util_java", "//chrome/browser/segmentation_platform:factory_java", @@ -540,6 +539,7 @@ "//chrome/browser/ui/android/logo:utils_java", "//chrome/browser/ui/android/management:java", "//chrome/browser/ui/android/multiwindow:java", + "//chrome/browser/ui/android/multiwindow:multi_instance_data_proto_java", "//chrome/browser/ui/android/native_page:java", "//chrome/browser/ui/android/night_mode:java", "//chrome/browser/ui/android/omnibox:java", @@ -958,7 +958,7 @@ "//chrome/browser/ui/android/hats/internal:java", "//chrome/browser/ui/android/webid/internal:java", "//chrome/browser/ui/browser_window/internal:java", - "//chrome/browser/ui/side_panel:java", + "//chrome/browser/ui/side_panel/android:java", "//chrome/browser/ui/side_panel_container/internal:java", "//chrome/browser/ui/side_ui/internal:java", "//components/android_autofill/browser:java",
diff --git a/chrome/android/chrome_java_resources.gni b/chrome/android/chrome_java_resources.gni index 5fa41f2..c2f2255 100644 --- a/chrome/android/chrome_java_resources.gni +++ b/chrome/android/chrome_java_resources.gni
@@ -259,6 +259,7 @@ "java/res/drawable/bg_circle_tab_strip_button.xml", "java/res/drawable/bg_tabstrip_tab_divider.xml", "java/res/drawable/blue_google_shield.xml", + "java/res/drawable/bolt_24dp.xml", "java/res/drawable/bookmark_empty_state_illustration.xml", "java/res/drawable/bookmark_title_bar_shadow.xml", "java/res/drawable/bookmark_touch_ripple.xml",
diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml index 2c9f5f2..5f60c1d 100644 --- a/chrome/android/java/AndroidManifest.xml +++ b/chrome/android/java/AndroidManifest.xml
@@ -97,8 +97,7 @@ <uses-permission-sdk-23 android:name="android.permission.READ_MEDIA_AUDIO"/> <!-- Needed for handling media-viewing Intents from other apps for images and video on low end - or managed devices (eg. crbug.com/40546519) and monitoring of screenshots if permission has - been previously granted (doesn't request independently) (crbug.com/40520892) --> + or managed devices (eg. crbug.com/40546519) --> <uses-permission-sdk-23 android:name="android.permission.READ_MEDIA_IMAGES"/> <uses-permission-sdk-23 android:name="android.permission.READ_MEDIA_VIDEO"/>
diff --git a/chrome/android/java/res/drawable/bolt_24dp.xml b/chrome/android/java/res/drawable/bolt_24dp.xml new file mode 100644 index 0000000..6f1534f6 --- /dev/null +++ b/chrome/android/java/res/drawable/bolt_24dp.xml
@@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +Copyright 2026 The Chromium Authors +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="960" + android:viewportHeight="960" + android:tint="@macro/default_icon_color"> + <path + android:fillColor="@android:color/white" + android:pathData="M422,728L629,480L469,480L498,253L313,520L452,520L422,728ZM320,880L360,600L160,600L520,80L600,80L560,400L800,400L400,880L320,880ZM471,490L471,490L471,490L471,490L471,490L471,490Z"/> +</vector>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java index 5a312080..4b6439c3 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -318,6 +318,8 @@ import org.chromium.chrome.browser.ui.IncognitoRestoreAppLaunchDrawBlockerFactory; import org.chromium.chrome.browser.ui.RootUiCoordinator; import org.chromium.chrome.browser.ui.appmenu.AppMenuPropertiesDelegate; +import org.chromium.chrome.browser.ui.bottombar.BottomBarConfigUtils; +import org.chromium.chrome.browser.ui.bottombar.BottomBarHostManager; import org.chromium.chrome.browser.ui.browser_window.BrowserWindowType; import org.chromium.chrome.browser.ui.default_browser_promo.DefaultBrowserPromoUtils; import org.chromium.chrome.browser.ui.desktop_windowing.AppHeaderUtils; @@ -639,6 +641,7 @@ private NextTabPolicySupplier mNextTabPolicySupplier; private HubProvider mHubProvider; + private @Nullable BottomBarHostManager mBottomBarHostManager; private Runnable mCleanUpHubOverviewColorObserver; private @Nullable SettableMonotonicObservableSupplier<TabModelStartupInfo> mTabModelStartupInfoSupplier; @@ -1122,6 +1125,7 @@ mBackPressManager, getMenuOrKeyboardActionController(), this::getSnackbarManager, + getBottomBarHostManager(), getTabModelSelectorSupplier(), () -> getToolbarManager().getOverviewModeMenuButtonCoordinator(), mEdgeToEdgeControllerSupplier, @@ -3127,7 +3131,8 @@ getEdgeToEdgeManager(), mBookmarkManagerOpenerSupplier, getXrSpaceModeObservableSupplier(), - mInactivityTrackerSupplier); + mInactivityTrackerSupplier, + getBottomBarHostManager()); } @Override @@ -5277,6 +5282,13 @@ IntentHandler.EXTRA_OPEN_NEW_INCOGNITO_WINDOW, false); } + private BottomBarHostManager getBottomBarHostManager() { + if (mBottomBarHostManager == null && BottomBarConfigUtils.isBottomBarEnabled(this)) { + mBottomBarHostManager = new BottomBarHostManager(); + } + return mBottomBarHostManager; + } + @Override protected void initializeNightModeStateProvider() { if (mIncognitoWindowNightModeStateProvider != null) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bottombar/BottomBarContainerCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/bottombar/BottomBarContainerCoordinator.java index 890af51..f09c3e7 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/bottombar/BottomBarContainerCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/bottombar/BottomBarContainerCoordinator.java
@@ -4,17 +4,22 @@ package org.chromium.chrome.browser.bottombar; +import android.content.Context; +import android.view.View; +import android.view.ViewGroup; import android.widget.FrameLayout; import androidx.annotation.ColorInt; import org.chromium.base.Callback; -import org.chromium.build.annotations.Initializer; import org.chromium.build.annotations.NullMarked; import org.chromium.build.annotations.Nullable; +import org.chromium.chrome.R; import org.chromium.chrome.browser.browser_controls.BottomControlsStacker.LayerScrollBehavior; import org.chromium.chrome.browser.toolbar.bottom.BottomControlsContentDelegate; import org.chromium.chrome.browser.toolbar.bottom.BottomControlsCoordinator.BottomControlsVisibilityController; +import org.chromium.chrome.browser.ui.bottombar.BottomBar; +import org.chromium.chrome.browser.ui.bottombar.BottomBarHostManager.Host; import org.chromium.components.browser_ui.widget.gesture.BackPressHandler; /** @@ -24,16 +29,29 @@ */ @NullMarked public class BottomBarContainerCoordinator implements BottomControlsContentDelegate { - @SuppressWarnings("unused") private final FrameLayout mBottomBarContainer; - - @SuppressWarnings("unused") private final Callback<Boolean> mRequestLayerUpdateCallback; - private BottomControlsVisibilityController mVisibilityController; + // Temporary view to act as a placeholder for the bottom bar. + private final FrameLayout mTemporaryView; - @SuppressWarnings("unused") - private Callback<Object> mOnModelTokenChange; + // Temporary bottom bar implementation to be replaced with the real bottom bar (likely + // constructed externally). + private final BottomBar mTemporaryBottomBar = + new BottomBar() { + @Override + public View getView() { + return mTemporaryView; + } + + @Override + public void setParent(@Host int host) { + // Do nothing for now. + } + }; + + private @Nullable BottomControlsVisibilityController mVisibilityController; + private @Nullable Callback<Object> mOnModelTokenChange; /** * @param bottomBarContainer The {@link FrameLayout} for the bottom bar. @@ -43,9 +61,18 @@ FrameLayout bottomBarContainer, Callback<Boolean> requestLayerUpdateCallback) { mBottomBarContainer = bottomBarContainer; mRequestLayerUpdateCallback = requestLayerUpdateCallback; + + // Create a temporary view to act as a placeholder for the bottom bar. + Context context = bottomBarContainer.getContext(); + mTemporaryView = new FrameLayout(context); + int bottomBarHeight = + context.getResources().getDimensionPixelOffset(R.dimen.bottom_controls_height); + mTemporaryView.setLayoutParams( + new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, bottomBarHeight)); + mTemporaryView.setVisibility(View.VISIBLE); + mTemporaryView.setBackgroundColor(0xFF00FF00); } - @Initializer @Override public void initializeWithNative( BottomControlsVisibilityController visibilityController, @@ -54,6 +81,9 @@ mOnModelTokenChange = onModelTokenChange; mVisibilityController.setBottomControlsVisible(true); + // TODO(crbug.com/493594829): The token change should be based on the property model of the + // bottom bar. + mOnModelTokenChange.onResult(new Object()); } @Override @@ -68,4 +98,22 @@ public @Nullable @ColorInt Integer getBackgroundColor() { return null; } + + /** Returns the bottom bar. */ + public BottomBar getBottomBar() { + return mTemporaryBottomBar; + } + + /** Attaches the provided bottom bar view to the container. */ + public void attachBottomBarView(View view) { + mBottomBarContainer.addView(view); + + if (mOnModelTokenChange != null) { + // TODO(crbug.com/493594829): The token change should be based on the property model of + // the bottom bar. + mOnModelTokenChange.onResult(new Object()); + } + + mRequestLayerUpdateCallback.onResult(true); + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bottombar/BottomBarContainerCoordinatorUnitTest.java b/chrome/android/java/src/org/chromium/chrome/browser/bottombar/BottomBarContainerCoordinatorUnitTest.java new file mode 100644 index 0000000..dc93dde --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/bottombar/BottomBarContainerCoordinatorUnitTest.java
@@ -0,0 +1,117 @@ +// Copyright 2026 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.bottombar; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import android.app.Activity; +import android.view.View; +import android.widget.FrameLayout; + +import androidx.test.ext.junit.rules.ActivityScenarioRule; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +import org.chromium.base.Callback; +import org.chromium.base.test.BaseRobolectricTestRunner; +import org.chromium.chrome.browser.browser_controls.BottomControlsStacker.LayerScrollBehavior; +import org.chromium.chrome.browser.toolbar.bottom.BottomControlsCoordinator.BottomControlsVisibilityController; +import org.chromium.chrome.browser.ui.bottombar.BottomBar; +import org.chromium.chrome.browser.ui.bottombar.BottomBarHostManager.Host; +import org.chromium.ui.base.TestActivity; + +/** Unit tests for {@link BottomBarContainerCoordinator}. */ +@RunWith(BaseRobolectricTestRunner.class) +public class BottomBarContainerCoordinatorUnitTest { + @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule(); + + @Rule + public ActivityScenarioRule<TestActivity> mActivityScenarioRule = + new ActivityScenarioRule<>(TestActivity.class); + + @Mock private Callback<Boolean> mRequestLayerUpdateCallback; + @Mock private BottomControlsVisibilityController mVisibilityController; + @Mock private Callback<Object> mOnModelTokenChange; + + private Activity mActivity; + private FrameLayout mBottomBarContainer; + private BottomBarContainerCoordinator mCoordinator; + + @Before + public void setUp() { + mActivityScenarioRule + .getScenario() + .onActivity( + (activity) -> { + mActivity = activity; + mBottomBarContainer = new FrameLayout(mActivity); + mCoordinator = + new BottomBarContainerCoordinator( + mBottomBarContainer, mRequestLayerUpdateCallback); + }); + } + + @Test + public void testInitialization() { + mCoordinator.initializeWithNative(mVisibilityController, mOnModelTokenChange); + verify(mVisibilityController).setBottomControlsVisible(true); + verify(mOnModelTokenChange).onResult(any()); + } + + @Test + public void testGetScrollBehavior() { + assertEquals(LayerScrollBehavior.DEFAULT_SCROLL_OFF, mCoordinator.getScrollBehavior()); + } + + @Test + public void testGetBackgroundColor() { + assertNull(mCoordinator.getBackgroundColor()); + } + + @Test + public void testGetBottomBar() { + BottomBar bottomBar = mCoordinator.getBottomBar(); + assertNotNull(bottomBar); + + View view = bottomBar.getView(); + assertNotNull(view); + + bottomBar.setParent(Host.HUB); // Should not crash + } + + @Test + public void testAttachBottomBarView_notInitialized() { + View childView = new View(mActivity); + mCoordinator.attachBottomBarView(childView); + assertEquals(1, mBottomBarContainer.getChildCount()); + assertEquals(childView, mBottomBarContainer.getChildAt(0)); + verify(mRequestLayerUpdateCallback).onResult(true); + verify(mOnModelTokenChange, never()).onResult(any()); + } + + @Test + public void testAttachBottomBarView_initialized() { + mCoordinator.initializeWithNative(mVisibilityController, mOnModelTokenChange); + + View childView = new View(mActivity); + mCoordinator.attachBottomBarView(childView); + assertEquals(1, mBottomBarContainer.getChildCount()); + assertEquals(childView, mBottomBarContainer.getChildAt(0)); + verify(mRequestLayerUpdateCallback).onResult(true); + verify(mOnModelTokenChange, times(2)).onResult(any()); + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java index 8ecdff0..553d351 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java
@@ -51,6 +51,7 @@ import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.supplier.NonNullObservableSupplier; import org.chromium.base.supplier.ObservableSuppliers; +import org.chromium.base.supplier.OneshotSupplier; import org.chromium.base.supplier.SettableNonNullObservableSupplier; import org.chromium.build.annotations.EnsuresNonNullIf; import org.chromium.build.annotations.NullMarked; @@ -184,6 +185,7 @@ private TabModelSelector mTabModelSelector; private @Nullable BrowserControlsManager mBrowserControlsManager; + private @Nullable OneshotSupplier<SideUiStateProvider> mSideUiStateProviderSupplier; private @Nullable SideUiStateProvider mSideUiStateProvider; @VisibleForTesting @Nullable View mAccessibilityView; private @Nullable CompositorAccessibilityProvider mNodeProvider; @@ -720,6 +722,9 @@ if (mContentView != null) { mContentView.removeOnHierarchyChangeListener(this); } + if (mSideUiStateProvider != null) { + mSideUiStateProvider.removeObserver(this); + } } /** This is called when the native library are ready. */ @@ -1491,14 +1496,20 @@ } /** - * Sets the {@link SideUiStateProvider}. Will only be called if the related feature flag is - * enabled. + * Sets the {@link OneshotSupplier} for {@link SideUiStateProvider}. Will only be called if the + * related feature flag is enabled. * - * @param sideUiStateProvider The {@link SideUiStateProvider}. + * @param sideUiStateProviderSupplier The {@link OneshotSupplier} for {@link + * SideUiStateProvider}. */ - public void setSideUiStateProvider(SideUiStateProvider sideUiStateProvider) { - mSideUiStateProvider = sideUiStateProvider; - mSideUiStateProvider.addObserver(this); + public void setSideUiStateProviderSupplier( + OneshotSupplier<SideUiStateProvider> sideUiStateProviderSupplier) { + mSideUiStateProviderSupplier = sideUiStateProviderSupplier; + mSideUiStateProviderSupplier.onAvailable( + (sideUiStateProvider) -> { + mSideUiStateProvider = sideUiStateProvider; + mSideUiStateProvider.addObserver(this); + }); } public int getTopControlsHeightPixels() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabRootUiCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabRootUiCoordinator.java index c0f7a2d..30bb1a9 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabRootUiCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabRootUiCoordinator.java
@@ -291,7 +291,8 @@ ObservableSuppliers.createNonNull(Color.TRANSPARENT), edgeToEdgeManager, /* xrSpaceModeObservableSupplier= */ ObservableSuppliers.alwaysFalse(), - desktopWindowStateManager); + desktopWindowStateManager, + /* bottomBarHostManager= */ null); mCustomTabProvider = customTabProvider; mToolbarCoordinator = customTabToolbarCoordinator; mIntentDataProvider = intentDataProvider;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/hub/HubProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/hub/HubProvider.java index 8e3240e6..34c385c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/hub/HubProvider.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/hub/HubProvider.java
@@ -23,6 +23,7 @@ import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.toolbar.menu_button.MenuButtonCoordinator; +import org.chromium.chrome.browser.ui.bottombar.BottomBarHostManager; import org.chromium.chrome.browser.ui.edge_to_edge.EdgeToEdgeController; import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager; import org.chromium.chrome.browser.ui.searchactivityutils.SearchActivityClient; @@ -69,6 +70,7 @@ BackPressManager backPressManager, MenuOrKeyboardActionController menuOrKeyboardActionController, Supplier<SnackbarManager> snackbarManagerSupplier, + @Nullable BottomBarHostManager bottomBarHostManager, Supplier<TabModelSelector> tabModelSelectorSupplier, Supplier<MenuButtonCoordinator> menuButtonCoordinatorSupplier, MonotonicObservableSupplier<EdgeToEdgeController> edgeToEdgeSupplier, @@ -95,6 +97,7 @@ backPressManager, menuOrKeyboardActionController, snackbarManager, + bottomBarHostManager, tabSupplier, menuButtonCoordinatorSupplier.get(), mHubShowPaneHelper,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/hub/HubProviderUnitTest.java b/chrome/android/java/src/org/chromium/chrome/browser/hub/HubProviderUnitTest.java index 9a8eb90..62f0aaf 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/hub/HubProviderUnitTest.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/hub/HubProviderUnitTest.java
@@ -45,6 +45,7 @@ import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.toolbar.menu_button.MenuButtonCoordinator; import org.chromium.chrome.browser.ui.actions.DisplayButtonData; +import org.chromium.chrome.browser.ui.bottombar.BottomBarHostManager; import org.chromium.chrome.browser.ui.edge_to_edge.EdgeToEdgeController; import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager; import org.chromium.chrome.browser.ui.searchactivityutils.SearchActivityClient; @@ -83,6 +84,7 @@ @Mock private BackPressManager mBackPressManagerMock; @Mock private MenuOrKeyboardActionController mMenuOrKeyboardActionController; @Mock private SnackbarManager mSnackbarManager; + @Mock private BottomBarHostManager mBottomBarHostManager; @Mock private MenuButtonCoordinator mMenuButtonCoordinator; @Mock private SearchActivityClient mSearchActivityClient; @@ -123,6 +125,7 @@ mBackPressManagerMock, mMenuOrKeyboardActionController, () -> mSnackbarManager, + mBottomBarHostManager, () -> mTabModelSelector, () -> mMenuButtonCoordinator, mEdgeToEdgeSupplier,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/ChromeMultiInstancePersistentStore.java b/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/ChromeMultiInstancePersistentStore.java index 7eacbb8..249312dc 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/ChromeMultiInstancePersistentStore.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/ChromeMultiInstancePersistentStore.java
@@ -4,13 +4,18 @@ package org.chromium.chrome.browser.multiwindow; +import static org.chromium.build.NullUtil.assumeNonNull; + import org.chromium.base.TimeUtils; +import org.chromium.base.shared_preferences.SharedPreferencesManager; import org.chromium.build.annotations.NullMarked; import org.chromium.build.annotations.Nullable; import org.chromium.chrome.browser.incognito.IncognitoUtils; +import org.chromium.chrome.browser.multiwindow.MultiInstanceDataProto.InstanceData; import org.chromium.chrome.browser.preferences.MultiInstancePreferenceKeys; import org.chromium.chrome.browser.tabmodel.SupportedProfileType; +import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -31,20 +36,23 @@ // continue to persist across activity kills / restarts. The taskMap can be cleared when an // activity is destroyed and during invalid instance data cleanup which is why we will not // use the same to extract ids. - Map<String, Long> lastAccessedTimeMap = - getManager() - .readLongsWithPrefix( - MultiInstancePreferenceKeys.MULTI_INSTANCE_LAST_ACCESSED_TIME); - Pattern pattern = Pattern.compile("(\\d+)$"); - - Set<Integer> ids = new HashSet<>(); - - for (String prefKey : lastAccessedTimeMap.keySet()) { - Matcher matcher = pattern.matcher(prefKey); - boolean matchFound = matcher.find(); - assert matchFound : "Key should be suffixed with the instance id."; - int id = Integer.parseInt(matcher.group(1)); - ids.add(id); + Set<Integer> ids; + if (sData != null) { + ids = sData.getInstancesMap().keySet(); + } else { + Map<String, Long> lastAccessedTimeMap = + getManager() + .readLongsWithPrefix( + MultiInstancePreferenceKeys.MULTI_INSTANCE_LAST_ACCESSED_TIME); + Pattern pattern = Pattern.compile("(\\d+)$"); + ids = new HashSet<>(); + for (String prefKey : lastAccessedTimeMap.keySet()) { + Matcher matcher = pattern.matcher(prefKey); + boolean matchFound = matcher.find(); + assert matchFound : "Key should be suffixed with the instance id."; + int id = Integer.parseInt(matcher.group(1)); + ids.add(id); + } } return ids; @@ -55,96 +63,222 @@ } static void deleteInstanceState(int instanceId) { - removeActiveTabUrl(instanceId); - removeActiveTabTitle(instanceId); - removeCustomTitle(instanceId); - removeTabCount(instanceId); - removeIncognitoSelected(instanceId); - removeLastAccessedTime(instanceId); - removeClosureTime(instanceId); - removeProfileType(instanceId); - removeLatestPersistentStateId(instanceId); - removeMarkedForDeletion(instanceId); + if (sData != null) { + sData = sData.toBuilder().removeInstances(instanceId).build(); + saveProto(); + } else { + SharedPreferencesManager manager = getManager(); + manager.removeKey(lastAccessedTimeKey(instanceId)); + manager.removeKey(closureTimeKey(instanceId)); + manager.removeKey(taskIdKey(instanceId)); + manager.removeKey(normalTabCountKey(instanceId)); + manager.removeKey(incognitoTabCountKey(instanceId)); + manager.removeKey(tabCountForRelaunchKey(instanceId)); + manager.removeKey(urlKey(instanceId)); + manager.removeKey(activeTabTitleKey(instanceId)); + manager.removeKey(customTitleKey(instanceId)); + manager.removeKey(profileTypeKey(instanceId)); + manager.removeKey(latestPersistentStateIdKey(instanceId)); + manager.removeKey(incognitoSelectedKey(instanceId)); + manager.removeKey(markedForDeletionKey(instanceId)); + } } static long readLastAccessedTime(int instanceId) { + if (sData != null) { + InstanceData instance = sData.getInstancesMap().get(instanceId); + return instance != null ? instance.getLastAccessedTime() : 0; + } return getManager().readLong(lastAccessedTimeKey(instanceId)); } static void writeLastAccessedTime(int instanceId) { - getManager().writeLong(lastAccessedTimeKey(instanceId), TimeUtils.currentTimeMillis()); + long time = TimeUtils.currentTimeMillis(); + if (sData != null) { + putInstance(instanceId, getInstanceFromProto(instanceId).setLastAccessedTime(time)); + } else { + getManager().writeLong(lastAccessedTimeKey(instanceId), time); + } } static long readClosureTime(int instanceId) { + if (sData != null) { + InstanceData instance = sData.getInstancesMap().get(instanceId); + return instance != null ? instance.getClosureTime() : 0; + } return getManager().readLong(closureTimeKey(instanceId)); } static void writeClosureTime(int instanceId) { - getManager().writeLong(closureTimeKey(instanceId), TimeUtils.currentTimeMillis()); + long time = TimeUtils.currentTimeMillis(); + if (sData != null) { + putInstance(instanceId, getInstanceFromProto(instanceId).setClosureTime(time)); + } else { + getManager().writeLong(closureTimeKey(instanceId), time); + } } - static Map<String, Integer> readTaskMap() { - return getManager().readIntsWithPrefix(MultiInstancePreferenceKeys.MULTI_INSTANCE_TASK_MAP); + static Map<Integer, Integer> readTaskMap() { + Map<Integer, Integer> taskMap = new HashMap<>(); + if (sData != null) { + for (Map.Entry<Integer, InstanceData> entry : sData.getInstancesMap().entrySet()) { + if (entry.getValue().hasTaskId()) { + taskMap.put(entry.getKey(), entry.getValue().getTaskId()); + } + } + } else { + Map<String, Integer> taskIdMap = + getManager() + .readIntsWithPrefix( + MultiInstancePreferenceKeys.MULTI_INSTANCE_TASK_MAP); + Pattern pattern = Pattern.compile("(\\d+)$"); + for (Map.Entry<String, Integer> entry : taskIdMap.entrySet()) { + Matcher matcher = pattern.matcher(entry.getKey()); + if (matcher.find()) { + int id = Integer.parseInt(matcher.group(1)); + taskMap.put(id, entry.getValue()); + } + } + } + return taskMap; } static int readTaskId(int instanceId) { + if (sData != null) { + InstanceData instance = sData.getInstancesMap().get(instanceId); + return (instance != null && instance.hasTaskId()) + ? instance.getTaskId() + : MultiInstanceManager.INVALID_TASK_ID; + } return getManager().readInt(taskIdKey(instanceId), MultiInstanceManager.INVALID_TASK_ID); } static void writeTaskId(int instanceId, int taskId) { - getManager().writeInt(taskIdKey(instanceId), taskId); + if (sData != null) { + putInstance(instanceId, getInstanceFromProto(instanceId).setTaskId(taskId)); + } else { + getManager().writeInt(taskIdKey(instanceId), taskId); + } } static void removeTaskId(int instanceId) { - getManager().removeKey(taskIdKey(instanceId)); + if (sData != null) { + InstanceData instance = sData.getInstancesMap().get(instanceId); + if (instance != null) { + putInstance(instanceId, instance.toBuilder().clearTaskId()); + } + } else { + getManager().removeKey(taskIdKey(instanceId)); + } } static int readNormalTabCount(int instanceId) { + if (sData != null) { + InstanceData instance = sData.getInstancesMap().get(instanceId); + return instance != null ? instance.getNormalTabCount() : 0; + } return getManager().readInt(normalTabCountKey(instanceId)); } static int readIncognitoTabCount(int instanceId) { + if (sData != null) { + InstanceData instance = sData.getInstancesMap().get(instanceId); + return instance != null ? instance.getIncognitoTabCount() : 0; + } return getManager().readInt(incognitoTabCountKey(instanceId)); } static void writeTabCount(int instanceId, int normalTabCount, int incognitoTabCount) { - getManager().writeInt(normalTabCountKey(instanceId), normalTabCount); - getManager().writeInt(incognitoTabCountKey(instanceId), incognitoTabCount); + if (sData != null) { + putInstance( + instanceId, + getInstanceFromProto(instanceId) + .setNormalTabCount(normalTabCount) + .setIncognitoTabCount(incognitoTabCount)); + } else { + getManager().writeInt(normalTabCountKey(instanceId), normalTabCount); + getManager().writeInt(incognitoTabCountKey(instanceId), incognitoTabCount); + } } static int readTabCountForRelaunch(int instanceId) { + if (sData != null) { + InstanceData instance = sData.getInstancesMap().get(instanceId); + return instance != null ? instance.getTabCountForRelaunch() : 0; + } return getManager().readInt(tabCountForRelaunchKey(instanceId)); } static void writeTabCountForRelaunchSync(int instanceId, int tabCount) { - getManager().writeIntSync(tabCountForRelaunchKey(instanceId), tabCount); + if (sData != null) { + putInstance( + instanceId, getInstanceFromProto(instanceId).setTabCountForRelaunch(tabCount)); + } else { + getManager().writeIntSync(tabCountForRelaunchKey(instanceId), tabCount); + } } static @Nullable String readActiveTabUrl(int instanceId) { + if (sData != null) { + InstanceData instance = sData.getInstancesMap().get(instanceId); + return instance != null ? instance.getUrl() : null; + } return getManager().readString(urlKey(instanceId), null); } static void writeActiveTabUrl(int instanceId, String url) { - getManager().writeString(urlKey(instanceId), url); + if (sData != null) { + putInstance(instanceId, getInstanceFromProto(instanceId).setUrl(url)); + } else { + getManager().writeString(urlKey(instanceId), url); + } } static @Nullable String readActiveTabTitle(int instanceId) { + if (sData != null) { + InstanceData instance = sData.getInstancesMap().get(instanceId); + return instance != null ? instance.getActiveTabTitle() : null; + } return getManager().readString(activeTabTitleKey(instanceId), null); } static void writeActiveTabTitle(int instanceId, String title) { - getManager().writeString(activeTabTitleKey(instanceId), title); + if (sData != null) { + putInstance(instanceId, getInstanceFromProto(instanceId).setActiveTabTitle(title)); + } else { + getManager().writeString(activeTabTitleKey(instanceId), title); + } } static @Nullable String readCustomTitle(int instanceId) { + if (sData != null) { + InstanceData instance = sData.getInstancesMap().get(instanceId); + return (instance != null && instance.hasCustomTitle()) + ? instance.getCustomTitle() + : null; + } return getManager().readString(customTitleKey(instanceId), null); } - static void writeCustomTitle(int instanceId, String title) { - getManager().writeString(customTitleKey(instanceId), title); + static void writeCustomTitle(int instanceId, @Nullable String title) { + if (sData != null) { + InstanceData.Builder builder = getInstanceFromProto(instanceId); + if (title == null) { + builder.clearCustomTitle(); + } else { + builder.setCustomTitle(title); + } + putInstance(instanceId, builder); + } else { + getManager().writeString(customTitleKey(instanceId), title); + } } static @SupportedProfileType int readProfileType(int instanceId) { + if (sData != null) { + InstanceData instance = sData.getInstancesMap().get(instanceId); + return instance != null ? instance.getProfileType() : SupportedProfileType.UNSET; + } return getManager().readInt(profileTypeKey(instanceId), SupportedProfileType.UNSET); } @@ -154,78 +288,77 @@ if (IncognitoUtils.shouldOpenIncognitoAsWindow() && (profileType == SupportedProfileType.REGULAR || profileType == SupportedProfileType.OFF_THE_RECORD)) { - getManager().writeInt(profileTypeKey(instanceId), profileType); + if (sData != null) { + putInstance( + instanceId, getInstanceFromProto(instanceId).setProfileType(profileType)); + } else { + getManager().writeInt(profileTypeKey(instanceId), profileType); + } } } static boolean containsLatestPersistentStateId(int instanceId) { + if (sData != null) { + InstanceData instance = sData.getInstancesMap().get(instanceId); + return instance != null && instance.hasLatestPersistentStateId(); + } return getManager().contains(latestPersistentStateIdKey(instanceId)); } static int readLatestPersistentStateId(int instanceId) { + if (sData != null) { + InstanceData instance = sData.getInstancesMap().get(instanceId); + return instance != null ? instance.getLatestPersistentStateId() : 0; + } return getManager().readInt(latestPersistentStateIdKey(instanceId)); } static void writeLatestPersistentStateId(int instanceId, int latestPersistentStateHash) { - getManager().writeInt(latestPersistentStateIdKey(instanceId), latestPersistentStateHash); + if (sData != null) { + putInstance( + instanceId, + getInstanceFromProto(instanceId) + .setLatestPersistentStateId(latestPersistentStateHash)); + } else { + getManager() + .writeInt(latestPersistentStateIdKey(instanceId), latestPersistentStateHash); + } } static boolean readIncognitoSelected(int instanceId) { + if (sData != null) { + InstanceData instance = sData.getInstancesMap().get(instanceId); + return instance != null ? instance.getIncognitoSelected() : false; + } return getManager().readBoolean(incognitoSelectedKey(instanceId), false); } static void writeIncognitoSelected(int instanceId, boolean incognitoSelected) { - getManager().writeBoolean(incognitoSelectedKey(instanceId), incognitoSelected); + if (sData != null) { + putInstance( + instanceId, + getInstanceFromProto(instanceId).setIncognitoSelected(incognitoSelected)); + } else { + getManager().writeBoolean(incognitoSelectedKey(instanceId), incognitoSelected); + } } static boolean readMarkedForDeletion(int instanceId) { + if (sData != null) { + InstanceData instance = sData.getInstancesMap().get(instanceId); + return instance != null ? instance.getMarkedForDeletion() : false; + } return getManager().readBoolean(markedForDeletionKey(instanceId), false); } static void writeMarkedForDeletion(int instanceId, boolean markedForDeletion) { - getManager().writeBoolean(markedForDeletionKey(instanceId), markedForDeletion); - } - - private static void removeLastAccessedTime(int instanceId) { - getManager().removeKey(lastAccessedTimeKey(instanceId)); - } - - private static void removeClosureTime(int instanceId) { - getManager().removeKey(closureTimeKey(instanceId)); - } - - private static void removeTabCount(int instanceId) { - getManager().removeKey(normalTabCountKey(instanceId)); - getManager().removeKey(incognitoTabCountKey(instanceId)); - getManager().removeKey(tabCountForRelaunchKey(instanceId)); - } - - private static void removeActiveTabUrl(int instanceId) { - getManager().removeKey(urlKey(instanceId)); - } - - private static void removeActiveTabTitle(int instanceId) { - getManager().removeKey(activeTabTitleKey(instanceId)); - } - - private static void removeCustomTitle(int instanceId) { - getManager().removeKey(customTitleKey(instanceId)); - } - - private static void removeProfileType(int instanceId) { - getManager().removeKey(profileTypeKey(instanceId)); - } - - private static void removeLatestPersistentStateId(int instanceId) { - getManager().removeKey(latestPersistentStateIdKey(instanceId)); - } - - private static void removeIncognitoSelected(int instanceId) { - getManager().removeKey(incognitoSelectedKey(instanceId)); - } - - private static void removeMarkedForDeletion(int instanceId) { - getManager().removeKey(markedForDeletionKey(instanceId)); + if (sData != null) { + putInstance( + instanceId, + getInstanceFromProto(instanceId).setMarkedForDeletion(markedForDeletion)); + } else { + getManager().writeBoolean(markedForDeletionKey(instanceId), markedForDeletion); + } } private static String lastAccessedTimeKey(int instanceId) { @@ -291,4 +424,17 @@ return MultiInstancePreferenceKeys.MULTI_INSTANCE_MARKED_FOR_DELETION.createKey( String.valueOf(instanceId)); } + + private static void putInstance(int instanceId, InstanceData.Builder builder) { + if (sData == null) return; + sData = sData.toBuilder().putInstances(instanceId, builder.build()).build(); + saveProto(); + } + + private static InstanceData.Builder getInstanceFromProto(int instanceId) { + assumeNonNull(sData); + return sData + .getInstancesOrDefault(instanceId, InstanceData.getDefaultInstance()) + .toBuilder(); + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31.java b/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31.java index a892f9a..f9a86cd 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31.java
@@ -894,12 +894,13 @@ private void removeInvalidInstanceData() { // Update persisted task state based on current AppTasks. Set<Integer> appTaskIds = MultiWindowUtils.getAllAppTaskIds(mActivity); - Map<String, Integer> taskMap = ChromeMultiInstancePersistentStore.readTaskMap(); + + Map<Integer, Integer> taskMap = ChromeMultiInstancePersistentStore.readTaskMap(); List<String> tasksRemoved = new ArrayList<>(); - for (Map.Entry<String, Integer> entry : taskMap.entrySet()) { + for (Map.Entry<Integer, Integer> entry : taskMap.entrySet()) { if (!appTaskIds.contains(entry.getValue())) { - tasksRemoved.add(entry.getKey() + " - " + entry.getValue()); - ChromeMultiInstancePersistentStore.getManager().removeKey(entry.getKey()); + tasksRemoved.add("instanceId: " + entry.getKey() + " taskId: " + entry.getValue()); + ChromeMultiInstancePersistentStore.removeTaskId(entry.getKey()); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/synced_set_up/CrossDeviceSettingImporter.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/synced_set_up/CrossDeviceSettingImporter.java index 78a5ec8f..ab3abbd 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/sync/synced_set_up/CrossDeviceSettingImporter.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/synced_set_up/CrossDeviceSettingImporter.java
@@ -4,7 +4,6 @@ package org.chromium.chrome.browser.sync.synced_set_up; -import static org.chromium.build.NullUtil.assumeNonNull; import static org.chromium.chrome.browser.flags.ChromeFeatureList.XPLAT_SYNCED_SETUP; import static org.chromium.chrome.browser.ntp_customization.ntp_cards.NtpCardsMediator.MODULE_TYPE_TO_USER_PREFS_KEY; import static org.chromium.chrome.browser.sync.synced_set_up.SyncedSetUpUtilsBridge.getCrossDevicePrefsFromRemoteDevice; @@ -194,11 +193,20 @@ // If the cross-device pref tracker is still not ready, keep listening // for a future status change. if (NOT_READY_YET_STATES.contains(status)) return; + + // Ensure the tab and profile are up-to-date, and still non-null. + @Nullable Tab tabAfterStatusChange = mActivityTabSupplier.get(); + if (tabAfterStatusChange == null) return; + + @Nullable Profile profileAfterStatusChange = + tabAfterStatusChange.getProfile(); + if (!profile.equals(profileAfterStatusChange)) return; + onCrossDevicePrefTrackerReady( crossDevicePrefTracker, status, - profile, - currentTab, + profileAfterStatusChange, + tabAfterStatusChange, /* availableImmediately= */ false); } }); @@ -251,12 +259,14 @@ // If there was no delay, apply the settings immediately (skipping the user straight // to the undo prompt). applyAndNotifySettingImport( - getPrefsFromRemoteDevice(tracker, profile), + profile, + getPrefsFromRemoteDevice(profile, tracker), /* onlyOmniboxPosition= */ onlyOmniboxPosition); } else { // If there was a delay, ask the user whether they want to apply the settings. askToApplyNtpSettingImportIfNeeded( - getPrefsFromRemoteDevice(tracker, profile), + profile, + getPrefsFromRemoteDevice(profile, tracker), /* onlyOmniboxPosition= */ onlyOmniboxPosition); } } else { @@ -323,6 +333,7 @@ /** * Shows a snackbar asking the user if they want to import NTP settings from another device. * + * @param profile The {@link Profile}. * @param preferencesToApply The preferences that will be applied. * @param onlyOmniboxPosition Whether only the omnibox position should be considered. If true, * we only check the omnibox position to determine whether to show the snackbar, and when we @@ -332,8 +343,8 @@ */ @VisibleForTesting void askToApplyNtpSettingImportIfNeeded( - Map<String, Object> preferencesToApply, boolean onlyOmniboxPosition) { - if (shouldShowSnackbar(preferencesToApply, onlyOmniboxPosition)) { + Profile profile, Map<String, Object> preferencesToApply, boolean onlyOmniboxPosition) { + if (shouldShowSnackbar(profile, preferencesToApply, onlyOmniboxPosition)) { Snackbar offerApplySnackbar = Snackbar.make( mContext.getString(R.string.synced_set_up_snackbar_ask_to_apply), @@ -342,7 +353,7 @@ public void onAction(@Nullable Object actionData) { recordAction(onlyOmniboxPosition, "Apply"); applyAndNotifySettingImport( - preferencesToApply, onlyOmniboxPosition); + profile, preferencesToApply, onlyOmniboxPosition); } }, TYPE_ACTION, @@ -361,14 +372,15 @@ * Applies settings from another device and shows a snackbar to the user, informing them that * their settings were applied and offering an undo button. * + * @param profile The {@link Profile}. * @param preferencesToApply The preferences that will be applied. * @param onlyOmniboxPosition Whether only the omnibox position should be considered (see * askToApplyNtpSettingImportIfNeeded documentation above). */ private void applyAndNotifySettingImport( - Map<String, Object> preferencesToApply, boolean onlyOmniboxPosition) { - if (shouldShowSnackbar(preferencesToApply, onlyOmniboxPosition)) { - Map<String, Object> currentPreferences = getCurrentSettings(); + Profile profile, Map<String, Object> preferencesToApply, boolean onlyOmniboxPosition) { + if (shouldShowSnackbar(profile, preferencesToApply, onlyOmniboxPosition)) { + Map<String, Object> currentPreferences = getCurrentSettings(profile); Snackbar offerUndoSnackbar = Snackbar.make( mContext.getString( @@ -379,11 +391,12 @@ if (onlyOmniboxPosition) { applyLocalStateSettings(currentPreferences); } else { - applySettings(currentPreferences); + applySettings(profile, currentPreferences); } recordAction(onlyOmniboxPosition, "Undo"); - askToRedoSettingImport(preferencesToApply, onlyOmniboxPosition); + askToRedoSettingImport( + profile, preferencesToApply, onlyOmniboxPosition); } }, Snackbar.TYPE_ACTION, @@ -392,7 +405,7 @@ /* actionText= */ mContext.getString(R.string.undo), /* actionData= */ Map.of()); showSnackbarAfterDialogs(offerUndoSnackbar, onlyOmniboxPosition); - applySettings(preferencesToApply); + applySettings(profile, preferencesToApply); } else { markCrossDeviceSettingImportComplete( onlyOmniboxPosition, CrossDeviceSettingImportOutcome.NO_SETTINGS_TO_IMPORT); @@ -403,12 +416,13 @@ * Shows a snackbar asking the user if they want to redo their NTP setting import (this is * offered after the user hits undo). * + * @param profile The {@link Profile}. * @param preferencesToApply The preferences that will be applied during the redo. * @param onlyOmniboxPosition Whether only the omnibox position should be considered (see * askToApplyNtpSettingImportIfNeeded documentation above). */ private void askToRedoSettingImport( - Map<String, Object> preferencesToApply, boolean onlyOmniboxPosition) { + Profile profile, Map<String, Object> preferencesToApply, boolean onlyOmniboxPosition) { Snackbar offerRedoSnackbar = Snackbar.make( mContext.getString(R.string.synced_set_up_snackbar_removed_confirmation), @@ -417,7 +431,7 @@ public void onAction(@Nullable Object actionData) { recordAction(onlyOmniboxPosition, "Redo"); applyAndNotifySettingImport( - preferencesToApply, onlyOmniboxPosition); + profile, preferencesToApply, onlyOmniboxPosition); } }, TYPE_ACTION, @@ -428,7 +442,7 @@ } /** Returns the user's current settings. */ - private Map<String, Object> getCurrentSettings() { + private Map<String, Object> getCurrentSettings(Profile profile) { Map<String, Object> result = new HashMap<>(); PrefService localStatePrefs = LocalStatePrefs.get(); @@ -437,8 +451,6 @@ result.put(omniboxPositionPref, localStatePrefs.getBoolean(omniboxPositionPref)); } - // Assumes mTab.getProfile() is non-null and UserPrefs.areNativePrefsLoaded is true. - Profile profile = assumeNonNull(mActivityTabSupplier.get()).getProfile(); PrefService userPrefs = UserPrefs.get(profile); if (userPrefs != null) { String allCardsPref = Pref.MAGIC_STACK_HOME_MODULE_ENABLED; @@ -452,12 +464,14 @@ } /** + * @param profile The {@link Profile}. * @param preferences The preferences to check. * @return whether the user's current settings are different from {@param preferences}. */ - private boolean importedSettingsHavePreferenceChange(Map<String, Object> preferences) { - // Assumes mTab.getProfile() is non-null and UserPrefs.areNativePrefsLoaded is true. - Profile profile = assumeNonNull(mActivityTabSupplier.get()).getProfile(); + private boolean importedSettingsHavePreferenceChange( + Profile profile, Map<String, Object> preferences) { + if (!UserPrefs.areNativePrefsLoaded(profile)) return false; + PrefService userPrefs = UserPrefs.get(profile); if (userPrefs == null) { return false; @@ -479,16 +493,17 @@ } /** + * @param profile The {@link Profile}. * @param preferences The preferences to compare with local. * @param onlyOmniboxPosition Whether only the omnibox position should be considered (see * askToApplyNtpSettingImportIfNeeded documentation above). * @return Whether the undo/redo snackbar should be shown. */ private boolean shouldShowSnackbar( - Map<String, Object> preferences, boolean onlyOmniboxPosition) { + Profile profile, Map<String, Object> preferences, boolean onlyOmniboxPosition) { return onlyOmniboxPosition ? importedSettingsHaveOmniboxChange(preferences) - : importedSettingsHavePreferenceChange(preferences); + : importedSettingsHavePreferenceChange(profile, preferences); } /** @@ -543,21 +558,21 @@ /** * Applies the given {@param preferencesToApply}. * + * @param profile The {@link Profile}. * @param preferencesToApply The preferences to apply. */ - private void applySettings(Map<String, Object> preferencesToApply) { - applyUserPrefSettings(preferencesToApply); + private void applySettings(Profile profile, Map<String, Object> preferencesToApply) { + applyUserPrefSettings(profile, preferencesToApply); applyLocalStateSettings(preferencesToApply); } /** * Applies the user pref settings from {@param preferencesToApply}. * + * @param profile The {@link Profile}. * @param preferencesToApply The preferences to apply. */ - private void applyUserPrefSettings(Map<String, Object> preferencesToApply) { - // Assumes mTab.getProfile() is non-null and UserPrefs.areNativePrefsLoaded is true. - Profile profile = assumeNonNull(mActivityTabSupplier.get()).getProfile(); + private void applyUserPrefSettings(Profile profile, Map<String, Object> preferencesToApply) { PrefService userPrefs = UserPrefs.get(profile); if (userPrefs == null) return; @@ -612,12 +627,12 @@ /** * Get a map of prefs to values, stripped of the "cross_device." prefix. * - * @param tracker The {@link CrossDevicePrefTracker}. * @param profile The {@link Profile}. + * @param tracker The {@link CrossDevicePrefTracker}. * @return The map of prefs to values. */ @VisibleForTesting - Map<String, Object> getPrefsFromRemoteDevice(CrossDevicePrefTracker tracker, Profile profile) { + Map<String, Object> getPrefsFromRemoteDevice(Profile profile, CrossDevicePrefTracker tracker) { Map<String, Object> crossDevicePrefs = getCrossDevicePrefsFromRemoteDevice(tracker, profile); Map<String, Object> res = new HashMap<>(); @@ -633,7 +648,7 @@ return res; } - /** Logs UMA with suffix {@param suffix} (omnibox-psecific if {@param onlyOmniboxPosition}) */ + /** Logs UMA with suffix {@param suffix} (omnibox-specific if {@param onlyOmniboxPosition}) */ private void recordAction(boolean onlyOmniboxPosition, String suffix) { StringBuilder action = new StringBuilder("Android.CrossDeviceSettingImport"); if (onlyOmniboxPosition) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java index 1ce0db6..d72d201 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java
@@ -200,6 +200,7 @@ import org.chromium.chrome.browser.ui.RootUiCoordinator; import org.chromium.chrome.browser.ui.appmenu.AppMenuBlocker; import org.chromium.chrome.browser.ui.appmenu.AppMenuDelegate; +import org.chromium.chrome.browser.ui.bottombar.BottomBarHostManager; import org.chromium.chrome.browser.ui.default_browser_promo.DefaultBrowserPromoUtils; import org.chromium.chrome.browser.ui.desktop_windowing.AppHeaderCoordinator; import org.chromium.chrome.browser.ui.desktop_windowing.AppHeaderUtils; @@ -214,6 +215,7 @@ import org.chromium.chrome.browser.ui.side_panel_container.dev.SidePanelDevFeatureFactory; import org.chromium.chrome.browser.ui.side_ui.SideUiCoordinator; import org.chromium.chrome.browser.ui.side_ui.SideUiCoordinatorFactory; +import org.chromium.chrome.browser.ui.side_ui.SideUiStateProvider; import org.chromium.chrome.browser.ui.signin.FullscreenSigninPromoLauncher; import org.chromium.chrome.browser.ui.system.StatusBarColorController.StatusBarColorProvider; import org.chromium.chrome.browser.webapps.PwaRestorePromoUtils; @@ -329,6 +331,8 @@ private @Nullable SidePanelDevFeature mSidePanelDevFeature; private final OneshotSupplierImpl<Boolean> mTrackerInitializedOneshotSupplier = new OneshotSupplierImpl<>(); + private final OneshotSupplierImpl<SideUiStateProvider> mSideUiStateProviderSupplier = + new OneshotSupplierImpl<>(); private ContextualTasksBridge mContextualTasksBridge; private @Nullable ActorOverlayCoordinator mActorOverlayCoordinator; private @Nullable ActorControlCoordinator mActorControlCoordinator; @@ -491,7 +495,8 @@ EdgeToEdgeManager edgeToEdgeManager, MonotonicObservableSupplier<BookmarkManagerOpener> bookmarkManagerOpenerSupplier, NonNullObservableSupplier<Boolean> xrSpaceModeObservableSupplier, - OneshotSupplier<ChromeInactivityTracker> inactivityTrackerSupplier) { + OneshotSupplier<ChromeInactivityTracker> inactivityTrackerSupplier, + @Nullable BottomBarHostManager bottomBarHostManager) { super( activity, onOmniboxFocusChangedListener, @@ -545,7 +550,8 @@ browserControlsManager, insetObserver, activityLifecycleDispatcher, - multiInstanceManager)); + multiInstanceManager), + bottomBarHostManager); mInsetObserver = insetObserver; mBackButtonShouldCloseTabFn = backButtonShouldCloseTabFn; mSendToBackground = sendToBackground; @@ -987,6 +993,12 @@ assumeNonNull(mSnackbarManagerSupplier.get()), mLayoutManagerSupplier); } + + if (ChromeFeatureList.sEnableAndroidSidePanel.isEnabled()) { + mCompositorViewHolderSupplier + .get() + .setSideUiStateProviderSupplier(mSideUiStateProviderSupplier); + } } @Override @@ -1296,7 +1308,6 @@ mActivity, mWindowAndroid, mAppMenuCoordinator, - mActivityLifecycleDispatcher, profile, mActivityTabProvider.asObservable(), mIsInOverviewModeSupplier, @@ -1878,7 +1889,7 @@ mProfileSupplier, mSidePanelContainerCoordinator, mWindowAndroid); } - mCompositorViewHolderSupplier.get().setSideUiStateProvider(mSideUiCoordinator); + mSideUiStateProviderSupplier.set(mSideUiCoordinator); } private void destroySideUi() { @@ -2294,4 +2305,9 @@ }); } } + + /** Returns the {@link OneshotSupplier} for the {@link SideUiStateProvider}. */ + public OneshotSupplier<SideUiStateProvider> getSideUiStateProviderSupplier() { + return mSideUiStateProviderSupplier; + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarButtonInProductHelpController.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarButtonInProductHelpController.java index 6a6e383..fb93723 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarButtonInProductHelpController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarButtonInProductHelpController.java
@@ -8,29 +8,19 @@ import android.os.Handler; import android.view.View; -import org.chromium.base.DeviceInfo; import org.chromium.base.TraceEvent; import org.chromium.base.supplier.NullableObservableSupplier; -import org.chromium.base.task.PostTask; -import org.chromium.base.task.TaskTraits; import org.chromium.build.annotations.NullMarked; -import org.chromium.build.annotations.Nullable; import org.chromium.chrome.R; import org.chromium.chrome.browser.bookmarks.PowerBookmarkUtils; import org.chromium.chrome.browser.commerce.ShoppingServiceFactory; import org.chromium.chrome.browser.download.DownloadUtils; import org.chromium.chrome.browser.feature_engagement.TrackerFactory; import org.chromium.chrome.browser.flags.ChromeFeatureList; -import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; -import org.chromium.chrome.browser.lifecycle.PauseResumeWithNativeObserver; import org.chromium.chrome.browser.ntp_customization.NtpCustomizationUtils; import org.chromium.chrome.browser.offlinepages.OfflinePageBridge; import org.chromium.chrome.browser.pdf.PdfPage; import org.chromium.chrome.browser.profiles.Profile; -import org.chromium.chrome.browser.screenshot_monitor.ScreenshotMonitor; -import org.chromium.chrome.browser.screenshot_monitor.ScreenshotMonitorDelegate; -import org.chromium.chrome.browser.screenshot_monitor.ScreenshotMonitorImpl; -import org.chromium.chrome.browser.screenshot_monitor.ScreenshotTabObserver; import org.chromium.chrome.browser.tab.CurrentTabObserver; import org.chromium.chrome.browser.tab.EmptyTabObserver; import org.chromium.chrome.browser.tab.Tab; @@ -57,18 +47,13 @@ * IPH from here. */ @NullMarked -public class ToolbarButtonInProductHelpController - implements ScreenshotMonitorDelegate, PauseResumeWithNativeObserver { +public class ToolbarButtonInProductHelpController { private final CurrentTabObserver mPageLoadObserver; private final Activity mActivity; private final WindowAndroid mWindowAndroid; - private final ActivityLifecycleDispatcher mLifecycleDispatcher; - private @Nullable ScreenshotMonitor mScreenshotMonitor; private final View mMenuButtonAnchorView; private final AppMenuHandler mAppMenuHandler; private final UserEducationHelper mUserEducationHelper; - private final Profile mProfile; - private final NullableObservableSupplier<Tab> mCurrentTabSupplier; private final Supplier<Boolean> mIsInOverviewModeSupplier; /** @@ -76,7 +61,6 @@ * @param windowAndroid {@link WindowAndroid} for the current Activity. * @param appMenuCoordinator {@link AppMenuCoordinator} whose visual state is to be updated * accordingly. - * @param lifecycleDispatcher {@link LifecycleDispatcher} that helps observe activity lifecycle. * @param profile The current Profile. * @param tabSupplier An observable supplier of the current {@link Tab}. * @param isInOverviewModeSupplier Supplies whether the app is in overview mode. @@ -86,7 +70,6 @@ Activity activity, WindowAndroid windowAndroid, AppMenuCoordinator appMenuCoordinator, - ActivityLifecycleDispatcher lifecycleDispatcher, Profile profile, NullableObservableSupplier<Tab> tabSupplier, Supplier<Boolean> isInOverviewModeSupplier, @@ -97,13 +80,6 @@ mMenuButtonAnchorView = menuButtonAnchorView; mIsInOverviewModeSupplier = isInOverviewModeSupplier; mUserEducationHelper = new UserEducationHelper(mActivity, profile, new Handler()); - if (!DeviceInfo.isAutomotive()) { - mScreenshotMonitor = new ScreenshotMonitorImpl(this, mActivity); - } - mLifecycleDispatcher = lifecycleDispatcher; - mLifecycleDispatcher.register(this); - mProfile = profile; - mCurrentTabSupplier = tabSupplier; mPageLoadObserver = new CurrentTabObserver( tabSupplier, @@ -157,7 +133,6 @@ public void destroy() { mPageLoadObserver.destroy(); - mLifecycleDispatcher.unregister(this); } /** @@ -279,43 +254,6 @@ } } - // Overridden public methods. - @Override - public void onResumeWithNative() { - // Part of the (more runtime-related) check to determine whether to trigger help UI is - // left until onScreenshotTaken() since it is less expensive to keep monitoring on and - // check when the help UI is accessed than it is to start/stop monitoring per tab change - // (e.g. tab switch or in overview mode). - if (DeviceFormFactor.isWindowOnTablet(mWindowAndroid)) return; - if (mScreenshotMonitor != null) mScreenshotMonitor.startMonitoring(); - } - - @Override - public void onPauseWithNative() { - if (mScreenshotMonitor != null) mScreenshotMonitor.stopMonitoring(); - } - - @Override - public void onScreenshotTaken() { - Tab currentTab = mCurrentTabSupplier.get(); - Profile currentProfile = currentTab != null ? currentTab.getProfile() : mProfile; - - Tracker tracker = TrackerFactory.getTrackerForProfile(currentProfile); - tracker.notifyEvent(EventConstants.SCREENSHOT_TAKEN_CHROME_IN_FOREGROUND); - - if (currentTab == null) return; - - PostTask.postTask( - TaskTraits.UI_DEFAULT, - () -> { - if (currentTab != mCurrentTabSupplier.get()) return; - showDownloadPageTextBubble( - currentTab, FeatureConstants.DOWNLOAD_PAGE_SCREENSHOT_FEATURE); - ScreenshotTabObserver tabObserver = ScreenshotTabObserver.from(currentTab); - if (tabObserver != null) tabObserver.onScreenshotTaken(); - }); - } - private void showDownloadHomeIph() { mUserEducationHelper.requestShowIph( new IphCommandBuilder( @@ -379,12 +317,6 @@ .setOnDismissCallback(this::turnOffHighlightForMenuItem) .setAnchorView(mMenuButtonAnchorView) .build()); - // Record metrics if we show Download IPH after a screenshot of the page. - ScreenshotTabObserver tabObserver = ScreenshotTabObserver.from(tab); - if (tabObserver != null) { - tabObserver.onActionPerformedAfterScreenshot( - ScreenshotTabObserver.SCREENSHOT_ACTION_DOWNLOAD_IPH); - } } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java index 01b2c3e..351bdc30 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -192,6 +192,7 @@ import org.chromium.chrome.browser.ui.appmenu.AppMenuDelegate; import org.chromium.chrome.browser.ui.appmenu.MenuButtonDelegate; import org.chromium.chrome.browser.ui.bottombar.BottomBarConfigUtils; +import org.chromium.chrome.browser.ui.bottombar.BottomBarHostManager; import org.chromium.chrome.browser.ui.browser_window.ChromeAndroidTask; import org.chromium.chrome.browser.ui.edge_to_edge.EdgeToEdgeController; import org.chromium.chrome.browser.ui.edge_to_edge.TopInsetProvider; @@ -442,6 +443,7 @@ private @Nullable ToolbarPositionController mToolbarPositionController; private @Nullable UndoBarThrottle mUndoBarThrottle; private @Nullable IncognitoNtpOmniboxAutofocusManager mIncognitoNtpOmniboxAutofocusManager; + private final @Nullable BottomBarHostManager mBottomBarHostManager; private CustomTabCount mCustomTabCount; private int mIncognitoNtpViewIdForA11y = View.NO_ID; @@ -778,6 +780,7 @@ * space mode, false otherwise. * @param pageZoomManager The {@link PageZoomManager} used to manage the page zoom. * @param omniboxChipManager The {@link OmniboxChipManager} to show chips in the omnibox. + * @param bottomBarHostManager The {@link BottomBarHostManager} to manage the bottom bar. */ public ToolbarManager( AppCompatActivity activity, @@ -834,7 +837,8 @@ NonNullObservableSupplier<Boolean> xrSpaceModeObservableSupplier, PageZoomManager pageZoomManager, SnackbarManager snackbarManager, - @Nullable OmniboxChipManager omniboxChipManager) { + @Nullable OmniboxChipManager omniboxChipManager, + @Nullable BottomBarHostManager bottomBarHostManager) { TraceEvent.begin("ToolbarManager.ToolbarManager"); mActivity = activity; mWindowAndroid = windowAndroid; @@ -875,6 +879,7 @@ mCustomTabCount = new CustomTabCount(tabModelSelectorSupplier); mProfileSupplier = profileSupplier; mChromeAndroidTaskSupplier = chromeAndroidTaskSupplier; + mBottomBarHostManager = bottomBarHostManager; mToolbarLayout = mActivity.findViewById(R.id.toolbar); NewTabPageDelegate ntpDelegate = createNewTabPageDelegate(); @@ -2354,10 +2359,18 @@ var bottomBarContainerOneshotSupplier = new OneshotSupplierImpl<BottomControlsContentDelegate>(); - bottomBarContainerOneshotSupplier.set( + BottomBarContainerCoordinator bottomBarContainerCoordinator = new BottomBarContainerCoordinator( bottomAppBarContainer.findViewById(R.id.bottom_container_slot), - mBottomControlsStacker::requestLayerUpdate)); + mBottomControlsStacker::requestLayerUpdate); + bottomBarContainerOneshotSupplier.set(bottomBarContainerCoordinator); + + if (mBottomBarHostManager != null) { + mBottomBarHostManager.registerBottomBar( + bottomBarContainerCoordinator.getBottomBar(), + bottomBarContainerCoordinator::attachBottomBarView); + } + var bottomAppBarCoordinator = new BottomControlsCoordinator( mWindowAndroid,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java index cf1fe11..b10f871 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java
@@ -180,6 +180,7 @@ import org.chromium.chrome.browser.ui.appmenu.AppMenuDelegate; import org.chromium.chrome.browser.ui.appmenu.AppMenuHandler; import org.chromium.chrome.browser.ui.appmenu.AppMenuObserver; +import org.chromium.chrome.browser.ui.bottombar.BottomBarHostManager; import org.chromium.chrome.browser.ui.browser_window.ChromeAndroidTask; import org.chromium.chrome.browser.ui.desktop_windowing.AppHeaderUtils; import org.chromium.chrome.browser.ui.desktop_windowing.TopControlsLockCoordinator; @@ -427,6 +428,7 @@ mReaderModeIphControllerSupplier = ObservableSuppliers.createMonotonic(); protected @Nullable OpenInAppEntryPoint mOpenInAppEntryPoint; protected @Nullable OmniboxChipManager mOmniboxChipManager; + protected @Nullable BottomBarHostManager mBottomBarHostManager; /** * Create a new {@link RootUiCoordinator} for the given activity. @@ -523,7 +525,8 @@ NonNullObservableSupplier<Integer> overviewColorSupplier, EdgeToEdgeManager edgeToEdgeManager, NonNullObservableSupplier<Boolean> xrSpaceModeObservableSupplier, - @Nullable DesktopWindowStateManager desktopWindowStateManager) { + @Nullable DesktopWindowStateManager desktopWindowStateManager, + @Nullable BottomBarHostManager bottomBarHostManager) { mCallbackController = new CallbackController(); mActivity = activity; mWindowAndroid = windowAndroid; @@ -566,6 +569,7 @@ mEdgeToEdgeManager = edgeToEdgeManager; mXrSpaceModeObservableSupplier = xrSpaceModeObservableSupplier; mDesktopWindowStateManager = desktopWindowStateManager; + mBottomBarHostManager = bottomBarHostManager; mAppMenuSupplier = new OneshotSupplierImpl<>(); mIsTablet = DeviceFormFactor.isNonMultiDisplayContextOnTablet(activity); mActionModeControllerCallback = new ToolbarActionModeCallback(); @@ -1934,7 +1938,8 @@ mXrSpaceModeObservableSupplier, mPageZoomManager, assertNonNull(mSnackbarManagerSupplier.get()), - mOmniboxChipManager); + mOmniboxChipManager, + mBottomBarHostManager); if (!mSupportsAppMenuSupplier.getAsBoolean()) { mToolbarManager.getToolbar().disableMenuButton(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/xr/OWNERS b/chrome/android/java/src/org/chromium/chrome/browser/xr/OWNERS index fd72936a..1fab956 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/xr/OWNERS +++ b/chrome/android/java/src/org/chromium/chrome/browser/xr/OWNERS
@@ -1 +1 @@ -file://ui/android/java/src/org/chromium/ui/xr/OWNERS +file://chrome/android/modules/xr/OWNERS
diff --git a/chrome/android/javatests/BUILD.gn b/chrome/android/javatests/BUILD.gn index 4fb4bc8..be6104a 100644 --- a/chrome/android/javatests/BUILD.gn +++ b/chrome/android/javatests/BUILD.gn
@@ -161,7 +161,6 @@ "//chrome/browser/safe_browsing/android:java", "//chrome/browser/safety_check/android:java", "//chrome/browser/safety_hub/android:java", - "//chrome/browser/screenshot_monitor:java", "//chrome/browser/search_engines/android:java", "//chrome/browser/settings:java", "//chrome/browser/settings:test_support_java", @@ -1639,7 +1638,6 @@ "src/org/chromium/chrome/browser/push_messaging/PushMessagingTest.java", "src/org/chromium/chrome/browser/read_later/ReadLaterContextMenuTest.java", "src/org/chromium/chrome/browser/reengagement/ReengagementNotificationControllerIntegrationTest.java", - "src/org/chromium/chrome/browser/screenshot_monitor/ScreenshotTabObserverTest.java", "src/org/chromium/chrome/browser/searchwidget/SearchActivityTest.java", "src/org/chromium/chrome/browser/searchwidget/SearchWidgetProviderTest.java", "src/org/chromium/chrome/browser/segmentation_platform/ContextualPageActionControllerTest.java", @@ -1726,7 +1724,6 @@ "//chrome/browser/preferences:pref_service_java", "//chrome/browser/profiles/android:java", "//chrome/browser/regional_capabilities/android:java", - "//chrome/browser/screenshot_monitor:java", "//chrome/browser/search_engines/android:java", "//chrome/browser/settings:factory_java", "//chrome/browser/settings:test_support_java", @@ -1946,7 +1943,6 @@ "src/org/chromium/chrome/browser/ntp/IncognitoDescriptionViewRenderTest.java", "src/org/chromium/chrome/browser/ntp/TitleUtilTest.java", "src/org/chromium/chrome/browser/payments/ui/CurrencyFormatterTest.java", - "src/org/chromium/chrome/browser/screenshot_monitor/ScreenshotMonitorTest.java", "src/org/chromium/chrome/browser/search_engines/settings/SearchEngineSettingsRenderTest.java", "src/org/chromium/chrome/browser/share/ShareUrlTest.java", "src/org/chromium/chrome/browser/status_indicator/StatusIndicatorViewBinderTest.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/screenshot_monitor/ScreenshotMonitorTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/screenshot_monitor/ScreenshotMonitorTest.java deleted file mode 100644 index a10ea332..0000000 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/screenshot_monitor/ScreenshotMonitorTest.java +++ /dev/null
@@ -1,314 +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.chrome.browser.screenshot_monitor; - -import android.content.Context; -import android.content.ContextWrapper; -import android.content.pm.PackageManager; -import android.database.ContentObserver; -import android.database.Cursor; -import android.net.Uri; -import android.provider.MediaStore; -import android.test.mock.MockContentProvider; -import android.test.mock.MockContentResolver; - -import androidx.core.content.ContextCompat; -import androidx.test.core.app.ApplicationProvider; -import androidx.test.filters.SmallTest; - -import org.junit.Assert; -import org.junit.Assume; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.junit.MockitoJUnit; -import org.mockito.junit.MockitoRule; - -import org.chromium.base.ContextUtils; -import org.chromium.base.Log; -import org.chromium.base.ThreadUtils; -import org.chromium.base.task.PostTask; -import org.chromium.base.task.TaskTraits; -import org.chromium.base.test.util.Batch; -import org.chromium.base.test.util.Feature; -import org.chromium.chrome.test.ChromeJUnit4ClassRunner; -import org.chromium.ui.base.MimeTypeUtils; -import org.chromium.ui.display.DisplayAndroid; - -import java.util.concurrent.Semaphore; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; - -/** Tests ScreenshotMonitor. */ -@RunWith(ChromeJUnit4ClassRunner.class) -@Batch(Batch.PER_CLASS) -public class ScreenshotMonitorTest { - private static final String TAG = "ScreenshotTest"; - private static final Uri TEST_URI = Uri.parse("content://media/external/images/media/101"); - - @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule(); - private ScreenshotMonitorImpl mTestScreenshotMonitor; - private TestScreenshotMonitorDelegate mTestScreenshotMonitorDelegate; - private ContentObserver mContentObserver; - - private final MockContentResolver mMockContentResolver = new MockContentResolver(); - - @Mock private DisplayAndroid mDisplayAndroid; - - static class TestScreenshotMonitorDelegate implements ScreenshotMonitorDelegate { - // This is modified on the UI thread and accessed on the test thread. - public final AtomicInteger screenshotShowUiCount = new AtomicInteger(); - - @Override - public void onScreenshotTaken() { - Assert.assertTrue(ThreadUtils.runningOnUiThread()); - screenshotShowUiCount.getAndIncrement(); - } - } - - private static class TestContext extends ContextWrapper { - public TestContext(Context base) { - super(base); - } - - @Override - public int checkPermission(String permission, int pid, int uid) { - return PackageManager.PERMISSION_GRANTED; - } - } - - @Before - public void setUp() { - // Replaces the application context with a test implementation which will return true for - // permission requests. This is needed for the permission check in - // ScreenshotMonitorImpl#doesChangeLookLikeScreenshot. - Context context = new TestContext(ApplicationProvider.getApplicationContext()); - ContextUtils.initApplicationContextForTests(context); - Assume.assumeTrue( - ContextCompat.checkSelfPermission( - ContextUtils.getApplicationContext(), - MimeTypeUtils.getPermissionNameForMimeType( - MimeTypeUtils.Type.IMAGE)) - == PackageManager.PERMISSION_GRANTED); - - mTestScreenshotMonitorDelegate = new TestScreenshotMonitorDelegate(); - - ThreadUtils.runOnUiThreadBlocking( - () -> { - mTestScreenshotMonitor = - new ScreenshotMonitorImpl( - mTestScreenshotMonitorDelegate, - null, - mMockContentResolver, - mDisplayAndroid); - mContentObserver = mTestScreenshotMonitor.getContentObserver(); - }); - } - - private void mockValidContentResolver(String path, String width, String height) { - final Cursor cursor = Mockito.mock(Cursor.class); - Mockito.doReturn(true).when(cursor).moveToNext(); - - Mockito.doReturn(1) - .when(cursor) - .getColumnIndexOrThrow(Mockito.eq(MediaStore.MediaColumns.DATA)); - Mockito.doReturn(2) - .when(cursor) - .getColumnIndexOrThrow(Mockito.eq(MediaStore.MediaColumns.WIDTH)); - Mockito.doReturn(3) - .when(cursor) - .getColumnIndexOrThrow(Mockito.eq(MediaStore.MediaColumns.HEIGHT)); - Mockito.doReturn(path).when(cursor).getString(Mockito.eq(1)); - Mockito.doReturn(width).when(cursor).getString(Mockito.eq(2)); - Mockito.doReturn(height).when(cursor).getString(Mockito.eq(3)); - - mMockContentResolver.addProvider( - "media", - new MockContentProvider() { - @Override - public Cursor query( - Uri uri, - String[] projection, - String selection, - String[] selectionArgs, - String sortOrder) { - return cursor; - } - }); - } - - private void mockDisplay(int width, int height) { - Mockito.doReturn(width).when(mDisplayAndroid).getDisplayWidth(); - Mockito.doReturn(height).when(mDisplayAndroid).getDisplayHeight(); - } - - /** - * Verify that if monitoring starts, the delegate should be called. Also verify that the inner - * TestFileObserver monitors as expected. - */ - @Test - @SmallTest - @Feature({"FeatureEngagement", "Screenshot"}) - public void testDelegateCalledOnEvent() { - mockDisplay(50, 100); - mockValidContentResolver("Screenshot", "50", "100"); - - startMonitoringOnUiThreadBlocking(); - Assert.assertEquals(0, mTestScreenshotMonitorDelegate.screenshotShowUiCount.get()); - - mContentObserver.onChange(true, TEST_URI); - assertScreenshotShowUiCountOnUiThreadBlocking(1); - - stopMonitoringOnUiThreadBlocking(); - } - - /** Verify that the delegate is called after a restart. */ - @Test - @SmallTest - @Feature({"FeatureEngagement", "Screenshot"}) - public void testRestartShouldTriggerDelegate() { - mockDisplay(50, 100); - mockValidContentResolver("Screenshot", "50", "100"); - - startMonitoringOnUiThreadBlocking(); - Assert.assertEquals(0, mTestScreenshotMonitorDelegate.screenshotShowUiCount.get()); - - mContentObserver.onChange(true, TEST_URI); - assertScreenshotShowUiCountOnUiThreadBlocking(1); - - stopMonitoringOnUiThreadBlocking(); - - // Restart and call onEvent a second time - startMonitoringOnUiThreadBlocking(); - Assert.assertEquals(1, mTestScreenshotMonitorDelegate.screenshotShowUiCount.get()); - - mContentObserver.onChange(true, TEST_URI); - assertScreenshotShowUiCountOnUiThreadBlocking(2); - } - - /** Verify that if monitoring stops, the delegate should not be called. */ - @Test - @SmallTest - @Feature({"FeatureEngagement", "Screenshot"}) - public void testStopMonitoringShouldNotTriggerDelegate() { - mockDisplay(50, 100); - mockValidContentResolver("Screenshot", "50", "100"); - - startMonitoringOnUiThreadBlocking(); - Assert.assertEquals(0, mTestScreenshotMonitorDelegate.screenshotShowUiCount.get()); - - stopMonitoringOnUiThreadBlocking(); - - mContentObserver.onChange(true, TEST_URI); - assertScreenshotShowUiCountOnUiThreadBlocking(0); - } - - /** Verify that if monitoring is never started, the delegate should not be called. */ - @Test - @SmallTest - @Feature({"FeatureEngagement", "Screenshot"}) - public void testNoMonitoringShouldNotTriggerDelegate() { - mockDisplay(50, 100); - mockValidContentResolver("Screenshot", "50", "100"); - - Assert.assertEquals(0, mTestScreenshotMonitorDelegate.screenshotShowUiCount.get()); - - mContentObserver.onChange(true, TEST_URI); - assertScreenshotShowUiCountOnUiThreadBlocking(0); - } - - @Test - @SmallTest - @Feature({"FeatureEngagement", "Screenshot"}) - public void testRotatedContent() { - mockDisplay(100, 50); - mockValidContentResolver("Screenshot", "50", "100"); - - startMonitoringOnUiThreadBlocking(); - Assert.assertEquals(0, mTestScreenshotMonitorDelegate.screenshotShowUiCount.get()); - - mContentObserver.onChange(true, TEST_URI); - assertScreenshotShowUiCountOnUiThreadBlocking(1); - } - - @Test - @SmallTest - @Feature({"FeatureEngagement", "Screenshot"}) - public void testInvalidSize() { - mockDisplay(150, 150); - mockValidContentResolver("Screenshot", "50", "100"); - - startMonitoringOnUiThreadBlocking(); - Assert.assertEquals(0, mTestScreenshotMonitorDelegate.screenshotShowUiCount.get()); - - mContentObserver.onChange(true, TEST_URI); - assertScreenshotShowUiCountOnUiThreadBlocking(0); - } - - // This ensures that the UI thread finishes executing startMonitoring. - private void startMonitoringOnUiThreadBlocking() { - final Semaphore semaphore = new Semaphore(0); - - PostTask.postTask( - TaskTraits.UI_DEFAULT, - new Runnable() { - @Override - public void run() { - mTestScreenshotMonitor.startMonitoring(); - semaphore.release(); - } - }); - try { - Assert.assertTrue(semaphore.tryAcquire(10, TimeUnit.SECONDS)); - } catch (InterruptedException e) { - Log.e(TAG, "Cannot acquire semaphore"); - } - } - - // This ensures that the UI thread finishes executing stopMonitoring. - private void stopMonitoringOnUiThreadBlocking() { - final Semaphore semaphore = new Semaphore(0); - - PostTask.postTask( - TaskTraits.UI_DEFAULT, - new Runnable() { - @Override - public void run() { - mTestScreenshotMonitor.stopMonitoring(); - semaphore.release(); - } - }); - try { - Assert.assertTrue(semaphore.tryAcquire(10, TimeUnit.SECONDS)); - } catch (InterruptedException e) { - Log.e(TAG, "Cannot acquire semaphore"); - } - } - - // This ensures that after UI thread finishes all tasks, screenshotShowUiCount equals - // expectedCount. - private void assertScreenshotShowUiCountOnUiThreadBlocking(int expectedCount) { - final Semaphore semaphore = new Semaphore(0); - - PostTask.postTask( - TaskTraits.UI_DEFAULT, - new Runnable() { - @Override - public void run() { - semaphore.release(); - } - }); - try { - Assert.assertTrue(semaphore.tryAcquire(10, TimeUnit.SECONDS)); - } catch (InterruptedException e) { - Log.e(TAG, "Cannot acquire semaphore"); - } - Assert.assertEquals( - expectedCount, mTestScreenshotMonitorDelegate.screenshotShowUiCount.get()); - } -}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/screenshot_monitor/ScreenshotTabObserverTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/screenshot_monitor/ScreenshotTabObserverTest.java deleted file mode 100644 index 37adc59a..0000000 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/screenshot_monitor/ScreenshotTabObserverTest.java +++ /dev/null
@@ -1,136 +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.chrome.browser.screenshot_monitor; - -import androidx.test.filters.MediumTest; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.chromium.base.ThreadUtils; -import org.chromium.base.test.util.CallbackHelper; -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.HistogramWatcher; -import org.chromium.base.test.util.Matchers; -import org.chromium.base.test.util.UserActionTester; -import org.chromium.chrome.browser.flags.ChromeSwitches; -import org.chromium.chrome.browser.tab.Tab; -import org.chromium.chrome.browser.tabmodel.TabClosureParams; -import org.chromium.chrome.test.ChromeJUnit4ClassRunner; -import org.chromium.chrome.test.transit.AutoResetCtaTransitTestRule; -import org.chromium.chrome.test.transit.ChromeTransitTestRules; -import org.chromium.chrome.test.transit.page.WebPageStation; - -import java.util.List; -import java.util.concurrent.TimeoutException; - -/** Tests for ScreenshotTabObserver class. */ -@RunWith(ChromeJUnit4ClassRunner.class) -@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) -// TODO(crbug.com/344675714): Failing when batched, batch this again. -public class ScreenshotTabObserverTest { - @Rule - public AutoResetCtaTransitTestRule mActivityTestRule = - ChromeTransitTestRules.fastAutoResetCtaActivityRule(); - - private WebPageStation mPage; - private Tab mTab; - private ScreenshotTabObserver mObserver; - - @Before - public void setUp() throws Exception { - mPage = mActivityTestRule.startOnBlankPage(); - mTab = mPage.getTab(); - ThreadUtils.runOnUiThreadBlocking( - (Runnable) () -> mObserver = ScreenshotTabObserver.from(mTab)); - } - - private void closeCurrentTab() { - mActivityTestRule - .getActivity() - .getCurrentTabModel() - .getTabRemover() - .closeTabs( - TabClosureParams.closeTab(mTab).allowUndo(false).build(), - /* allowDialog= */ false); - } - - @Test - @MediumTest - public void testScreenshotUserCounts() { - UserActionTester userActionTester = new UserActionTester(); - mObserver.onScreenshotTaken(); - // Must wait for the user action to arrive on the UI thread before checking it. - CriteriaHelper.pollUiThread( - () -> { - List<String> actions = userActionTester.getActions(); - Criteria.checkThat(actions, Matchers.hasItem("Tab.Screenshot")); - }); - } - - @Test - @MediumTest - public void testScreenshotNumberReportingOne() throws TimeoutException { - var histogramWatcher = - HistogramWatcher.newSingleRecordWatcher("Tab.Screenshot.ScreenshotsPerPage", 1); - CallbackHelper callbackHelper = new CallbackHelper(); - setupOnReportCompleteCallbackHelper(callbackHelper); - int count = callbackHelper.getCallCount(); - - mObserver.onScreenshotTaken(); - ThreadUtils.runOnUiThreadBlocking(this::closeCurrentTab); - callbackHelper.waitForCallback(count); - - histogramWatcher.assertExpected("Should be one page with one snapshot reported."); - } - - @Test - @MediumTest - public void testScreenshotNumberReportingTwo() throws TimeoutException { - var histogramWatcher = - HistogramWatcher.newSingleRecordWatcher("Tab.Screenshot.ScreenshotsPerPage", 2); - CallbackHelper callbackHelper = new CallbackHelper(); - setupOnReportCompleteCallbackHelper(callbackHelper); - int count = callbackHelper.getCallCount(); - - mObserver.onScreenshotTaken(); - mObserver.onScreenshotTaken(); - ThreadUtils.runOnUiThreadBlocking(this::closeCurrentTab); - callbackHelper.waitForCallback(count); - - histogramWatcher.assertExpected("Should be one page with two snapshots reported."); - } - - @Test - @MediumTest - public void testScreenshotActionReporting() throws TimeoutException { - var histogramWatcher = HistogramWatcher.newSingleRecordWatcher("Tab.Screenshot.Action", 1); - CallbackHelper callbackHelper = new CallbackHelper(); - setupOnReportCompleteCallbackHelper(callbackHelper); - int count = callbackHelper.getCallCount(); - - mObserver.onScreenshotTaken(); - mObserver.onActionPerformedAfterScreenshot(ScreenshotTabObserver.SCREENSHOT_ACTION_SHARE); - ThreadUtils.runOnUiThreadBlocking(this::closeCurrentTab); - callbackHelper.waitForCallback(count); - - histogramWatcher.assertExpected( - "Should be one share action reported, but none of the other types."); - } - - private void setupOnReportCompleteCallbackHelper(CallbackHelper callbackHelper) { - mObserver.setOnReportCompleteForTesting( - new Runnable() { - @Override - public void run() { - callbackHelper.notifyCalled(); - } - }); - } -}
diff --git a/chrome/android/junit/BUILD.gn b/chrome/android/junit/BUILD.gn index fcefd9bb..2eb5aa25 100644 --- a/chrome/android/junit/BUILD.gn +++ b/chrome/android/junit/BUILD.gn
@@ -166,7 +166,6 @@ "//chrome/browser/regional_capabilities/android:java", "//chrome/browser/safety_check/android:java", "//chrome/browser/safety_hub/android:java", - "//chrome/browser/screenshot_monitor:java", "//chrome/browser/search_engines/android:java", "//chrome/browser/segmentation_platform:factory_java", "//chrome/browser/settings:factory_java", @@ -420,6 +419,7 @@ # Partition tests into one target per-package to keep incremental build times down. robolectric_library("chrome_junit_tests_org.chromium.chrome.browser") { sources = [ + "//chrome/android/java/src/org/chromium/chrome/browser/bottombar/BottomBarContainerCoordinatorUnitTest.java", "src/org/chromium/chrome/browser/ChromeActionModeHandlerUnitTest.java", "src/org/chromium/chrome/browser/ChromeActivityUnitTest.java", "src/org/chromium/chrome/browser/ChromeBaseAppCompatActivityUnitTest.java",
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/CompositorViewHolderUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/CompositorViewHolderUnitTest.java index 230b5f9f..213e94f 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/CompositorViewHolderUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/CompositorViewHolderUnitTest.java
@@ -56,6 +56,7 @@ import org.chromium.base.InputHintCheckerJni; import org.chromium.base.UserDataHost; import org.chromium.base.supplier.ObservableSuppliers; +import org.chromium.base.supplier.OneshotSupplierImpl; import org.chromium.base.supplier.SettableMonotonicObservableSupplier; import org.chromium.base.supplier.SettableNonNullObservableSupplier; import org.chromium.base.test.BaseRobolectricTestRunner; @@ -203,6 +204,7 @@ private ApplicationViewportInsetTracker mViewportInsets; private SettableNonNullObservableSupplier<Integer> mKeyboardInsetSupplier; private SettableNonNullObservableSupplier<Integer> mKeyboardAccessoryInsetSupplier; + private OneshotSupplierImpl<SideUiStateProvider> mSideUiStateProviderSupplier; private final UserDataHost mUserDataHost = new UserDataHost(); @Before @@ -224,6 +226,7 @@ mViewportInsets.setKeyboardInsetSupplier(mKeyboardInsetSupplier); mKeyboardAccessoryInsetSupplier = ObservableSuppliers.createNonNull(0); mViewportInsets.setKeyboardAccessoryInsetSupplier(mKeyboardAccessoryInsetSupplier); + mSideUiStateProviderSupplier = new OneshotSupplierImpl<>(); when(mIncognitoProfile.isOffTheRecord()).thenReturn(true); @@ -278,6 +281,7 @@ mCompositorViewHolder.setApplicationViewportInsetSupplier(mViewportInsets); mCompositorViewHolder.onFinishNativeInitialization( mTabModelSelector, null, ObservableSuppliers.alwaysZero()); + mCompositorViewHolder.setSideUiStateProviderSupplier(mSideUiStateProviderSupplier); when(mCompositorViewHolder.getCurrentTab()).thenReturn(mTab); when(mCompositorViewHolder.getRootWindowInsets()) .thenReturn(VISIBLE_SYSTEM_BARS_WINDOW_INSETS.toWindowInsets()); @@ -1221,10 +1225,11 @@ @Test @EnableFeatures(ChromeFeatureList.ENABLE_ANDROID_SIDE_PANEL) - public void testSetSideUiStateProvider() { + public void testSetSideUiStateProviderSupplier() { when(mSideUiStateProvider.getCurrentSideUiSpecs()) .thenReturn(SideUiSpecs.EMPTY_SIDE_UI_SPECS); - mCompositorViewHolder.setSideUiStateProvider(mSideUiStateProvider); + mSideUiStateProviderSupplier.set(mSideUiStateProvider); + runCurrentTasks(); verify(mSideUiStateProvider).addObserver(mCompositorViewHolder); } @@ -1246,7 +1251,8 @@ int endContainerWidth = 200; SideUiSpecs currentSideUiSpecs = new SideUiSpecs(startContainerWidth, endContainerWidth); when(mSideUiStateProvider.getCurrentSideUiSpecs()).thenReturn(currentSideUiSpecs); - mCompositorViewHolder.setSideUiStateProvider(mSideUiStateProvider); + mSideUiStateProviderSupplier.set(mSideUiStateProvider); + runCurrentTasks(); // Act. Pass empty specs, as the CompositorViewHolder is expected to instead query from // the set SideUiStateProvider. @@ -1279,7 +1285,8 @@ int endContainerWidth = 150; SideUiSpecs currentSideUiSpecs = new SideUiSpecs(startContainerWidth, endContainerWidth); when(mSideUiStateProvider.getCurrentSideUiSpecs()).thenReturn(currentSideUiSpecs); - mCompositorViewHolder.setSideUiStateProvider(mSideUiStateProvider); + mSideUiStateProviderSupplier.set(mSideUiStateProvider); + runCurrentTasks(); // Act. mCompositorViewHolder.onSideUiSpecsChanged(currentSideUiSpecs);
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/sync/synced_set_up/CrossDeviceSettingImporterUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/sync/synced_set_up/CrossDeviceSettingImporterUnitTest.java index b42d2ed..ae94a2a 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/sync/synced_set_up/CrossDeviceSettingImporterUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/sync/synced_set_up/CrossDeviceSettingImporterUnitTest.java
@@ -210,7 +210,7 @@ initializeCrossDeviceSettingImporter() .askToApplyNtpSettingImportIfNeeded( - preferencesToApply, /* onlyOmniboxPosition= */ false); + mProfile, preferencesToApply, /* onlyOmniboxPosition= */ false); verify(mSnackbarManager).showSnackbar(mSnackbarCaptor.capture()); Snackbar snackbar = mSnackbarCaptor.getValue(); @@ -259,7 +259,7 @@ initializeCrossDeviceSettingImporter() .askToApplyNtpSettingImportIfNeeded( - preferencesToApply, /* onlyOmniboxPosition= */ false); + mProfile, preferencesToApply, /* onlyOmniboxPosition= */ false); verify(mSnackbarManager, times(0)).showSnackbar(mSnackbarCaptor.capture()); } @@ -274,7 +274,7 @@ initializeCrossDeviceSettingImporter() .askToApplyNtpSettingImportIfNeeded( - preferencesToApply, /* onlyOmniboxPosition= */ false); + mProfile, preferencesToApply, /* onlyOmniboxPosition= */ false); verify(mSnackbarManager).showSnackbar(mSnackbarCaptor.capture()); Snackbar snackbar = mSnackbarCaptor.getValue(); @@ -321,7 +321,7 @@ initializeCrossDeviceSettingImporter() .askToApplyNtpSettingImportIfNeeded( - preferencesToApply, /* onlyOmniboxPosition= */ false); + mProfile, preferencesToApply, /* onlyOmniboxPosition= */ false); verify(mSnackbarManager).showSnackbar(mSnackbarCaptor.capture()); Snackbar snackbar = mSnackbarCaptor.getValue(); @@ -363,7 +363,7 @@ initializeCrossDeviceSettingImporter() .askToApplyNtpSettingImportIfNeeded( - preferencesToApply, /* onlyOmniboxPosition= */ true); + mProfile, preferencesToApply, /* onlyOmniboxPosition= */ true); verify(mSnackbarManager).showSnackbar(mSnackbarCaptor.capture()); Snackbar snackbar = mSnackbarCaptor.getValue(); @@ -390,7 +390,7 @@ initializeCrossDeviceSettingImporter() .askToApplyNtpSettingImportIfNeeded( - preferencesToApply, /* onlyOmniboxPosition= */ true); + mProfile, preferencesToApply, /* onlyOmniboxPosition= */ true); verify(mSnackbarManager, never()).showSnackbar(any(Snackbar.class)); } @@ -408,7 +408,7 @@ initializeCrossDeviceSettingImporter() .askToApplyNtpSettingImportIfNeeded( - preferencesToApply, /* onlyOmniboxPosition= */ false); + mProfile, preferencesToApply, /* onlyOmniboxPosition= */ false); verify(mSnackbarManager).showSnackbar(any(Snackbar.class)); } @@ -421,7 +421,7 @@ initializeCrossDeviceSettingImporter() .askToApplyNtpSettingImportIfNeeded( - preferencesToApply, /* onlyOmniboxPosition= */ true); + mProfile, preferencesToApply, /* onlyOmniboxPosition= */ true); verify(mSnackbarManager).showSnackbar(mSnackbarCaptor.capture()); Snackbar snackbar = mSnackbarCaptor.getValue(); @@ -599,7 +599,7 @@ false)); Map<String, Object> result = initializeCrossDeviceSettingImporter() - .getPrefsFromRemoteDevice(mCrossDevicePrefTracker, mProfile); + .getPrefsFromRemoteDevice(mProfile, mCrossDevicePrefTracker); assertEquals("The result map should contain two preferences.", 2, result.size()); assertTrue( @@ -735,7 +735,7 @@ initializeCrossDeviceSettingImporter() .askToApplyNtpSettingImportIfNeeded( - preferencesToApply, /* onlyOmniboxPosition= */ true); + mProfile, preferencesToApply, /* onlyOmniboxPosition= */ true); verify(mSnackbarManager).showSnackbar(mSnackbarCaptor.capture()); Snackbar snackbar = mSnackbarCaptor.getValue(); @@ -773,4 +773,38 @@ verify(mTab2).removeObserver(any(TabObserver.class)); assertTrue(!mActivityTabSupplier.hasObservers()); } + + @Test + public void testOnServiceStatusChanged_TabBecomesNull_NoCrash() { + when(mCrossDevicePrefTracker.getServiceStatus()) + .thenReturn(ServiceStatus.DEVICE_INFO_TRACKER_MISSING); + + initializeCrossDeviceSettingImporter().onTabChangeOrGainFocus(mTab); + + verify(mCrossDevicePrefTracker).addObserver(mTrackerObserverCaptor.capture()); + + // Simulate tab becoming null. + mActivityTabSupplier.set(null); + + // Simulate tracker becoming ready. + // This should NOT crash even though mActivityTabSupplier.get() is null. + mTrackerObserverCaptor.getValue().onServiceStatusChanged(ServiceStatus.AVAILABLE); + } + + @Test + public void testOnServiceStatusChanged_ProfileBecomesNull_NoCrash() { + when(mCrossDevicePrefTracker.getServiceStatus()) + .thenReturn(ServiceStatus.DEVICE_INFO_TRACKER_MISSING); + + initializeCrossDeviceSettingImporter().onTabChangeOrGainFocus(mTab); + + verify(mCrossDevicePrefTracker).addObserver(mTrackerObserverCaptor.capture()); + + // Simulate profile becoming null on the tab. + when(mTab.getProfile()).thenReturn(null); + + // Simulate tracker becoming ready. + // This should NOT crash even though tab.getProfile() is null. + mTrackerObserverCaptor.getValue().onServiceStatusChanged(ServiceStatus.AVAILABLE); + } }
diff --git a/chrome/android/modules/xr/OWNERS b/chrome/android/modules/xr/OWNERS new file mode 100644 index 0000000..70aa4d46 --- /dev/null +++ b/chrome/android/modules/xr/OWNERS
@@ -0,0 +1,5 @@ +gurmeetk@google.com +desiatyrikov@google.com + +#For XR DFM changes. +mondello@google.com \ No newline at end of file
diff --git a/chrome/android/modules/xr/internal/java/src/org/chromium/chrome/browser/xr/scenecore/XrSceneCoreSessionManagerImpl.java b/chrome/android/modules/xr/internal/java/src/org/chromium/chrome/browser/xr/scenecore/XrSceneCoreSessionManagerImpl.java index 8d7e8210..1baa57f 100644 --- a/chrome/android/modules/xr/internal/java/src/org/chromium/chrome/browser/xr/scenecore/XrSceneCoreSessionManagerImpl.java +++ b/chrome/android/modules/xr/internal/java/src/org/chromium/chrome/browser/xr/scenecore/XrSceneCoreSessionManagerImpl.java
@@ -62,8 +62,7 @@ assert result instanceof SessionCreateSuccess : "Session creation failed."; mXrSession = ((SessionCreateSuccess) result).getSession(); - Scene scene = SessionExt.getScene(mXrSession); - mActivitySpace = scene.getActivitySpace(); + mActivitySpace = getScene().getActivitySpace(); mActivitySpace.addOnBoundsChangedListener(mBoundsChangedListener); boolean isXrFullSpaceMode = @@ -128,7 +127,7 @@ mIsFullSpaceModeRequested = requestFullSpaceMode; mXrModeSwitchCallback = completedCallback; - Scene scene = SessionExt.getScene(mXrSession); + Scene scene = getScene(); if (requestFullSpaceMode) { scene.requestFullSpaceMode(); } else { @@ -151,7 +150,7 @@ @MainThread @Override public void setMainPanelVisibility(boolean visible) { - SessionExt.getScene(mXrSession).getMainPanelEntity().setEnabled(visible); + getScene().getMainPanelEntity().setEnabled(visible); } @SuppressWarnings("NullAway") @@ -165,6 +164,10 @@ mActivity = null; } + private Scene getScene() { + return SessionExt.getScene(mXrSession); + } + private void boundsChangeCallback(FloatSize3d dimensions) { mIsFullSpaceModeNowSupplier.set(dimensions.getWidth() == Float.POSITIVE_INFINITY);
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp index 02ebc98..b05cb92 100644 --- a/chrome/app/chromeos_strings.grdp +++ b/chrome/app/chromeos_strings.grdp
@@ -3479,255 +3479,6 @@ Installing </message> - <!-- Android Apps --> - <message name="IDS_ARC_PLAYSTORE_ICON_TITLE_BETA" desc="The Play Store icon title with the beta label in the launcher."> - Play Store - </message> - <message name="IDS_ARC_NOTIFICATION_DISPLAY_SOURCE" desc="Context title of the first-run notification that enables Android apps."> - Google Play - </message> - <message name="IDS_ARC_PLAYSTORE_SETTING_UP_TITLE" desc="The text tile which is shown when Play Store is initializing."> - Setting up Google Play... - </message> - <message name="IDS_ARC_OPT_IN_DIALOG_BUTTON_AGREE" desc="Agree button of the opt-in dialog for Android apps."> - Accept - </message> - <message name="IDS_ARC_OPT_IN_DIALOG_BUTTON_CANCEL" desc="Cancel button of the opt-in dialog for Android apps."> - Cancel - </message> - <message name="IDS_ARC_OPT_IN_DIALOG_BUTTON_NEXT" desc="Next button of the opt-in dialog for Android apps."> - More - </message> - <message name="IDS_ARC_OPT_IN_DIALOG_BUTTON_RETRY" desc="Retry button of the opt-in dialog for Android apps."> - Try again - </message> - <message name="IDS_ARC_OPT_IN_DIALOG_BUTTON_SEND_FEEDBACK" desc="Send feedback button of the opt-in dialog for Android apps."> - Send feedback - </message> - <message name="IDS_ARC_OPT_IN_DIALOG_BUTTON_RUN_NETWORK_TESTS" desc="Run network tests button of the opt-in dialog for Android apps."> - Check connection - </message> - <message name="IDS_ARC_OPT_IN_DIALOG_PROGRESS_TERMS" desc="Name of Terms Of Services loading progress of the opt-in dialog for Android apps."> - Just a sec... - </message> - <message name="IDS_ARC_OPT_IN_DIALOG_PROGRESS_ANDROID" desc="Name of Android loading progress of the opt-in dialog for Android apps."> - This may take a minute or so. - </message> - <message name="IDS_ARC_OPT_IN_DIALOG_AUTHORIZATION_FAILED" desc="Error message shown when an auth code is not returned by server."> - Authorization failed - </message> - <message name="IDS_ARC_OPT_IN_DIALOG_TERMS_OF_SERVICE" desc="Terms of service caption in the opt-in dialog for Android apps."> - Terms of Service - </message> - <message name="IDS_ARC_OPT_IN_DIALOG_METRICS_MANAGED_ENABLED" desc="Message in the opt-in dialog for Android apps in case metrics are managed on the device and on."> - Send usage and diagnostic data. This device is currently automatically sending diagnostic, device, and app usage data to Google. This will help system and app stability and other improvements. Some aggregate data will also help Google apps and partners, such as Android developers. This <ph name="BEGIN_LINK1"><a href="#" id="settings-link"></ph>setting<ph name="END_LINK1"></a><ex></a></ex></ph> is enforced by the owner. If your additional Web & App Activity setting is turned on, this data may be saved to your Google account. <ph name="BEGIN_LINK2"><a href="#" id="learn-more-link-metrics" aria-label="</ph>Learn more about metrics<ph name="BEGIN_LINK2_END">"></ph>Learn More<ph name="END_LINK2"></a><ex></a></ex></ph> - </message> - <message name="IDS_ARC_OPT_IN_DIALOG_METRICS_MANAGED_ENABLED_CHILD" desc="Message in the opt-in dialog for Android apps in case metrics are managed on the device and on, and a child account is in use."> - Send usage and diagnostic data. This device is currently automatically sending diagnostic, device, and app usage data to Google. This won't be used to identify your child and will help system and app stability and other improvements. Some aggregate data will also help Google apps and partners, such as Android developers. This <ph name="BEGIN_LINK1"><a href="#" id="settings-link"></ph>setting<ph name="END_LINK1"></a><ex></a></ex></ph> is enforced by the owner. If additional Web & App Activity setting is turned on for your child, this data may be saved to their Google account. <ph name="BEGIN_LINK2"><a href="#" id="learn-more-link-metrics" aria-label="</ph>Learn more about metrics<ph name="BEGIN_LINK2_END">"></ph>Learn More<ph name="END_LINK2"></a><ex></a></ex></ph> - </message> - <message name="IDS_ARC_OPT_IN_DIALOG_METRICS_MANAGED_DISABLED" desc="Message in the opt-in dialog for Android apps in case metrics are managed on the device and off."> - Send usage and diagnostic data. Help improve your Android experience by automatically sending diagnostic, device, and app usage data to Google. This will help system and app stability and other improvements. Some aggregate data will also help Google apps and partners, such as Android developers. This <ph name="BEGIN_LINK1"><a href="#" id="settings-link"></ph>setting<ph name="END_LINK1"></a><ex></a></ex></ph> is enforced by the owner. The owner may choose to send diagnostic and usage data for this device to Google. If your additional Web & App Activity setting is turned on, this data may be saved to your Google account. <ph name="BEGIN_LINK2"><a href="#" id="learn-more-link-metrics" aria-label="</ph>Learn more about metrics<ph name="BEGIN_LINK2_END">"></ph>Learn More<ph name="END_LINK2"></a><ex></a></ex></ph> - </message> - <message name="IDS_ARC_OPT_IN_DIALOG_METRICS_MANAGED_DISABLED_CHILD" desc="Message in the opt-in dialog for Android apps in case metrics are managed on the device and off, and a child account is in use."> - Send usage and diagnostic data. Help improve your child's Android experience by automatically sending diagnostic, device, and app usage data to Google. This won't be used to identify your child and will help system and app stability and other improvements. Some aggregate data will also help Google apps and partners, such as Android developers. This <ph name="BEGIN_LINK1"><a href="#" id="settings-link"></ph>setting<ph name="END_LINK1"></a><ex></a></ex></ph> is enforced by the owner. The owner may choose to send diagnostic and usage data for this device to Google. If additional Web & App Activity setting is turned on for your child, this data may be saved to their Google account. <ph name="BEGIN_LINK2"><a href="#" id="learn-more-link-metrics" aria-label="</ph>Learn more about metrics<ph name="BEGIN_LINK2_END">"></ph>Learn More<ph name="END_LINK2"></a><ex></a></ex></ph> - </message> - <message name="IDS_ARC_OPT_IN_DIALOG_METRICS_ENABLED" desc="Message in the opt-in dialog for Android apps in case metrics are already enabled on the device. User has no way to deactivate them using opt-in dialog."> - Send usage and diagnostic data. This device is currently automatically sending diagnostic, device, and app usage data to Google. This will help system and app stability and other improvements. Some aggregate data will also help Google apps and partners, such as Android developers. If your additional Web & App Activity setting is turned on, this data may be saved to your Google Account. <ph name="BEGIN_LINK2"><a href="#" id="learn-more-link-metrics" aria-label="</ph>Learn more about metrics<ph name="BEGIN_LINK2_END">"></ph>Learn More<ph name="END_LINK2"></a><ex></a></ex></ph> - </message> - <message name="IDS_ARC_OPT_IN_DIALOG_METRICS_ENABLED_CHILD" desc="Message in the opt-in dialog for Android apps in case metrics are already enabled on the device, and a child account is in use. User has no way to deactivate them using opt-in dialog."> - Send usage and diagnostic data. This device is currently automatically sending diagnostic, device, and app usage data to Google. This won't be used to idenfity your child and will help system and app stability and other improvements. Some aggregate data will also help Google apps and partners, such as Android developers. If additional Web & App Activity setting is turned on for your child, this data may be saved to their Google Account. <ph name="BEGIN_LINK2"><a href="#" id="learn-more-link-metrics" aria-label="</ph>Learn more about metrics<ph name="BEGIN_LINK2_END">"></ph>Learn More<ph name="END_LINK2"></a><ex></a></ex></ph> - </message> - <message name="IDS_ARC_OPT_IN_DIALOG_METRICS_DISABLED" desc="Message in the opt-in dialog for Android apps in case metrics are disabled on the device. User has an option to active them using opt-in dialog"> - Send usage and diagnostic data. Help improve your Android experience by automatically sending diagnostic, device, and app usage data to Google. This will help system and app stability and other improvements. Some aggregate data will also help Google apps and partners, such as Android developers. If your additional Web & App Activity setting is turned on, this data may be saved to your Google account. <ph name="BEGIN_LINK1"><a href="#" id="learn-more-link-metrics" aria-label="</ph>Learn more about metrics<ph name="BEGIN_LINK1_END">"></ph>Learn More<ph name="END_LINK1"></a><ex></a></ex></ph> - </message> - <message name="IDS_ARC_OPT_IN_DIALOG_METRICS_DISABLED_CHILD" desc="Message in the opt-in dialog for Android apps in case metrics are disabled on the device, and a child account is in use. User has an option to active them using opt-in dialog"> - Send usage and diagnostic data. Help improve your child's Android experience by automatically sending diagnostic, device, and app usage data to Google. This won't be used to identify your child and will help system and app stability and other improvements. Some aggregate data will also help Google apps and partners, such as Android developers. If additional Web & App Activity is turned on for you child, this data may be saved to their Google account. <ph name="BEGIN_LINK1"><a href="#" id="learn-more-link-metrics" aria-label="</ph>Learn more about metrics<ph name="BEGIN_LINK1_END">"></ph>Learn More<ph name="END_LINK1"></a><ex></a></ex></ph> - </message> - <message name="IDS_ARC_OPT_IN_DIALOG_BACKUP_RESTORE" desc="Message in the opt-in dialog for users to enable Backup and Restore for Android apps."> - Back up to Google Drive. Easily restore your data or switch device at any time. Your backup includes app data. Your backups are uploaded to Google and encrypted using your Google Account password. <ph name="BEGIN_LINK1"><a href="#" id="learn-more-link-backup-restore" aria-label="</ph>Learn more about backup<ph name="BEGIN_LINK1_END">"></ph>Learn More<ph name="END_LINK1"></a><ex></a></ex></ph> - </message> - <message name="IDS_ARC_OPT_IN_DIALOG_BACKUP_RESTORE_CHILD" desc="Message in the opt-in dialog for users to enable Backup and Restore for Android apps, and a child account is in use."> - Back up to Google Drive. Easily restore data or switch device at any time. This backup includes app data. Backups are uploaded to Google and encrypted using your child's Google Account password. <ph name="BEGIN_LINK1"><a href="#" id="learn-more-link-backup-restore" aria-label="</ph>Learn more about backup<ph name="BEGIN_LINK1_END">"></ph>Learn More<ph name="END_LINK1"></a><ex></a></ex></ph> - </message> - <message name="IDS_ARC_OPT_IN_DIALOG_BACKUP_RESTORE_LABEL" desc="This string is spoken when ChromeVox focuses the checkbox to enable Backup and Restore for Android apps in the opt-in dialog." is_accessibility_with_no_ui="true"> - Back up to Google Drive. Easily restore your data or switch device at any time. Your backup includes app data. Your backups are uploaded to Google and encrypted using your Google Account password. - </message> - <message name="IDS_ARC_OPT_IN_DIALOG_BACKUP_RESTORE_CHILD_LABEL" desc="This string is spoken when ChromeVox focuses the checkbox to enable Backup and Restore for Android apps in the opt-in dialog, and a child account is in use." is_accessibility_with_no_ui="true"> - Back up to Google Drive. Easily restore data or switch device at any time. This backup includes app data. Backups are uploaded to Google and encrypted using your child's Google Account password. - </message> - <message name="IDS_ARC_OPT_IN_LOCATION_SETTING" desc="Message in the opt-in dialog for Android apps for the user to turn on Google location services."> - Use location. Allow apps and services with location permission to use your device’s location. Google may collect location data periodically and use this data in an anonymous way to improve location accuracy and location-based services. <ph name="BEGIN_LINK1"><a href="#" id="learn-more-link-location-service" aria-label="</ph>Learn more about location<ph name="BEGIN_LINK1_END">"></ph>Learn More<ph name="END_LINK1"></a><ex></a></ex></ph> - </message> - <message name="IDS_ARC_OPT_IN_LOCATION_SETTING_CHILD" desc="Message in the opt-in dialog for Android apps for the user to turn on Google location services, and a child account is in use."> - Use location. Allow apps and services with location permission to use this device’s location. Google may collect location data periodically and use this data in an anonymous way to improve location accuracy and location-based services. <ph name="BEGIN_LINK1"><a href="#" id="learn-more-link-location-service" aria-label="</ph>Learn more about location<ph name="BEGIN_LINK1_END">"></ph>Learn More<ph name="END_LINK1"></a><ex></a></ex></ph> - </message> - <message name="IDS_CROS_OPT_IN_LOCATION_SETTING" desc="Message in the opt-in dialog for Android apps for the user to turn on Google location services."> - Use location. Allow ChromeOS and Android apps, websites, and services with location permission to use your device's location. Location Accuracy provides more accurate location for Android apps and services. To do this, Google periodically processes information about device sensors and wireless signals from your device to crowdsource wireless signal locations. These are used without identifying you to improve location accuracy and location-based services and to improve, provide, and maintain Google's services based on Google's and third parties' legitimate interests to serve users' needs. <ph name="BEGIN_LINK1"><a href="#" id="learn-more-link-location-service"></ph>Learn more about using location<ph name="END_LINK1"></a><ex></a></ex></ph> - </message> - <message name="IDS_CROS_OPT_IN_LOCATION_SETTING_CHILD" desc="Message in the opt-in dialog for Android apps for the user to turn on Google location services, and a child account is in use."> - Use location. Allow ChromeOS and Android apps, websites, and services with location permission to use this device's location. Location Accuracy provides more accurate location for Android apps and services. To do this, Google periodically processes information about device sensors and wireless signals from this device to crowdsource wireless signal locations. These are used without identifying any individual to improve location accuracy and location-based services and to improve, provide, and maintain Google's services based on Google's and third parties' legitimate interests to serve users' needs. <ph name="BEGIN_LINK1"><a href="#" id="learn-more-link-location-service"></ph>Learn more about using location<ph name="END_LINK1"></a><ex></a></ex></ph> - </message> - <message name="IDS_ARC_OPT_IN_PAI" desc="Message in the opt-in dialog for Play auto install."> - Install updates & apps. By continuing, you agree that this device may also automatically download and install updates and apps from Google, your carrier, and your device's manufacturer, possibly using cellular data. Some of these apps may offer in-app purchases. <ph name="BEGIN_LINK1"><a href="#" id="learn-more-link-pai" aria-label="</ph>Learn more about play auto install<ph name="BEGIN_LINK1_END">"></ph>Learn More<ph name="END_LINK1"></a><ex></a></ex></ph> - </message> - <message name="IDS_ARC_OPT_IN_GOOGLE_SERVICE_CONFIRMATION" desc="Message in the opt-in dialog for Accepting Google services."> - Tap “Accept” to confirm your selection of these Google services settings. - </message> - <message name="IDS_ARC_OPT_IN_LEARN_MORE_CLOSE" desc="Text for close button in learn more dialog"> - Close - </message> - <message name="IDS_ARC_OPT_IN_LEARN_MORE_STATISTICS_TITLE" desc="Title for pop up overlay dialog when user clicks learn more UMA"> - Usage and diagnostic data - </message> - <message name="IDS_ARC_OPT_IN_LEARN_MORE_STATISTICS" desc="Message shown in pop up overlay dialog when user clicks learn more UMA"> - <ph name="BEGIN_PARAGRAPH1"><p></ph>This is general information about your device and how you use it (such as battery level, system and app activity, and errors). The data will be used to improve Android, and some aggregated information will also help Google apps and partners, such as Android developers, make their apps and products better.<ph name="END_PARAGRAPH1"></p></ph> - <ph name="BEGIN_PARAGRAPH2"><p></ph>Turning off this feature doesn't affect your device's ability to send the information needed for essential services such as system updates and security.<ph name="END_PARAGRAPH2"></p></ph> - <ph name="BEGIN_PARAGRAPH3"><p></ph>The owner can control this feature from Settings > Advanced > Automatically send diagnostic and usage data to Google.<ph name="END_PARAGRAPH3"></p></ph> - <ph name="BEGIN_PARAGRAPH4"><p></ph>If your additional Web & App Activity setting is turned on, this data may be saved to your Google Account. You can see your data, delete it, and change your account settings at account.google.com.<ph name="END_PARAGRAPH4"></p></ph> - </message> - <message name="IDS_ARC_OPT_IN_LEARN_MORE_STATISTICS_CHILD" desc="Message shown in pop up overlay dialog when user clicks learn more UMA, and a child account is in use"> - <ph name="BEGIN_PARAGRAPH1"><p></ph>This is general information about this device and how it's used (such as battery level, system and app activity, and errors). The data will be used to improve Android, and some aggregated information will also help Google apps and partners, such as Android developers, make their apps and products better.<ph name="END_PARAGRAPH1"></p></ph> - <ph name="BEGIN_PARAGRAPH2"><p></ph>Turning off this feature doesn't affect this device's ability to send the information needed for essential services such as system updates and security.<ph name="END_PARAGRAPH2"></p></ph> - <ph name="BEGIN_PARAGRAPH3"><p></ph>The owner can control this feature from Settings > Advanced > Automatically send diagnostic and usage data to Google.<ph name="END_PARAGRAPH3"></p></ph> - <ph name="BEGIN_PARAGRAPH4"><p></ph>If additional Web & App Activity setting is turned on for your child, this data may be saved to their Google Account. Learn more about these settings and how to adjust them at families.google.com.<ph name="END_PARAGRAPH4"></p></ph> - </message> - <message name="IDS_ARC_OPT_IN_LEARN_MORE_BACKUP_AND_RESTORE_TITLE" desc="Title for pop up overlay dialog when user clicks learn more backup and restore"> - Back up to Google Drive - </message> - <message name="IDS_ARC_OPT_IN_LEARN_MORE_BACKUP_AND_RESTORE" desc="Message shown in pop up overlay dialog when user clicks learn more backup and restore"> - <ph name="BEGIN_PARAGRAPH1"><p></ph>Back up to Google Drive. Easily restore your data or switch device at any time. Your backup includes app data.<ph name="END_PARAGRAPH1"></p></ph> - <ph name="BEGIN_PARAGRAPH2"><p></ph>Your backups are uploaded to Google and encrypted using your Google Account password.<ph name="END_PARAGRAPH2"></p></ph> - <ph name="BEGIN_PARAGRAPH3"><p></ph>App data can be any data that an app has saved (based on developer settings), including data such as contacts, messages, and photos.<ph name="END_PARAGRAPH3"></p></ph> - <ph name="BEGIN_PARAGRAPH4"><p></ph>Backup data will not count toward your Drive storage quota.<ph name="END_PARAGRAPH4"></p></ph> - <ph name="BEGIN_PARAGRAPH5"><p></ph>You can turn this service off in Settings.<ph name="END_PARAGRAPH5"></p></ph> - </message> - <message name="IDS_ARC_OPT_IN_LEARN_MORE_BACKUP_AND_RESTORE_CHILD" desc="Message shown in pop up overlay dialog when user clicks learn more backup and restore, and a child account is in use"> - <ph name="BEGIN_PARAGRAPH1"><p></ph>App data can be any data that an app has saved (based on developer settings), including data such as contacts, messages, and photos.<ph name="END_PARAGRAPH1"></p></ph> - <ph name="BEGIN_PARAGRAPH2"><p></ph>Backup data will not count toward your child's Drive storage quota.<ph name="END_PARAGRAPH2"></p></ph> - <ph name="BEGIN_PARAGRAPH3"><p></ph>You can turn this service off in Settings.<ph name="END_PARAGRAPH3"></p></ph> - </message> - <message name="IDS_ARC_OPT_IN_LEARN_MORE_LOCATION_SERVICES_TITLE" desc="Title for pop up overlay dialog when user clicks learn more location services"> - Location Services - </message> - <message name="IDS_ARC_OPT_IN_LEARN_MORE_LOCATION_SERVICES" desc="Message shown in pop up overlay dialog when user clicks learn more location services"> - <ph name="BEGIN_PARAGRAPH1"><p></ph>Google's location service uses sources like Wi-Fi, mobile networks, and sensors to help estimate your device’s location.<ph name="END_PARAGRAPH1"></p></ph> - <ph name="BEGIN_PARAGRAPH2"><p></ph>You can turn off Location by turning off the main Location setting on your device. You can also turn off the use of Wi-Fi, mobile networks, and sensors for location in location settings.<ph name="END_PARAGRAPH2"></p></ph> - </message> - <message name="IDS_ARC_OPT_IN_LEARN_MORE_LOCATION_SERVICES_CHILD" desc="Message shown in pop up overlay dialog when user clicks learn more location services, and a child account is in use"> - <ph name="BEGIN_PARAGRAPH1"><p></ph>Google's location service uses sources like Wi-Fi, mobile networks, and sensors to help estimate this device’s location.<ph name="END_PARAGRAPH1"></p></ph> - <ph name="BEGIN_PARAGRAPH2"><p></ph>You can turn off Location by turning off the main Location setting on this device. You can also turn off the use of Wi-Fi, mobile networks, and sensors for location in location settings.<ph name="END_PARAGRAPH2"></p></ph> - </message> - <message name="IDS_CROS_OPT_IN_LEARN_MORE_LOCATION_SERVICES" desc="Message shown in pop up overlay dialog when user clicks learn more location services"> - <ph name="BEGIN_PARAGRAPH1"><p></ph>When Location Accuracy is on, information about wireless signals, such as Wi-Fi access points and cellular network towers, along with device sensor data, such as accelerometer and gyroscope, is used to estimate more accurate device location, which Android apps and services use to provide location-based features. To do this, Google periodically collects information about device sensors and wireless signals near you to contribute to crowdsourced wireless signal locations.<ph name="END_PARAGRAPH1"></p></ph> - <ph name="BEGIN_PARAGRAPH2"><p></ph>Google uses this information without identifying you to: improve location accuracy and location-based services; and generally improve, provide, and maintain Google's services. We process this information based on the legitimate interests of Google and third parties to serve users' needs.<ph name="END_PARAGRAPH2"></p></ph> - <ph name="BEGIN_PARAGRAPH3"><p></ph>You can turn off Location Accuracy at any time in your device's location settings under Settings > Privacy and security > Privacy controls > Location access > Advanced location settings. If Location Accuracy is off, no Location Accuracy data will be collected. For Android apps and services, only IP address is used, if available, to determine your device's location, which may impact the availability and accuracy of locations for Android apps and services such as Google Maps.<ph name="END_PARAGRAPH3"></p></ph> - <ph name="BEGIN_PARAGRAPH4"><p></ph><ph name="LINK_BEGIN"><a id="LocationAccuracyLink" href="$1<ex>https://google.com/</ex>" target="_blank"></ph>Learn more about Location Accuracy<ph name="LINK_END"></a></ph><ph name="END_PARAGRAPH4"></p></ph> - </message> - <message name="IDS_CROS_OPT_IN_LEARN_MORE_LOCATION_SERVICES_CHILD" desc="Message shown in pop up overlay dialog when user clicks learn more location services, and a child account is in use"> - <ph name="BEGIN_PARAGRAPH1"><p></ph>When Location Accuracy is on, information about wireless signals, such as Wi-Fi access points and cellular network towers, along with device sensor data, such as accelerometer and gyroscope, is used to estimate more accurate device location, which Android apps and services use to provide location-based features. To do this, Google periodically collects information about device sensors and wireless signals near this device to contribute to crowdsourced wireless signal locations.<ph name="END_PARAGRAPH1"></p></ph> - <ph name="BEGIN_PARAGRAPH2"><p></ph>Google uses this information collected from this device to: improve location accuracy and location-based services; and generally improve, provide, and maintain Google's services. We process this information based on the legitimate interests of Google and third parties to serve users' needs. This information is not used to identify any individual.<ph name="END_PARAGRAPH2"></p></ph> - <ph name="BEGIN_PARAGRAPH3"><p></ph>You can turn off Location Accuracy at any time in this device's location settings under Settings > Privacy and security > Privacy controls > Location access > Advanced location settings. If Location Accuracy is off, no Location Accuracy data will be collected. For Android apps and services, only IP address is used, if available, to determine this device's location, which may impact the availability and accuracy of locations for Android apps and services such as Google Maps.<ph name="END_PARAGRAPH3"></p></ph> - <ph name="BEGIN_PARAGRAPH4"><p></ph><ph name="LINK_BEGIN"><a id="LocationAccuracyLink" href="$1<ex>https://google.com/</ex>" target="_blank"></ph>Learn more about Location Accuracy<ph name="LINK_END"></a></ph><ph name="END_PARAGRAPH4"></p></ph> - </message> - <message name="IDS_ARC_OPT_IN_LEARN_MORE_PAI_SERVICE_TITLE" desc="Title for pop up overlay dialog when user clicks learn more play auto install services"> - Install Updates and Apps - </message> - <message name="IDS_ARC_OPT_IN_LEARN_MORE_PAI_SERVICE" desc="Message shown in pop up overlay dialog when user clicks learn more play auto install services."> - <ph name="BEGIN_PARAGRAPH1"><p></ph>To remove apps, go to Settings > Google Play Store > Manage Android preferences > Apps or Application manager. Then tap the app you want to uninstall (you may need to swipe right or left to find the app). Then tap Uninstall or Disable.<ph name="END_PARAGRAPH1"></p></ph> - </message> - <message name="IDS_ARC_OPT_IN_CONTACT_ADMIN_TITLE" desc="Title of dialog shown when user tries to launch ARC app but ARC is diabled by admin"> - This app requires access to the Play Store - </message> - <message name="IDS_ARC_OPT_IN_CONTACT_ADMIN_CONTEXT" desc="Text of dialog shown when user tries to launch ARC app but ARC is diabled by admin"> - To ask for access, contact the administrator of this device. - </message> - <message name="IDS_ARC_OPT_IN_PRIVACY_POLICY_LINK" desc="Text of the Link to Goolge Privacy Policy in opt-in dialog"> - Google privacy policy - </message> - <message name="IDS_ARC_SIGN_IN_NETWORK_ERROR" desc="Android sign-in error because of network error"> - Network connection was lost. Check your network connection or try another Wi-Fi network. - </message> - <message name="IDS_ARC_SIGN_IN_GMS_SIGNIN_ERROR" desc="Android sign-in error because of service is unavailable"> - Couldn't connect to Google Play. Check your network connection and try again. Error code: <ph name="ERROR_CODE">$1<ex>7</ex></ph>. - </message> - <message name="IDS_ARC_SIGN_IN_BAD_AUTHENTICATION_ERROR" desc="Android sign-in error because of bad authentification"> - Couldn't verify your account. Please try again or restart your Chromebook. - </message> - <message name="IDS_ARC_SIGN_IN_GMS_CHECKIN_ERROR" desc="Android sign-in error because of GMS services are unavailable"> - Couldn't connect with Google services. Check your network connection and try again. Error code: <ph name="ERROR_CODE">$1<ex>7</ex></ph>. - </message> - <message name="IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_ACCOUNT_MISSING_ERROR" desc="Android permament sign-in error because of cloud provision flow failed"> - Provisioning failed because your account details could not be retrieved. Please try again. Error code: <ph name="ERROR_CODE">$1<ex>7</ex></ph>. - </message> - <message name="IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_DOMAIN_JOIN_FAIL_ERROR" desc="Android permament sign-in error because of cloud provision flow failed"> - Can't join the device to the domain. Please try again or contact your device owner or administrator. Error code: <ph name="ERROR_CODE">$1<ex>7</ex></ph>. - </message> - <message name="IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_ENROLLMENT_TOKEN_INVALID" desc="Android permament sign-in error because of cloud provision flow failed"> - Device enrollment token is invalid. Please contact your device owner or administrator. Error code: <ph name="ERROR_CODE">$1<ex>7</ex></ph>. - </message> - <message name="IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_INTERRUPTED_ERROR" desc="Android permament sign-in error because of cloud provision flow failed"> - Provisioning flow was interrupted. Please try again or contact your device owner or administrator. Error code: <ph name="ERROR_CODE">$1<ex>7</ex></ph>. - </message> - <message name="IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_NETWORK_ERROR" desc="Android permament sign-in error because of cloud provision flow failed"> - Couldn’t connect with the server. Check your network connection and try again. If you're still having trouble, try restarting your Chromebook. Error code: <ph name="ERROR_CODE">$1<ex>7</ex></ph>. - </message> - <message name="IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_PERMANENT_ERROR" desc="Android permament sign-in error because of cloud provision flow failed"> - Something went wrong. Please contact your device owner or administrator. Error code: <ph name="ERROR_CODE">$1<ex>7</ex></ph>. - </message> - <message name="IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_TRANSIENT_ERROR" desc="Android transient sign-in error because of cloud provision flow failed"> - Something went wrong. Please try again or contact your device owner or administrator. Error code: <ph name="ERROR_CODE">$1<ex>7</ex></ph>. - </message> - <message name="IDS_ARC_LOW_DISK_SPACE_ERROR" desc="Android sign-in failed due to low disk space"> - Disk space is critically low. Please free up disk space. - </message> - <message name="IDS_ARC_LOW_DISK_SPACE_PRE_STOP_NOTIFICATION_TITLE" desc="Title of the notification warning Android users that they are critically low on disk space"> - Device disk space critically low - </message> - <message name="IDS_ARC_LOW_DISK_SPACE_PRE_STOP_NOTIFICATION_MESSAGE" desc="Message in the notification warning Android users that they are critically low on disk space"> - Free up space to avoid losing access to Android. - </message> - <message name="IDS_ARC_LOW_DISK_SPACE_POST_STOP_NOTIFICATION_TITLE" desc="Title of the notification shown when Android is stopped due to low disk space"> - Android apps were stopped - </message> - <message name="IDS_ARC_LOW_DISK_SPACE_POST_STOP_NOTIFICATION_MESSAGE" desc="Message in the notification shown when Android is stopped due to low disk space"> - Free up disk space to launch Android apps. - </message> - <message name="IDS_ARC_SIGN_IN_UNKNOWN_ERROR" desc="Android sign-in error because of unknown error"> - Something went wrong. Error code: <ph name="ERROR_CODE">$1<ex>7</ex></ph>. - </message> - <message name="IDS_ARC_SERVER_COMMUNICATION_ERROR" desc="Android sign-in error because of server communication error"> - Couldn’t connect with the server. Check your network connection and try again. If you're still having trouble, try restarting your Chromebook. - </message> - <message name="IDS_ARC_ANDROID_MANAGEMENT_REQUIRED_ERROR" desc="Error message shown when Android management is required for an unmanaged ChromeOS user."> - Your organization has not enabled Google Play Store for your account. Contact your administrator for more information. - </message> - <message name="IDS_ARC_NETWORK_UNAVAILABLE_ERROR" desc="Error message shown when Android cannot set up network connection."> - Network connection cannot be established. Check your network connection and try again. - </message> - <message name="IDS_ARC_CRITICALLY_LOW_DISK_NOTIFICATION_TITLE" desc="Title of the notification warning users that they are critically low on disk space and Android apps can not be launched."> - Device disk space critically low - </message> - <message name="IDS_ARC_CRITICALLY_LOW_DISK_NOTIFICATION_MESSAGE" desc="Notification text warning users that they are critically low on disk space and Android apps can not be launched."> - Free up disk space to launch Android apps. - </message> - <message name="IDS_ARC_MANAGED_PROVISION_NOTIFICATION_TITLE" desc="Title of the notification shown to user during ARC provision when the ARC opt-in flow happens silently due to enterprise policies"> - Google Play Store - </message> - <message name="IDS_ARC_MANAGED_PROVISION_NOTIFICATION_MESSAGE" desc="Notification shown to user during ARC provision when the ARC opt-in flow happens silently due to enterprise policies."> - Installing the Google Play Store on your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph>. This could take a few minutes. - </message> - <message name="IDS_ARC_OOBE_TERMS_HEADING" desc="Heading of the Arc Terms OOBE dialog."> - Google Play apps and services - </message> - <message name="IDS_ARC_OOBE_TERMS_DESCRIPTION" desc="Description of the Arc Terms OOBE dialog."> - Use Google Play to install Android apps - </message> - <message name="IDS_ARC_OOBE_TERMS_POPUP_HELP_CLOSE_BUTTON" desc="Close button of the popup local help of Arc Play Store Terms OOBE dialog."> - Close - </message> - <message name="IDS_ARC_POPUP_HELP_LOADING" desc="Loading message of the Arc popup help."> - Loading... - </message> <message name="IDS_LOW_DISK_NOTIFICATION_TITLE" desc="Title of the notification warning users that they are low on disk space."> Device is low on disk space </message> @@ -3746,45 +3497,6 @@ <message name="IDS_HATS_DONE_BUTTON_LABEL" desc="Label used for the done button at the end of survey"> Done </message> - <message name="IDS_ARC_CHILD_TRANSITION_TITLE" desc="Title of the notification shown when the user tries to activate ARC app and transition from child to regular user or from regular to child user is not completed."> - Action not available - </message> - <message name="IDS_ARC_CHILD_TRANSITION_MESSAGE" desc="Message of the notification shown when the user tries to activate ARC app and transition from child to regular user or from regular to child user is not completed."> - Please try again in a few moments - </message> - <message name="IDS_ARC_DATA_REMOVAL_CONFIRMATION_HEADING" desc="Heading text in the content area of the confirmation for data removal in case ARC comes to wrong state."> - To use apps from Google Play, you must first restore your apps. Some data may have been lost. - </message> - <message name="IDS_ARC_DATA_REMOVAL_CONFIRMATION_OK_BUTTON" desc="Text for the OK button of the confirmation for data removal in case ARC comes to wrong state."> - Restore apps - </message> - <message name="IDS_ARC_DATA_REMOVAL_CONFIRMATION_TITLE" desc="Title of the confirmation for data removal in case in case ARC comes to wrong state."> - Something went wrong - </message> - <message name="IDS_ARC_MIGRATE_ENCRYPTION_NOTIFICATION_TITLE" desc="Title of the notification to navigate the user to first update the device encryption before running Android apps."> - Install critical update - </message> - <message name="IDS_ARC_MIGRATE_ENCRYPTION_NOTIFICATION_MESSAGE" desc="Main message of the notification to navigate the user to first update the device encryption before running Android apps."> - To use Android apps and keep your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph> working properly, sign in again and update. - </message> - <message name="IDS_ARC_MIGRATE_ENCRYPTION_NOTIFICATION_LOW_BATTERY_MESSAGE" desc="Main message of the notification to navigate the user to first update the device encryption before running Android apps."> - To use Android apps, charge & update your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph>. - </message> - <message name="IDS_ARC_USB_PERMISSION_TITLE" desc="Titlebar of Android app USB permissions prompt window"> - Confirm USB Permission - </message> - <message name="IDS_ARC_USB_SCAN_DEVICE_LIST_PERMISSION_HEADING" desc="Heading text in the content area of the Android app scan device list permission prompt. Tells the user the app will be able to scan attached USB device list if confirmed."> - Allow "<ph name="APP_NAME">$1<ex>Gmail Checker</ex></ph>" to get the list of your attached USB devices? - </message> - <message name="IDS_ARC_USB_ACCESS_PERMISSION_HEADING" desc="Heading text in the content area of the Android app USB device access permission prompt. Tells the user the app will be able to access the usb device if confirmed."> - Allow "<ph name="APP_NAME">$1<ex>Gmail Checker</ex></ph>" to access: - </message> - <message name="IDS_ARC_ACCESSIBILITY_SELECTED_STATUS" desc="Text used by screen readers that represents that the element is selected."> - Selected - </message> - <message name="IDS_ARC_ACCESSIBILITY_WINDOW_TITLE_IN_PIP" is_accessibility_with_no_ui="true" desc="A hint text that is read by screen readers appended to the window title, explaning that the window is in the picture-pi-picture mode."> - Picture in picture - </message> <message name="IDS_WAIT_FOR_CONTAINER_READY_INTRO_MESSAGE" desc="Introduction message for the wait for container ready OOBE screen"> Ask it questions. Tell it to do things. It's your personal Google, always ready to help. </message> @@ -5404,18 +5116,6 @@ </message> <!-- Strings for EDU Coexistence flow --> - <message name="IDS_EDU_COEXISTENCE_NETWORK_DOWN_HEADING" desc="Heading string shown in the EDU Coexistence flow when the network is not available."> - Can’t connect to the internet - </message> - <message name="IDS_EDU_COEXISTENCE_NETWORK_DOWN_DESCRIPTION" desc="Description shown in the EDU Coexistence flow when the network is not available."> - Check your internet connection - </message> - <message name="IDS_EDU_COEXISTENCE_ERROR_HEADING" desc="Heading string shown in the EDU Coexistence flow when an unrecoverable error occured."> - An error occurred - </message> - <message name="IDS_EDU_COEXISTENCE_ERROR_DESCRIPTION" desc="Description shown in the EDU Coexistence flow when an unrecoverable error occured."> - Please try again later - </message> <!-- Strings for Add Supervision screen --> <message name="IDS_ADD_SUPERVISION_PAGE_TITLE" desc="Title for the ChromeOS Add Supervision screen. Since the title bar is not visible, this string is only used by screen readers.">
diff --git a/chrome/app/chromeos_strings_grdp/IDS_EDU_COEXISTENCE_ERROR_DESCRIPTION.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_EDU_COEXISTENCE_ERROR_DESCRIPTION.png.sha1 deleted file mode 100644 index f74cc57..0000000 --- a/chrome/app/chromeos_strings_grdp/IDS_EDU_COEXISTENCE_ERROR_DESCRIPTION.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -fe5b179467573c349c9103c6ea2c039e63bac5e5 \ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_EDU_COEXISTENCE_ERROR_HEADING.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_EDU_COEXISTENCE_ERROR_HEADING.png.sha1 deleted file mode 100644 index f74cc57..0000000 --- a/chrome/app/chromeos_strings_grdp/IDS_EDU_COEXISTENCE_ERROR_HEADING.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -fe5b179467573c349c9103c6ea2c039e63bac5e5 \ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_EDU_COEXISTENCE_NETWORK_DOWN_DESCRIPTION.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_EDU_COEXISTENCE_NETWORK_DOWN_DESCRIPTION.png.sha1 deleted file mode 100644 index 36ed4cb1..0000000 --- a/chrome/app/chromeos_strings_grdp/IDS_EDU_COEXISTENCE_NETWORK_DOWN_DESCRIPTION.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -17d93a5572f7e0a928b6a620c972d5916cb3617b \ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_EDU_COEXISTENCE_NETWORK_DOWN_HEADING.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_EDU_COEXISTENCE_NETWORK_DOWN_HEADING.png.sha1 deleted file mode 100644 index 36ed4cb1..0000000 --- a/chrome/app/chromeos_strings_grdp/IDS_EDU_COEXISTENCE_NETWORK_DOWN_HEADING.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -17d93a5572f7e0a928b6a620c972d5916cb3617b \ No newline at end of file
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 86e482a..a03a2a204 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -7383,6 +7383,10 @@ You are using an unsupported feature flag: <ph name="BAD_FLAG">$1<ex>SignedHTTPExchange</ex></ph>. Stability and security will suffer. </message> + <message name="IDS_BAD_FLAGS_FROM_FILE_WARNING_MESSAGE" desc="Message shown when command-line flags are loaded from a file. [Keep it short so it fits in the infobar.]"> + Chrome is loading flags from a command-line file. Stability and security may be affected. + </message> + <!-- Bad Environment Variables Infobar--> <message name="IDS_BAD_ENVIRONMENT_VARIABLES_WARNING_MESSAGE" desc="Message shown when an unsupported environment variable is used [Keep it short so it fits in the infobar.]"> You are using an unsupported environment variable: <ph name="BAD_VAR">$1<ex>SSLKEYLOGFILE</ex></ph>. Stability and security will suffer.
diff --git a/chrome/app/generated_resources_grd/IDS_BAD_FLAGS_FROM_FILE_WARNING_MESSAGE.png.sha1 b/chrome/app/generated_resources_grd/IDS_BAD_FLAGS_FROM_FILE_WARNING_MESSAGE.png.sha1 new file mode 100644 index 0000000..2bf18f0 --- /dev/null +++ b/chrome/app/generated_resources_grd/IDS_BAD_FLAGS_FROM_FILE_WARNING_MESSAGE.png.sha1
@@ -0,0 +1 @@ +e9dc0c968f88073964ad5bc2e3e83681fe0e2139 \ No newline at end of file
diff --git a/chrome/app/profiles_strings.grdp b/chrome/app/profiles_strings.grdp index 0559b65..772c7762 100644 --- a/chrome/app/profiles_strings.grdp +++ b/chrome/app/profiles_strings.grdp
@@ -854,6 +854,14 @@ You currently have <ph name="NUMBERED_ITEM">$1<ex>10 bookmarks</ex></ph>, and more. Your organization, <ph name="ACCOUNT_MANAGER">$2<ex>example.com</ex></ph>, will be able to see and manage this data. </message> + <!--Accessible strings--> + <message name="IDS_ACCNAME_YOUR_AVATAR" desc="The accessible name for the user's avatar"> + Your avatar + </message> + <message name="IDS_ACCNAME_ENTERPRISE_ORGANIZATION_ICON" desc="The accessible name for the icon which indicates that the profile is managed by an organization"> + An icon indicating that this profile is managed by your organization + </message> + <!-- Supervised user profile signin IPH --> <message name="IDS_SUPERVISED_USER_PROFILE_SIGNIN_IPH_TITLE" desc="Title of a reminder message, which is intended to help supervised users understand that they have been signed in to Chrome."> Welcome, <ph name="CHILD_NAME">$1<ex>Charlie</ex></ph>
diff --git a/chrome/app/profiles_strings_grdp/IDS_ACCNAME_ENTERPRISE_ORGANIZATION_ICON.png.sha1 b/chrome/app/profiles_strings_grdp/IDS_ACCNAME_ENTERPRISE_ORGANIZATION_ICON.png.sha1 new file mode 100644 index 0000000..762010a --- /dev/null +++ b/chrome/app/profiles_strings_grdp/IDS_ACCNAME_ENTERPRISE_ORGANIZATION_ICON.png.sha1
@@ -0,0 +1 @@ +edae36f6084c8d99e0095a7245cfa9341e8e0c88 \ No newline at end of file
diff --git a/chrome/app/profiles_strings_grdp/IDS_ACCNAME_YOUR_AVATAR.png.sha1 b/chrome/app/profiles_strings_grdp/IDS_ACCNAME_YOUR_AVATAR.png.sha1 new file mode 100644 index 0000000..37adb6fe --- /dev/null +++ b/chrome/app/profiles_strings_grdp/IDS_ACCNAME_YOUR_AVATAR.png.sha1
@@ -0,0 +1 @@ +e8b42832e2991d4310e46c421a9ad8afb5068c8e \ No newline at end of file
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp index d9e3f457..94cd45c 100644 --- a/chrome/app/settings_strings.grdp +++ b/chrome/app/settings_strings.grdp
@@ -4136,6 +4136,14 @@ <message name="IDS_SETTINGS_SYSTEM_HARDWARE_ACCELERATION_LABEL" desc="Label for the checkbox that forces Chrome to render via graphics acceleration (GPU) when available."> Use graphics acceleration when available </message> + <if expr="is_win"> + <message name="IDS_SETTINGS_SYSTEM_ISOLATION_STATE_LABEL" desc="Label for the Enable process isolation toggle."> + Enable Process Isolation + </message> + <message name="IDS_SETTINGS_SYSTEM_ISOLATION_STATE_SUBLABEL" desc="Sublabel for the Enable process isolation toggle."> + Process Isolation prevents other applications from tampering with <ph name="IDS_SHORT_PRODUCT_NAME">$1<ex>Chrome</ex></ph>. + </message> + </if> <message name="IDS_SETTINGS_SYSTEM_FEATURE_NOTIFICATIONS_LABEL" desc="Label for the toggle that enables Chrome system notifications about features."> Show system notifications about Chrome features and tips </message>
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SYSTEM_ISOLATION_STATE_LABEL.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_SYSTEM_ISOLATION_STATE_LABEL.png.sha1 new file mode 100644 index 0000000..3741d71d --- /dev/null +++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_SYSTEM_ISOLATION_STATE_LABEL.png.sha1
@@ -0,0 +1 @@ +39eaea221ed64eb160acd692fbf6639217a4e713 \ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SYSTEM_ISOLATION_STATE_SUBLABEL.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_SYSTEM_ISOLATION_STATE_SUBLABEL.png.sha1 new file mode 100644 index 0000000..3741d71d --- /dev/null +++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_SYSTEM_ISOLATION_STATE_SUBLABEL.png.sha1
@@ -0,0 +1 @@ +39eaea221ed64eb160acd692fbf6639217a4e713 \ No newline at end of file
diff --git a/chrome/app_shim/app_shim_application.mm b/chrome/app_shim/app_shim_application.mm index 319232f..98bf450 100644 --- a/chrome/app_shim/app_shim_application.mm +++ b/chrome/app_shim/app_shim_application.mm
@@ -8,6 +8,9 @@ #include "chrome/app_shim/app_shim_delegate.h" #include "chrome/common/mac/app_shim.mojom.h" +// https://crbug.com/491147240: Clean up code that is duplicate here and in +// chrome/browser/chrome_browser_application_mac.mm. + @implementation AppShimApplication { BOOL _handlingSendEvent; }
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 37c172e..cf714e1a 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -472,8 +472,6 @@ "icon_loader.h", "icon_manager.cc", "icon_manager.h", - "idle/idle_detection_permission_context.cc", - "idle/idle_detection_permission_context.h", "language/accept_languages_service_factory.cc", "language/accept_languages_service_factory.h", "language/language_model_manager_factory.cc", @@ -1202,12 +1200,6 @@ "supervised_user/supervised_user_service_factory.h", "supervised_user/supervised_user_url_filtering_service_factory.cc", "supervised_user/supervised_user_url_filtering_service_factory.h", - "tab_contents/navigation_metrics_recorder.cc", - "tab_contents/navigation_metrics_recorder.h", - "tab_contents/tab_util.cc", - "tab_contents/tab_util.h", - "tab_contents/web_contents_collection.cc", - "tab_contents/web_contents_collection.h", "tab_group_sync/tab_group_sync_tab_state.cc", "tab_group_sync/tab_group_sync_tab_state.h", "tab_group_sync/tab_group_sync_utils.cc", @@ -1233,8 +1225,6 @@ "unexpire_flags.h", "universal_web_contents_observers.cc", "universal_web_contents_observers.h", - "visibility_timer_tab_helper.cc", - "visibility_timer_tab_helper.h", "webauthn/credential_sorter.h", "webauthn/password_credential_fetcher.cc", "webauthn/password_credential_fetcher.h", @@ -1503,6 +1493,7 @@ "//chrome/browser/interstitials", "//chrome/browser/obsolete_system", "//chrome/browser/profiles", + "//chrome/browser/tab_contents", "//chrome/browser/ui/tabs:tab_enums", ] @@ -1639,6 +1630,7 @@ "//chrome/browser/history_clusters", "//chrome/browser/history_clusters:impl", "//chrome/browser/history_embeddings:impl", + "//chrome/browser/idle", "//chrome/browser/image_decoder", "//chrome/browser/image_fetcher", "//chrome/browser/interstitials:impl", @@ -1768,6 +1760,7 @@ "//chrome/browser/strike_database", "//chrome/browser/subscription_eligibility", "//chrome/browser/sync", + "//chrome/browser/tab_contents:impl", "//chrome/browser/tab_group_sync:factories", "//chrome/browser/tab_group_sync:factories_impl", "//chrome/browser/tab_group_sync:utils", @@ -1861,6 +1854,7 @@ "//components/page_content_annotations/core", "//components/supervised_user/core/browser:device_parental_controls", "//components/supervised_user/core/browser:synthetic_field_trial_delegate", + "//components/visibility_timer", # TODO(crbug.com/369436587): Remove this dependency when # c/b/policy/configuration_policy_handler_list_factory.cc gets modularized. @@ -3069,9 +3063,6 @@ "tab_group_sync/android/tab_group_sync_utils_android.cc", "translate/android/translate_bridge.cc", "translate/android/translate_bridge.h", - "wallet/android/boarding_pass_bridge.cc", - "wallet/android/boarding_pass_detector.cc", - "wallet/android/boarding_pass_detector.h", "webauthn/android/cable_module_android.cc", "webauthn/android/cable_registration_state.cc", "webauthn/android/cable_registration_state.h", @@ -3227,10 +3218,9 @@ "//chrome/browser/ui/plus_addresses", "//chrome/browser/ui/webui/notifications_internals", "//chrome/browser/ui/webui/notifications_internals:impl", - "//chrome/browser/wallet/android:jni_headers", + "//chrome/browser/wallet/android:wallet_android", "//chrome/browser/webapps:android", "//chrome/common:non_code_constants", - "//chrome/common/wallet:mojo_bindings", "//chrome/services/media_gallery_util/public/cpp", "//components/android_autofill/browser:android", "//components/android_autofill/browser:features", @@ -3947,8 +3937,6 @@ "support_tool/support_tool_util.h", "support_tool/system_log_source_data_collector_adaptor.cc", "support_tool/system_log_source_data_collector_adaptor.h", - "tab_contents/form_interaction_tab_helper.cc", - "tab_contents/form_interaction_tab_helper.h", "webauthn/authenticator_list_observer.h", "webauthn/authenticator_reference.cc", "webauthn/authenticator_reference.h", @@ -4133,6 +4121,7 @@ "//chrome/browser/ui/views/toolbar:impl", "//chrome/browser/ui/views/zoom:impl", "//chrome/browser/ui/waap", + "//chrome/browser/ui/waap:manager", "//chrome/browser/ui/waap:waap_utils", "//chrome/browser/ui/waap:window_metrics_manager", "//chrome/browser/ui/web_applications:impl", @@ -4143,6 +4132,7 @@ "//chrome/browser/ui/webui/color_pipeline_internals", "//chrome/browser/ui/webui/commerce", "//chrome/browser/ui/webui/commerce:impl", + "//chrome/browser/ui/webui/content_annotator_internals", "//chrome/browser/ui/webui/cr_components/searchbox:searchbox_impl", "//chrome/browser/ui/webui/cr_components/theme_color_picker", "//chrome/browser/ui/webui/customize_buttons", @@ -8431,6 +8421,7 @@ "//chrome/browser/ui/webui/whats_new:mojo_bindings", "//chrome/browser/ui/webui_browser:browser_mojo_bindings", "//chrome/browser/webauthn/proto", + "//components/accessibility_annotator/core/logging:mojo_bindings", "//components/autofill/core/browser/ml_model/logging:mojo_bindings", "//components/browser_apis/tab_strip:mojom", ]
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS index 4b7ec7e4..a07a547 100644 --- a/chrome/browser/DEPS +++ b/chrome/browser/DEPS
@@ -41,6 +41,7 @@ "+chromeos", "+components/access_code_cast", "+components/private_ai", + "+components/accessibility_annotator/core", "+components/account_id", "+components/account_manager_core", "+components/activity_reporter", @@ -395,6 +396,7 @@ "+components/vector_icons", "+components/version_info", "+components/visited_url_ranking", + "+components/visibility_timer", "+components/viz/common", "+components/viz/host", "+components/wallet/core/common",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 303c10e..c3af38c 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -262,7 +262,6 @@ #include "ui/gl/gl_features.h" #include "ui/gl/gl_switches.h" #include "ui/native_theme/features/native_theme_features.h" -#include "ui/ui_features.h" #include "url/url_features.h" #if BUILDFLAG(IS_ANDROID) @@ -514,18 +513,6 @@ gl::kANGLEImplementationVulkanName}}; #endif -#if BUILDFLAG(ENABLE_EXTENSIONS) -const FeatureEntry::Choice kExtensionsToolbarZeroStateChoices[] = { - {flag_descriptions::kExtensionsToolbarZeroStateChoicesDisabled, "", ""}, - {flag_descriptions::kExtensionsToolbarZeroStateVistWebStore, - switches::kExtensionsToolbarZeroStateVariation, - switches::kExtensionsToolbarZeroStateSingleWebStoreLink}, - {flag_descriptions::kExtensionsToolbarZeroStateExploreExtensionsByCategory, - switches::kExtensionsToolbarZeroStateVariation, - switches::kExtensionsToolbarZeroStateExploreExtensionsByCategory}, -}; -#endif // ENABLE_EXTENSIONS - #if BUILDFLAG(IS_WIN) const FeatureEntry::FeatureParam kDXGIWaitableSwapChain1Frame[] = { {"DXGIWaitableSwapChainMaxQueuedFrames", "1"}}; @@ -5554,6 +5541,12 @@ flag_descriptions::kEnableIsolatedWebAppDevModeName, flag_descriptions::kEnableIsolatedWebAppDevModeDescription, kOsDesktop, FEATURE_VALUE_TYPE(features::kIsolatedWebAppDevMode)}, +#if BUILDFLAG(IS_WIN) + {"enable-process-isolation-ui", + flag_descriptions::kEnableProcessIsolationUiName, + flag_descriptions::kEnableProcessIsolationUiDescription, kOsWin, + FEATURE_VALUE_TYPE(features::kProcessIsolationSettings)}, +#endif // BUILDFLAG(IS_WIN) #if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) {"enable-iwa-key-distribution-component", flag_descriptions::kEnableIwaKeyDistributionComponentName, @@ -5819,9 +5812,6 @@ flag_descriptions::kOpenXRAndroidSmoothDepthName, flag_descriptions::kOpenXRAndroidSmoothDepthDescription, kOsAndroid, FEATURE_VALUE_TYPE(device::features::kOpenXR)}, - {"enable-openxr-extended", flag_descriptions::kOpenXRExtendedFeaturesName, - flag_descriptions::kOpenXRExtendedFeaturesDescription, kOsAndroid, - FEATURE_VALUE_TYPE(device::features::kOpenXrExtendedFeatureSupport)}, #endif // BUILDFLAG(IS_ANDROID) && BUILDFLAG(ENABLE_OPENXR) #endif // ENABLE_VR #if BUILDFLAG(IS_CHROMEOS) @@ -7206,6 +7196,13 @@ FEATURE_WITH_PARAMS_VALUE_TYPE(ntp_features::kNtpMiddleSlotPromoDismissal, kNtpMiddleSlotPromoDismissalVariations, "DesktopNtpModules")}, + {"ntp-animated-doodles", flag_descriptions::kNtpAnimatedDoodlesName, + flag_descriptions::kNtpAnimatedDoodlesDescription, kOsDesktop, + FEATURE_VALUE_TYPE(ntp_features::kNtpAnimatedDoodles)}, + + {"ntp-doodle-murals", flag_descriptions::kNtpDoodleMuralsName, + flag_descriptions::kNtpDoodleMuralsDescription, kOsDesktop, + FEATURE_VALUE_TYPE(ntp_features::kNtpDoodleMurals)}, {"ntp-module-sign-in-requirement", flag_descriptions::kNtpModuleSignInRequirementName, @@ -9017,11 +9014,6 @@ flag_descriptions::kExtensionsMenuAccessControlDescription, kOsDesktop, FEATURE_VALUE_TYPE(extensions_features::kExtensionsMenuAccessControl)}, - {"extensions-toolbar-zero-state-variation", - flag_descriptions::kExtensionsToolbarZeroStateName, - flag_descriptions::kExtensionsToolbarZeroStateDescription, kOsDesktop, - MULTI_VALUE_TYPE(kExtensionsToolbarZeroStateChoices)}, - {"iph-extensions-menu-feature", flag_descriptions::kIPHExtensionsMenuFeatureName, flag_descriptions::kIPHExtensionsMenuFeatureDescription, kOsDesktop, @@ -13099,6 +13091,13 @@ flag_descriptions::kApb144Patch3Description, kOsAndroid, FEATURE_VALUE_TYPE(chrome::android::kApb144Patch3)}, #endif + +#if BUILDFLAG(IS_ANDROID) + {"enable-three-dot-menu-back-button", + flag_descriptions::kThreeDotMenuBackButtonName, + flag_descriptions::kThreeDotMenuBackButtonDescription, kOsAndroid, + FEATURE_VALUE_TYPE(chrome::android::kThreeDotMenuBackButton)}, +#endif // Add new entries above this line. // NOTE: Adding a new flag requires adding a corresponding entry to enum // "LoginCustomFlags" in tools/metrics/histograms/enums.xml. See "Flag
diff --git a/chrome/browser/accessibility/live_caption/live_caption_test_util.cc b/chrome/browser/accessibility/live_caption/live_caption_test_util.cc index ea98cc02..33184fc 100644 --- a/chrome/browser/accessibility/live_caption/live_caption_test_util.cc +++ b/chrome/browser/accessibility/live_caption/live_caption_test_util.cc
@@ -27,7 +27,7 @@ // Chrome feature flags that gate Live Caption. std::vector<base::test::FeatureRef> RequiredFeatureFlags() { std::vector<base::test::FeatureRef> features = { - media::kLiveTranslate, media::kFeatureManagementLiveTranslateCrOS}; + media::kFeatureManagementLiveTranslateCrOS}; #if BUILDFLAG(IS_CHROMEOS) features.push_back(ash::features::kOnDeviceSpeechRecognition); #endif
diff --git a/chrome/browser/accessibility/live_translate_controller_browsertest.cc b/chrome/browser/accessibility/live_translate_controller_browsertest.cc index e232ef6..fb2d2ba 100644 --- a/chrome/browser/accessibility/live_translate_controller_browsertest.cc +++ b/chrome/browser/accessibility/live_translate_controller_browsertest.cc
@@ -27,8 +27,7 @@ void SetUp() override { scoped_feature_list_.InitWithFeatures( - {media::kLiveTranslate, media::kFeatureManagementLiveTranslateCrOS}, - {}); + {media::kFeatureManagementLiveTranslateCrOS}, {}); InProcessBrowserTest::SetUp(); }
diff --git a/chrome/browser/actor/actor_switches.cc b/chrome/browser/actor/actor_switches.cc index ee8d8a5f..455995b4 100644 --- a/chrome/browser/actor/actor_switches.cc +++ b/chrome/browser/actor/actor_switches.cc
@@ -17,4 +17,8 @@ const char kAttemptFormFillingToolSkipsUI[] = "attempt-form-filling-tool-skips-ui"; +// Forces logging of the actor aggregated journal events in VLOG(1). Useful on +// Android as VLOGs are removed on official builds. +const char kEnableActorJournalVLog[] = "enable-actor-journal-vlog"; + } // namespace actor::switches
diff --git a/chrome/browser/actor/actor_switches.h b/chrome/browser/actor/actor_switches.h index 1e1189be..eec4486d 100644 --- a/chrome/browser/actor/actor_switches.h +++ b/chrome/browser/actor/actor_switches.h
@@ -9,6 +9,7 @@ extern const char kDisableActorSafetyChecks[]; extern const char kAttemptFormFillingToolSkipsUI[]; +extern const char kEnableActorJournalVLog[]; } // namespace actor::switches
diff --git a/chrome/browser/actor/aggregated_journal.cc b/chrome/browser/actor/aggregated_journal.cc index 4cce73ca..3a1dbab5 100644 --- a/chrome/browser/actor/aggregated_journal.cc +++ b/chrome/browser/actor/aggregated_journal.cc
@@ -4,9 +4,11 @@ #include "chrome/browser/actor/aggregated_journal.h" +#include "base/command_line.h" #include "base/memory/safe_ref.h" #include "base/rand_util.h" #include "base/types/pass_key.h" +#include "chrome/browser/actor/actor_switches.h" #include "chrome/browser/profiles/profile.h" #include "chrome/common/actor/actor_logging.h" #include "chrome/common/actor/journal_details_builder.h" @@ -24,6 +26,12 @@ namespace { +bool ShouldLogJournal() { + static bool enabled = base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableActorJournalVLog); + return enabled || VLOG_IS_ON(1); +} + class NonTerminatedJournalEntries : public content::DocumentUserData<NonTerminatedJournalEntries> { public: @@ -124,6 +132,14 @@ } // namespace +// Redefine ACTOR_LOG here to enable gathering logs from this file with the +// --enable-actor-journal-vlog flag, this is done because the default +// implementation on official Android builds removes all VLOGs. Limited to this +// file to minimize binary size impact. +#undef ACTOR_LOG +#define ACTOR_LOG() \ + LAZY_STREAM(VLOG_STREAM(1), ShouldLogJournal()) << "[ActorTool]: " + AggregatedJournal::Entry::Entry(const std::string& location, mojom::JournalEntryPtr data_arg) : url(location), data(std::move(data_arg)) {}
diff --git a/chrome/browser/ai/ai_proofreader.cc b/chrome/browser/ai/ai_proofreader.cc index a6298e08..59e3d282 100644 --- a/chrome/browser/ai/ai_proofreader.cc +++ b/chrome/browser/ai/ai_proofreader.cc
@@ -39,7 +39,7 @@ blink::mojom::AIProofreaderCreateOptionsPtr options, mojo::PendingReceiver<blink::mojom::AIProofreader> receiver) : AIContextBoundObject(context_bound_object_set), - session_(std::move(session)), + session_wrapper_(std::move(session)), receiver_(this, std::move(receiver)), options_(std::move(options)) { receiver_.set_disconnect_handler(base::BindOnce( @@ -86,8 +86,9 @@ } void AIProofreader::SetPriority(on_device_model::mojom::Priority priority) { - if (session_) { - session_->SetPriority(priority); + auto* session = session_wrapper_.session(); + if (session) { + session->SetPriority(priority); } } @@ -97,7 +98,8 @@ const std::string& correction_instruction, mojo::PendingRemote<blink::mojom::ModelStreamingResponder> pending_responder) { - if (!session_) { + auto* session = session_wrapper_.session(); + if (!session) { mojo::Remote<blink::mojom::ModelStreamingResponder> responder( std::move(pending_responder)); on_device_ai::SendStreamingStatus( @@ -110,7 +112,7 @@ responder_set_.Add(std::move(pending_responder)); auto request = BuildRequest(input, corrected_input, correction_instruction); - session_->GetExecutionInputSizeInTokens( + session->GetExecutionInputSizeInTokens( optimization_guide::MultimodalMessageReadView(request), base::BindOnce(&AIProofreader::DidGetExecutionInputSizeForProofread, weak_ptr_factory_.GetWeakPtr(), responder_id, request)); @@ -128,7 +130,7 @@ return; } - if (!session_) { + if (!session_wrapper_.session()) { on_device_ai::SendStreamingStatus( responder, blink::mojom::ModelStreamingResponseStatus::kErrorSessionDestroyed); @@ -151,8 +153,8 @@ return; } - session_->ExecuteModel( - request, + session_wrapper_.ExecuteModelOrQueue( + optimization_guide::MultimodalMessage(request), base::BindRepeating(&AIProofreader::ModelExecutionCallback, weak_ptr_factory_.GetWeakPtr(), responder_id)); }
diff --git a/chrome/browser/ai/ai_proofreader.h b/chrome/browser/ai/ai_proofreader.h index feb698d..985e148 100644 --- a/chrome/browser/ai/ai_proofreader.h +++ b/chrome/browser/ai/ai_proofreader.h
@@ -11,6 +11,7 @@ #include "base/containers/flat_set.h" #include "base/memory/weak_ptr.h" #include "chrome/browser/ai/ai_context_bound_object.h" +#include "chrome/browser/ai/ai_on_device_session.h" #include "components/optimization_guide/core/model_execution/on_device_capability.h" #include "components/optimization_guide/proto/features/proofreader_api.pb.h" #include "mojo/public/cpp/bindings/pending_remote.h" @@ -86,8 +87,7 @@ const std::string& correction_instruction); // The underlying session provided by optimization guide component. - std::unique_ptr<optimization_guide::OnDeviceSession> session_; - mojo::Remote<blink::mojom::AIProofreader> remote_; + AIOnDeviceSession session_wrapper_; // The `RemoteSet` storing all the responders, each of them corresponds to one // `Proofread()` call. mojo::RemoteSet<blink::mojom::ModelStreamingResponder> responder_set_;
diff --git a/chrome/browser/apps/app_discovery_service/recommended_arc_apps/recommend_apps_fetcher_impl_unittest.cc b/chrome/browser/apps/app_discovery_service/recommended_arc_apps/recommend_apps_fetcher_impl_unittest.cc index 5cf4f82e..b8867d3 100644 --- a/chrome/browser/apps/app_discovery_service/recommended_arc_apps/recommend_apps_fetcher_impl_unittest.cc +++ b/chrome/browser/apps/app_discovery_service/recommended_arc_apps/recommend_apps_fetcher_impl_unittest.cc
@@ -95,11 +95,9 @@ // ash::CrosDisplayConfig: void AddObserver(Observer* observer) override {} void RemoveObserver(Observer* observer) override {} - crosapi::mojom::DisplayLayoutInfoPtr GetDisplayLayoutInfo() override { - NOTREACHED(); - } - crosapi::mojom::DisplayConfigResult SetDisplayLayoutInfo( - crosapi::mojom::DisplayLayoutInfoPtr info) override { + ash::DisplayLayoutInfo GetDisplayLayoutInfo() override { NOTREACHED(); } + ash::DisplayConfigResult SetDisplayLayoutInfo( + const ash::DisplayLayoutInfo& info) override { NOTREACHED(); } std::vector<crosapi::mojom::DisplayUnitInfoPtr> GetDisplayUnitInfoList( @@ -108,23 +106,26 @@ next_display_unit_info_list_.clear(); return result; } - crosapi::mojom::DisplayConfigResult SetDisplayProperties( + ash::DisplayConfigResult SetDisplayProperties( const std::string& id, - crosapi::mojom::DisplayConfigPropertiesPtr properties, + const ash::DisplayConfigProperties& properties, crosapi::mojom::DisplayConfigSource source) override { NOTREACHED(); } void SetUnifiedDesktopEnabled(bool enabled) override {} - crosapi::mojom::DisplayConfigResult OverscanCalibration( + ash::DisplayConfigResult OverscanCalibration( const std::string& display_id, crosapi::mojom::DisplayConfigOperation op, const std::optional<gfx::Insets>& delta) override { NOTREACHED(); } - void TouchCalibration(const std::string& display_id, - crosapi::mojom::DisplayConfigOperation op, - crosapi::mojom::TouchCalibrationPtr calibration, - TouchCalibrationCallback callback) override {} + void TouchCalibration( + const std::string& display_id, + crosapi::mojom::DisplayConfigOperation op, + base::optional_ref<const display::TouchCalibrationData> calibration, + TouchCalibrationCallback callback) override { + NOTREACHED(); + } void HighlightDisplay(int64_t id) override {} void DragDisplayDelta(int64_t display_id, int32_t delta_x,
diff --git a/chrome/browser/ash/accessibility/accessibility_event_rewriter_delegate_impl.cc b/chrome/browser/ash/accessibility/accessibility_event_rewriter_delegate_impl.cc index 35491092..1cb985c 100644 --- a/chrome/browser/ash/accessibility/accessibility_event_rewriter_delegate_impl.cc +++ b/chrome/browser/ash/accessibility/accessibility_event_rewriter_delegate_impl.cc
@@ -96,7 +96,7 @@ ForwardKeyToExtension(*(event->AsKeyEvent()), host); } -void AccessibilityEventRewriterDelegateImpl::DispatchKeyEventToChromeVoxMv3( +bool AccessibilityEventRewriterDelegateImpl::DispatchKeyEventToChromeVoxMv3( unsigned int id, std::unique_ptr<ui::Event> event) { CHECK(::features::IsAccessibilityManifestV3EnabledForChromeVox()); @@ -106,8 +106,9 @@ // switching profiles. See b:458302114. // AccessibilityManager is the source of truth for whether Spoken Feedback // is enabled since it handles loading/unloading. - return; + return false; } + CHECK(event->IsKeyEvent()); extensions::EventRouter* event_router = extensions::EventRouter::Get(AccessibilityManager::Get()->profile()); @@ -115,6 +116,17 @@ // Transform the ui::KeyEvent into an accessibility_private::KeyboardEvent. const ui::KeyEvent* key_event = event->AsKeyEvent(); + bool is_pressed = key_event->type() == ui::EventType::kKeyPressed; + + if (!event_router->HasEventListener( + is_pressed + ? extensions::api::accessibility_private::OnKeyDown::kEventName + : extensions::api::accessibility_private::OnKeyUp::kEventName)) { + // In the event the service worker has crashed and there is no longer a + // listener, do not try to dispatch the event. + return false; + } + extensions::api::accessibility_private::KeyboardEvent keyboard_event; keyboard_event.id = id; keyboard_event.alt_key = key_event->IsAltDown(); @@ -132,7 +144,7 @@ base::ListValue event_args; event_args.Append(keyboard_event.ToValue()); std::unique_ptr<extensions::Event> extension_event; - if (key_event->type() == ui::EventType::kKeyPressed) { + if (is_pressed) { extension_event = std::make_unique<extensions::Event>( extensions::events::ACCESSIBILITY_PRIVATE_ON_KEY_DOWN, extensions::api::accessibility_private::OnKeyDown::kEventName, @@ -144,8 +156,10 @@ std::move(event_args)); } - event_router->DispatchEventWithLazyListener( - extension_misc::kChromeVoxExtensionId, std::move(extension_event)); + event_router->DispatchEventToExtension(extension_misc::kChromeVoxExtensionId, + std::move(extension_event)); + + return true; } void AccessibilityEventRewriterDelegateImpl::DispatchMouseEvent(
diff --git a/chrome/browser/ash/accessibility/accessibility_event_rewriter_delegate_impl.h b/chrome/browser/ash/accessibility/accessibility_event_rewriter_delegate_impl.h index 188fd2b..4d31e4e 100644 --- a/chrome/browser/ash/accessibility/accessibility_event_rewriter_delegate_impl.h +++ b/chrome/browser/ash/accessibility/accessibility_event_rewriter_delegate_impl.h
@@ -32,7 +32,7 @@ // AccessibilityEventRewriterDelegate: void DispatchKeyEventToChromeVox(std::unique_ptr<ui::Event> event, bool capture) override; - void DispatchKeyEventToChromeVoxMv3( + bool DispatchKeyEventToChromeVoxMv3( unsigned int id, std::unique_ptr<ui::Event> event) override; void DispatchMouseEvent(std::unique_ptr<ui::Event> event) override;
diff --git a/chrome/browser/ash/app_list/arc/BUILD.gn b/chrome/browser/ash/app_list/arc/BUILD.gn index dc1fb96..007dd61 100644 --- a/chrome/browser/ash/app_list/arc/BUILD.gn +++ b/chrome/browser/ash/app_list/arc/BUILD.gn
@@ -63,6 +63,7 @@ deps = [ "//ash", "//ash/constants", + "//ash/strings", "//base", "//chrome/app:generated_resources", "//chrome/browser/ash/app_list",
diff --git a/chrome/browser/ash/app_list/arc/arc_app_list_prefs.cc b/chrome/browser/ash/app_list/arc/arc_app_list_prefs.cc index d01cf50e..1623b7b 100644 --- a/chrome/browser/ash/app_list/arc/arc_app_list_prefs.cc +++ b/chrome/browser/ash/app_list/arc/arc_app_list_prefs.cc
@@ -13,6 +13,7 @@ #include "ash/constants/ash_pref_names.h" #include "ash/constants/ash_switches.h" #include "ash/shell.h" +#include "ash/strings/grit/ash_strings.h" #include "base/check.h" #include "base/containers/flat_set.h" #include "base/files/file_util.h" @@ -44,7 +45,6 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/ash/shelf/chrome_shelf_controller.h" -#include "chrome/grit/generated_resources.h" #include "chromeos/ash/components/demo_mode/utils/demo_session_utils.h" #include "chromeos/ash/experiences/arc/app/arc_app_constants.h" #include "chromeos/ash/experiences/arc/arc_features.h"
diff --git a/chrome/browser/ash/arc/BUILD.gn b/chrome/browser/ash/arc/BUILD.gn index ede458eb..15899103 100644 --- a/chrome/browser/ash/arc/BUILD.gn +++ b/chrome/browser/ash/arc/BUILD.gn
@@ -273,6 +273,7 @@ "//chrome/browser/ash/profiles", "//chrome/browser/chromeos/arc", "//chrome/browser/profiles:profile", + "//chrome/browser/tab_contents", "//chrome/browser/ui/ash/login", "//chrome/browser/ui/ash/shelf", "//chromeos/ash/components/browser_context_helper",
diff --git a/chrome/browser/ash/arc/DEPS b/chrome/browser/ash/arc/DEPS index 98f8745..2f59c07 100644 --- a/chrome/browser/ash/arc/DEPS +++ b/chrome/browser/ash/arc/DEPS
@@ -68,7 +68,6 @@ "+chrome/common/net", "+chrome/common/pref_names.h", "+chrome/common/url_constants.h", - "+chrome/grit", "+chrome/services/printing/public/mojom", "+chrome/test/base", "+chrome/test/views", @@ -93,7 +92,12 @@ ], "arc_support_host\\.cc": [ + "+chrome/grit", "+chrome/browser/ui/extensions/app_launch_params.h", "+chrome/browser/ui/extensions/application_launch.h", - ] + ], + + "icon_decode_request\\.cc": [ + "+chrome/grit", + ], }
diff --git a/chrome/browser/ash/arc/arc_migration_guide_notification.cc b/chrome/browser/ash/arc/arc_migration_guide_notification.cc index 741f83b6..b05bbb79 100644 --- a/chrome/browser/ash/arc/arc_migration_guide_notification.cc +++ b/chrome/browser/ash/arc/arc_migration_guide_notification.cc
@@ -9,6 +9,7 @@ #include "ash/constants/notifier_catalogs.h" #include "ash/public/cpp/notification_utils.h" +#include "ash/strings/grit/ash_strings.h" #include "base/functional/bind.h" #include "chrome/browser/ash/arc/arc_migration_constants.h" #include "chrome/browser/ash/arc/arc_util.h" @@ -16,7 +17,6 @@ #include "chrome/browser/notifications/notification_display_service_factory.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/ash/multi_user/multi_user_util.h" -#include "chrome/grit/generated_resources.h" #include "chromeos/ash/components/dbus/dbus_thread_manager.h" #include "chromeos/dbus/power/power_manager_client.h" #include "chromeos/dbus/power_manager/power_supply_properties.pb.h"
diff --git a/chrome/browser/ash/arc/arc_support_host.cc b/chrome/browser/ash/arc/arc_support_host.cc index 43bb876..ea7df4d 100644 --- a/chrome/browser/ash/arc/arc_support_host.cc +++ b/chrome/browser/ash/arc/arc_support_host.cc
@@ -10,6 +10,7 @@ #include "ash/constants/ash_features.h" #include "ash/constants/url_constants.h" +#include "ash/strings/grit/ash_strings.h" #include "ash/webui/settings/public/constants/routes.mojom.h" #include "base/check_deref.h" #include "base/functional/bind.h" @@ -594,8 +595,8 @@ if (ash::features::IsCrosPrivacyHubLocationEnabled()) { loadtime_data.Set("textLocationService", l10n_util::GetStringUTF16( - is_child ? IDS_CROS_OPT_IN_LOCATION_SETTING_CHILD - : IDS_CROS_OPT_IN_LOCATION_SETTING)); + is_child ? IDS_ARC_CROS_OPT_IN_LOCATION_SETTING_CHILD + : IDS_ARC_CROS_OPT_IN_LOCATION_SETTING)); } else { loadtime_data.Set("textLocationService", l10n_util::GetStringUTF16( @@ -628,8 +629,8 @@ loadtime_data.Set( "learnMoreLocationServices", l10n_util::GetStringFUTF16( - is_child ? IDS_CROS_OPT_IN_LEARN_MORE_LOCATION_SERVICES_CHILD - : IDS_CROS_OPT_IN_LEARN_MORE_LOCATION_SERVICES, + is_child ? IDS_ARC_CROS_OPT_IN_LEARN_MORE_LOCATION_SERVICES_CHILD + : IDS_ARC_CROS_OPT_IN_LEARN_MORE_LOCATION_SERVICES, ash::external_urls::kPrivacyHubGeolocationAccuracyLearnMoreURL)); } else { loadtime_data.Set( @@ -792,8 +793,8 @@ if (ash::features::IsCrosPrivacyHubLocationEnabled()) { location_service_consent.add_description_grd_ids( - is_child ? IDS_CROS_OPT_IN_LOCATION_SETTING_CHILD - : IDS_CROS_OPT_IN_LOCATION_SETTING); + is_child ? IDS_ARC_CROS_OPT_IN_LOCATION_SETTING_CHILD + : IDS_ARC_CROS_OPT_IN_LOCATION_SETTING); } else { location_service_consent.add_description_grd_ids( is_child ? IDS_ARC_OPT_IN_LOCATION_SETTING_CHILD
diff --git a/chrome/browser/ash/arc/arc_util.cc b/chrome/browser/ash/arc/arc_util.cc index a463f19..12a85fd 100644 --- a/chrome/browser/ash/arc/arc_util.cc +++ b/chrome/browser/ash/arc/arc_util.cc
@@ -14,6 +14,7 @@ #include "ash/constants/ash_features.h" #include "ash/constants/ash_switches.h" +#include "ash/strings/grit/ash_strings.h" #include "base/files/file_path.h" #include "base/functional/bind.h" #include "base/functional/callback.h" @@ -47,7 +48,6 @@ #include "chrome/browser/ui/ash/login/login_display_host.h" #include "chrome/browser/ui/ash/shelf/chrome_shelf_controller.h" #include "chrome/browser/ui/simple_message_box.h" -#include "chrome/grit/generated_resources.h" #include "chromeos/ash/components/browser_context_helper/browser_context_helper.h" #include "chromeos/ash/components/demo_mode/utils/demo_session_utils.h" #include "chromeos/ash/components/install_attributes/install_attributes.h"
diff --git a/chrome/browser/ash/arc/notification/DEPS b/chrome/browser/ash/arc/notification/DEPS index 5d3e454..613533e 100644 --- a/chrome/browser/ash/arc/notification/DEPS +++ b/chrome/browser/ash/arc/notification/DEPS
@@ -25,7 +25,20 @@ "+chrome/browser/ui/ash/arc", "+chrome/browser/ui/ash/login", "+chrome/browser/ui/ash/multi_user", - "+chrome/grit", "+chrome/test/base", "+ui/message_center/message_center.h", ] + +specific_include_rules = { + "arc_boot_error_notification\\.cc": [ + "+chrome/grit", + ], + + "arc_management_transition_notification\\.cc": [ + "+chrome/grit", + ], + + "arc_provision_notification_service\\.cc": [ + "+chrome/grit", + ], +} \ No newline at end of file
diff --git a/chrome/browser/ash/arc/notification/arc_boot_error_notification.cc b/chrome/browser/ash/arc/notification/arc_boot_error_notification.cc index 4f00985..9afbabe 100644 --- a/chrome/browser/ash/arc/notification/arc_boot_error_notification.cc +++ b/chrome/browser/ash/arc/notification/arc_boot_error_notification.cc
@@ -8,6 +8,7 @@ #include <utility> #include "ash/public/cpp/notification_utils.h" +#include "ash/strings/grit/ash_strings.h" #include "ash/webui/settings/public/constants/routes.mojom.h" #include "base/check_deref.h" #include "base/functional/bind.h"
diff --git a/chrome/browser/ash/arc/notification/arc_management_transition_notification.cc b/chrome/browser/ash/arc/notification/arc_management_transition_notification.cc index 3185d5b..cda8052 100644 --- a/chrome/browser/ash/arc/notification/arc_management_transition_notification.cc +++ b/chrome/browser/ash/arc/notification/arc_management_transition_notification.cc
@@ -6,6 +6,7 @@ #include "ash/constants/notifier_catalogs.h" #include "ash/public/cpp/notification_utils.h" +#include "ash/strings/grit/ash_strings.h" #include "base/functional/bind.h" #include "base/memory/raw_ptr.h" #include "chrome/app/vector_icons/vector_icons.h" @@ -13,7 +14,6 @@ #include "chrome/browser/ash/arc/session/arc_session_manager.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/ash/multi_user/multi_user_util.h" -#include "chrome/grit/generated_resources.h" #include "chrome/grit/theme_resources.h" #include "chromeos/ash/experiences/arc/arc_prefs.h" #include "chromeos/ui/vector_icons/vector_icons.h"
diff --git a/chrome/browser/ash/arc/notification/arc_provision_notification_service.cc b/chrome/browser/ash/arc/notification/arc_provision_notification_service.cc index a2d603b..b4714d6 100644 --- a/chrome/browser/ash/arc/notification/arc_provision_notification_service.cc +++ b/chrome/browser/ash/arc/notification/arc_provision_notification_service.cc
@@ -7,6 +7,7 @@ #include <utility> #include "ash/constants/notifier_catalogs.h" +#include "ash/strings/grit/ash_strings.h" #include "base/memory/singleton.h" #include "base/strings/utf_string_conversions.h" #include "base/trace_event/trace_event.h" @@ -14,7 +15,6 @@ #include "chrome/browser/ash/arc/session/arc_session_manager.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/ash/multi_user/multi_user_util.h" -#include "chrome/grit/generated_resources.h" #include "chrome/grit/theme_resources.h" #include "chromeos/ash/components/demo_mode/utils/demo_session_utils.h" #include "chromeos/ash/experiences/arc/arc_browser_context_keyed_service_factory_base.h"
diff --git a/chrome/browser/ash/arc/optin/BUILD.gn b/chrome/browser/ash/arc/optin/BUILD.gn index 8630495..8be07d5dc 100644 --- a/chrome/browser/ash/arc/optin/BUILD.gn +++ b/chrome/browser/ash/arc/optin/BUILD.gn
@@ -43,6 +43,7 @@ ":optin", "//ash", "//ash/constants", + "//ash/strings", "//base", "//chrome/browser", "//chrome/browser/ash/arc",
diff --git a/chrome/browser/ash/arc/optin/DEPS b/chrome/browser/ash/arc/optin/DEPS index e865101..25baa67 100644 --- a/chrome/browser/ash/arc/optin/DEPS +++ b/chrome/browser/ash/arc/optin/DEPS
@@ -25,7 +25,6 @@ "+chrome/browser/signin", "+chrome/browser/ui/ash/login", "+chrome/browser/ui/webui/ash/login", - "+chrome/grit", "+chrome/test/base", ]
diff --git a/chrome/browser/ash/arc/optin/arc_terms_of_service_default_negotiator_unittest.cc b/chrome/browser/ash/arc/optin/arc_terms_of_service_default_negotiator_unittest.cc index e4d08ce..145c1ac 100644 --- a/chrome/browser/ash/arc/optin/arc_terms_of_service_default_negotiator_unittest.cc +++ b/chrome/browser/ash/arc/optin/arc_terms_of_service_default_negotiator_unittest.cc
@@ -10,6 +10,7 @@ #include "ash/constants/ash_features.h" #include "ash/constants/ash_pref_names.h" +#include "ash/strings/grit/ash_strings.h" #include "ash/system/privacy_hub/privacy_hub_controller.h" #include "base/functional/bind.h" #include "base/run_loop.h" @@ -27,7 +28,6 @@ #include "chrome/browser/consent_auditor/consent_auditor_test_utils.h" #include "chrome/browser/global_features.h" #include "chrome/browser/signin/identity_manager_factory.h" -#include "chrome/grit/generated_resources.h" #include "chrome/test/base/browser_with_test_window_test.h" #include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_profile.h" @@ -292,7 +292,7 @@ IDS_ARC_OPT_IN_DIALOG_BUTTON_AGREE); google_location_service_consent.add_description_grd_ids( ash::features::IsCrosPrivacyHubLocationEnabled() - ? IDS_CROS_OPT_IN_LOCATION_SETTING + ? IDS_ARC_CROS_OPT_IN_LOCATION_SETTING : IDS_ARC_OPT_IN_LOCATION_SETTING); return google_location_service_consent; }
diff --git a/chrome/browser/ash/arc/screen_capture/DEPS b/chrome/browser/ash/arc/screen_capture/DEPS index dd97db5..ca361042 100644 --- a/chrome/browser/ash/arc/screen_capture/DEPS +++ b/chrome/browser/ash/arc/screen_capture/DEPS
@@ -16,5 +16,10 @@ # directory basis. See //tools/chromeos/gen_deps.sh for details. "+chrome/browser/ash/notifications", "+chrome/browser/media/webrtc", - "+chrome/grit", ] + +specific_include_rules = { + "arc_screen_capture_session\\.cc": [ + "+chrome/grit", + ], +} \ No newline at end of file
diff --git a/chrome/browser/ash/arc/session/BUILD.gn b/chrome/browser/ash/arc/session/BUILD.gn index 0c65b8a2..201fab2 100644 --- a/chrome/browser/ash/arc/session/BUILD.gn +++ b/chrome/browser/ash/arc/session/BUILD.gn
@@ -116,6 +116,7 @@ public_deps = [ "//chrome/browser:browser_public_dependencies" ] deps = [ + "//ash/strings", "//chrome/browser:browser_process", "//chrome/browser:global_features", "//chrome/browser/ash/app_list/arc",
diff --git a/chrome/browser/ash/arc/session/DEPS b/chrome/browser/ash/arc/session/DEPS index eee9fe0..3d108e6e 100644 --- a/chrome/browser/ash/arc/session/DEPS +++ b/chrome/browser/ash/arc/session/DEPS
@@ -43,7 +43,6 @@ "+chrome/browser/ui/browser_commands.h", "+chrome/browser/ui/browser.h", "+chrome/browser/ui/webui/ash", - "+chrome/grit", "+chrome/test/base", ] @@ -57,9 +56,17 @@ "+chrome/browser/web_applications/web_app_utils.h", ], - "arc_session_manager_browsertest\.cc": [ + "arc_session_manager_browsertest\\.cc": [ "+chrome/browser/ash/test", "+chrome/browser/browser_process.h", "+chrome/browser/ui/browser_window.h", - ] + ], + + "arc_play_store_enabled_preference_handler\\.cc": [ + "+chrome/grit", + ], + + "arc_play_store_enabled_preference_handler_unittest\\.cc": [ + "+chrome/grit", + ], }
diff --git a/chrome/browser/ash/arc/session/arc_disk_space_monitor.cc b/chrome/browser/ash/arc/session/arc_disk_space_monitor.cc index aa53c7d..9b843cd 100644 --- a/chrome/browser/ash/arc/session/arc_disk_space_monitor.cc +++ b/chrome/browser/ash/arc/session/arc_disk_space_monitor.cc
@@ -5,13 +5,13 @@ #include "chrome/browser/ash/arc/session/arc_disk_space_monitor.h" #include "ash/public/cpp/notification_utils.h" +#include "ash/strings/grit/ash_strings.h" #include "base/logging.h" #include "chrome/app/vector_icons/vector_icons.h" #include "chrome/browser/ash/arc/arc_util.h" #include "chrome/browser/ash/arc/session/arc_session_manager.h" #include "chrome/browser/notifications/notification_display_service.h" #include "chrome/browser/notifications/notification_display_service_factory.h" -#include "chrome/grit/generated_resources.h" #include "chromeos/ash/components/dbus/spaced/spaced_client.h" #include "chromeos/ash/components/demo_mode/utils/demo_session_utils.h" #include "chromeos/ash/experiences/arc/arc_util.h"
diff --git a/chrome/browser/ash/login/chrome_restart_request.cc b/chrome/browser/ash/login/chrome_restart_request.cc index f8c8b1b..4e073ea 100644 --- a/chrome/browser/ash/login/chrome_restart_request.cc +++ b/chrome/browser/ash/login/chrome_restart_request.cc
@@ -79,7 +79,7 @@ bool IsRunningTest() { const base::CommandLine* current_command_line = base::CommandLine::ForCurrentProcess(); - return current_command_line->HasSwitch(ash::switches::kTestName) || + return current_command_line->HasSwitch(::switches::kTestName) || current_command_line->HasSwitch(::switches::kTestType); }
diff --git a/chrome/browser/ash/login/crash_restore_browsertest.cc b/chrome/browser/ash/login/crash_restore_browsertest.cc index e3bc771..cdc4c9ca 100644 --- a/chrome/browser/ash/login/crash_restore_browsertest.cc +++ b/chrome/browser/ash/login/crash_restore_browsertest.cc
@@ -110,48 +110,33 @@ } // Observer that keeps track of user sessions restore event. -class UserSessionRestoreObserver : public UserSessionStateObserver { +class UserSessionRestoreObserver { public: - UserSessionRestoreObserver() - : running_loop_(false), - user_sessions_restored_( - UserSessionManager::GetInstance()->UserSessionsRestored()) { - if (!user_sessions_restored_) - UserSessionManager::GetInstance()->AddSessionStateObserver(this); + UserSessionRestoreObserver() { + if (!UserSessionManager::GetInstance()->UserSessionsRestored()) { + run_loop_.emplace(); + UserSessionManager::GetInstance() + ->SetOnPendingUserSessionRestoreFinishedForTesting( + run_loop_->QuitClosure()); + } } UserSessionRestoreObserver(const UserSessionRestoreObserver&) = delete; UserSessionRestoreObserver& operator=(const UserSessionRestoreObserver&) = delete; - - ~UserSessionRestoreObserver() override = default; - - void PendingUserSessionsRestoreFinished() override { - user_sessions_restored_ = true; - UserSessionManager::GetInstance()->RemoveSessionStateObserver(this); - if (!running_loop_) - return; - - message_loop_runner_->Quit(); - running_loop_ = false; - } + ~UserSessionRestoreObserver() = default; // Wait until the user sessions are restored. If that happened between the // construction of this object and this call or even before it was created // then it returns immediately. void Wait() { - if (user_sessions_restored_) - return; - - running_loop_ = true; - message_loop_runner_ = new content::MessageLoopRunner(); - message_loop_runner_->Run(); + if (run_loop_) { + run_loop_->Run(); + } } private: - bool running_loop_; - bool user_sessions_restored_; - scoped_refptr<content::MessageLoopRunner> message_loop_runner_; + std::optional<base::RunLoop> run_loop_; }; class CrashRestoreComplexTest : public CrashRestoreSimpleTest {
diff --git a/chrome/browser/ash/login/enrollment/enrollment_embedded_policy_server_browsertest.cc b/chrome/browser/ash/login/enrollment/enrollment_embedded_policy_server_browsertest.cc index e5869644..a316f48 100644 --- a/chrome/browser/ash/login/enrollment/enrollment_embedded_policy_server_browsertest.cc +++ b/chrome/browser/ash/login/enrollment/enrollment_embedded_policy_server_browsertest.cc
@@ -7,6 +7,7 @@ #include <string> #include "ash/constants/ash_features.h" +#include "ash/constants/ash_pref_names.h" #include "ash/constants/ash_switches.h" #include "ash/public/cpp/login_screen_test_api.h" #include "base/check.h" @@ -58,7 +59,6 @@ #include "chrome/browser/ui/webui/ash/login/error_screen_handler.h" #include "chrome/browser/ui/webui/ash/login/gaia_screen_handler.h" #include "chrome/browser/ui/webui/ash/login/online_login_utils.h" -#include "chrome/common/pref_names.h" #include "chrome/grit/generated_resources.h" #include "chrome/test/base/fake_gaia_mixin.h" #include "chromeos/ash/components/attestation/mock_attestation_flow.h" @@ -306,17 +306,17 @@ int GetPsmExecutionResultPref() const { const PrefService& local_state = *g_browser_process->local_state(); const PrefService::Preference* has_psm_execution_result_pref = - local_state.FindPreference(prefs::kEnrollmentPsmResult); + local_state.FindPreference(ash::prefs::kEnrollmentPsmResult); // Verify the existence of an integer pref value - // `prefs::kEnrollmentPsmResult`. + // `ash::prefs::kEnrollmentPsmResult`. if (!has_psm_execution_result_pref) { - ADD_FAILURE() << "kEnrollmentPsmResult pref not found"; + ADD_FAILURE() << "ash::prefs::kEnrollmentPsmResult pref not found"; return -1; } if (!has_psm_execution_result_pref->GetValue()->is_int()) { - ADD_FAILURE() - << "kEnrollmentPsmResult pref does not have an integer value"; + ADD_FAILURE() << "ash::prefs::kEnrollmentPsmResult pref does not have an " + "integer value"; return -1; } EXPECT_FALSE(has_psm_execution_result_pref->IsDefaultValue()); @@ -335,18 +335,19 @@ int64_t GetPsmDeterminationTimestampPref() const { const PrefService& local_state = *g_browser_process->local_state(); const PrefService::Preference* has_psm_determination_timestamp_pref = - local_state.FindPreference(prefs::kEnrollmentPsmDeterminationTime); + local_state.FindPreference(ash::prefs::kEnrollmentPsmDeterminationTime); // Verify the existence of non-default value pref - // `prefs::kEnrollmentPsmDeterminationTime`. + // `ash::prefs::kEnrollmentPsmDeterminationTime`. if (!has_psm_determination_timestamp_pref) { - ADD_FAILURE() << "kEnrollmentPsmDeterminationTime pref not found"; + ADD_FAILURE() + << "ash::prefs::kEnrollmentPsmDeterminationTime pref not found"; return -1; } EXPECT_FALSE(has_psm_determination_timestamp_pref->IsDefaultValue()); const base::Time psm_determination_timestamp = - local_state.GetTime(prefs::kEnrollmentPsmDeterminationTime); + local_state.GetTime(ash::prefs::kEnrollmentPsmDeterminationTime); // The PSM determination timestamp should exist at this stage. Because // we already checked the existence of the pref with non-default value.
diff --git a/chrome/browser/ash/login/enrollment/enrollment_screen_unittest.cc b/chrome/browser/ash/login/enrollment/enrollment_screen_unittest.cc index 9e24771..a56985e 100644 --- a/chrome/browser/ash/login/enrollment/enrollment_screen_unittest.cc +++ b/chrome/browser/ash/login/enrollment/enrollment_screen_unittest.cc
@@ -10,6 +10,7 @@ #include <string> #include "ash/constants/ash_features.h" +#include "ash/constants/ash_pref_names.h" #include "base/check_deref.h" #include "base/functional/bind.h" #include "base/functional/callback.h" @@ -38,7 +39,6 @@ #include "chrome/browser/prefs/browser_prefs.h" #include "chrome/browser/ui/ash/login/fake_login_display_host.h" #include "chrome/browser/ui/webui/ash/login/online_login_utils.h" -#include "chrome/common/pref_names.h" #include "chrome/test/base/testing_browser_process.h" #include "chromeos/ash/components/install_attributes/stub_install_attributes.h" #include "chromeos/ash/components/network/network_handler_test_helper.h" @@ -463,7 +463,7 @@ ShowEnrollmentScreen(); EXPECT_EQ(last_screen_result(), EnrollmentScreen::Result::COMPLETED); - EXPECT_EQ(local_state().GetInteger(prefs::kDeviceRegistered), 1); + EXPECT_EQ(local_state().GetInteger(ash::prefs::kDeviceRegistered), 1); } TEST_P(EnrollmentScreenManualFlowTest, OobeConfigSkipEnrollmentSuccessScreen) { @@ -481,7 +481,7 @@ ShowEnrollmentScreen(); EXPECT_EQ(last_screen_result(), EnrollmentScreen::Result::COMPLETED); - EXPECT_EQ(local_state().GetInteger(prefs::kDeviceRegistered), 1); + EXPECT_EQ(local_state().GetInteger(ash::prefs::kDeviceRegistered), 1); } TEST_P(EnrollmentScreenManualFlowTest, ShouldNotAutomaticallyRetryEnrollment) { @@ -532,7 +532,7 @@ EXPECT_EQ(GetEnrollmentScreenRetries(), 1); EXPECT_EQ(last_screen_result(), EnrollmentScreen::Result::COMPLETED); - EXPECT_EQ(local_state().GetInteger(prefs::kDeviceRegistered), 1); + EXPECT_EQ(local_state().GetInteger(ash::prefs::kDeviceRegistered), 1); } INSTANTIATE_TEST_SUITE_P( @@ -736,7 +736,7 @@ ShowEnrollmentScreen(); EXPECT_EQ(last_screen_result(), EnrollmentScreen::Result::COMPLETED); - EXPECT_EQ(local_state().GetInteger(prefs::kDeviceRegistered), 1); + EXPECT_EQ(local_state().GetInteger(ash::prefs::kDeviceRegistered), 1); } TEST_P(EnrollmentScreenAttestationFlowTest, @@ -788,7 +788,7 @@ EXPECT_EQ(GetEnrollmentScreenRetries(), 1); EXPECT_EQ(last_screen_result(), EnrollmentScreen::Result::COMPLETED); - EXPECT_EQ(local_state().GetInteger(prefs::kDeviceRegistered), 1); + EXPECT_EQ(local_state().GetInteger(ash::prefs::kDeviceRegistered), 1); } // The add user flow is expected to only affect the manual enrollment. @@ -863,7 +863,7 @@ ShowEnrollmentScreen(); EXPECT_EQ(last_screen_result(), EnrollmentScreen::Result::COMPLETED); - EXPECT_EQ(local_state().GetInteger(prefs::kDeviceRegistered), 1); + EXPECT_EQ(local_state().GetInteger(ash::prefs::kDeviceRegistered), 1); } TEST_P(EnrollmentScreenAttestationFlowWithManualFallbackTest, @@ -900,7 +900,7 @@ UserCancel(); EXPECT_EQ(last_screen_result(), EnrollmentScreen::Result::COMPLETED); - EXPECT_EQ(local_state().GetInteger(prefs::kDeviceRegistered), 1); + EXPECT_EQ(local_state().GetInteger(ash::prefs::kDeviceRegistered), 1); } INSTANTIATE_TEST_SUITE_P(
diff --git a/chrome/browser/ash/login/login_ui_browsertest.cc b/chrome/browser/ash/login/login_ui_browsertest.cc index 1ab099d..b6c1f0e 100644 --- a/chrome/browser/ash/login/login_ui_browsertest.cc +++ b/chrome/browser/ash/login/login_ui_browsertest.cc
@@ -38,7 +38,6 @@ #include "chrome/browser/ui/webui/ash/login/gaia_screen_handler.h" #include "chrome/browser/ui/webui/ash/login/welcome_screen_handler.h" #include "chrome/browser/ui/webui/ash/system_web_dialog/system_web_dialog_delegate.h" -#include "chrome/common/pref_names.h" #include "chromeos/ash/components/dbus/dbus_thread_manager.h" #include "chromeos/ash/components/dbus/debug_daemon/fake_debug_daemon_client.h" #include "chromeos/ash/components/dbus/session_manager/fake_session_manager_client.h" @@ -69,8 +68,8 @@ void SetUpLocalState() override { StartupUtils::MarkOobeCompleted(); PrefService* prefs = g_browser_process->local_state(); - prefs->SetBoolean(::prefs::kDeviceEnrollmentAutoStart, true); - prefs->SetBoolean(::prefs::kDeviceEnrollmentCanExit, false); + prefs->SetBoolean(ash::prefs::kDeviceEnrollmentAutoStart, true); + prefs->SetBoolean(ash::prefs::kDeviceEnrollmentCanExit, false); } private:
diff --git a/chrome/browser/ash/login/session/chrome_session_manager.cc b/chrome/browser/ash/login/session/chrome_session_manager.cc index 324c85b..4a05305b 100644 --- a/chrome/browser/ash/login/session/chrome_session_manager.cc +++ b/chrome/browser/ash/login/session/chrome_session_manager.cc
@@ -194,7 +194,7 @@ const std::string& login_user_id) { base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - bool is_running_test = command_line->HasSwitch(ash::switches::kTestName) || + bool is_running_test = command_line->HasSwitch(::switches::kTestName) || command_line->HasSwitch(::switches::kTestType); if (command_line->HasSwitch(switches::kLoginUser)) {
diff --git a/chrome/browser/ash/login/session/user_session_manager.cc b/chrome/browser/ash/login/session/user_session_manager.cc index 7345450f..ced64cbe 100644 --- a/chrome/browser/ash/login/session/user_session_manager.cc +++ b/chrome/browser/ash/login/session/user_session_manager.cc
@@ -430,7 +430,7 @@ bool IsRunningTest() { return base::CommandLine::ForCurrentProcess()->HasSwitch( - ash::switches::kTestName) || + ::switches::kTestName) || base::CommandLine::ForCurrentProcess()->HasSwitch( ::switches::kTestType); } @@ -1067,18 +1067,6 @@ return true; } -void UserSessionManager::AddSessionStateObserver( - ash::UserSessionStateObserver* observer) { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - session_state_observer_list_.AddObserver(observer); -} - -void UserSessionManager::RemoveSessionStateObserver( - ash::UserSessionStateObserver* observer) { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - session_state_observer_list_.RemoveObserver(observer); -} - void UserSessionManager::AddUserAuthenticatorObserver( UserAuthenticatorObserver* observer) { authenticator_observer_list_.AddObserver(observer); @@ -2331,8 +2319,9 @@ void UserSessionManager::NotifyPendingUserSessionsRestoreFinished() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); user_sessions_restored_ = true; - for (auto& observer : session_state_observer_list_) - observer.PendingUserSessionsRestoreFinished(); + if (on_pending_user_session_restore_finished_for_testsing_) { + std::move(on_pending_user_session_restore_finished_for_testsing_).Run(); + } } void UserSessionManager::OnChildPolicyReady( @@ -2672,6 +2661,13 @@ eol_notification_handler_test_factory_ = eol_notification_handler_factory; } +void UserSessionManager::SetOnPendingUserSessionRestoreFinishedForTesting( + base::OnceClosure callback) { + CHECK(!UserSessionsRestored()); + CHECK(!on_pending_user_session_restore_finished_for_testsing_); + on_pending_user_session_restore_finished_for_testsing_ = std::move(callback); +} + base::WeakPtr<UserSessionManager> UserSessionManager::GetUserSessionManagerAsWeakPtr() { return weak_factory_.GetWeakPtr();
diff --git a/chrome/browser/ash/login/session/user_session_manager.h b/chrome/browser/ash/login/session/user_session_manager.h index 6d65c91..b511633 100644 --- a/chrome/browser/ash/login/session/user_session_manager.h +++ b/chrome/browser/ash/login/session/user_session_manager.h
@@ -80,15 +80,6 @@ virtual ~UserSessionManagerDelegate() = default; }; -class UserSessionStateObserver : public base::CheckedObserver { - public: - // Called when UserManager finishes restoring user sessions after crash. - virtual void PendingUserSessionsRestoreFinished() {} - - protected: - ~UserSessionStateObserver() override = default; -}; - class UserAuthenticatorObserver : public base::CheckedObserver { public: // Called when authentication is started. @@ -259,9 +250,6 @@ bool RestartToApplyPerSessionFlagsIfNeed(Profile* profile, bool early_restart); - void AddSessionStateObserver(ash::UserSessionStateObserver* observer); - void RemoveSessionStateObserver(ash::UserSessionStateObserver* observer); - void AddUserAuthenticatorObserver(UserAuthenticatorObserver* observer); void RemoveUserAuthenticatorObserver(UserAuthenticatorObserver* observer); @@ -333,6 +321,11 @@ void SetEolNotificationHandlerFactoryForTesting( const EolNotificationHandlerFactoryCallback& eol_notification_factory); + // Sets a testing callback which invoked when session restore is finished. + // The caller should check `UserSessionsRestored()` is false beforehand. + void SetOnPendingUserSessionRestoreFinishedForTesting( + base::OnceClosure callback); + base::WeakPtr<UserSessionManager> GetUserSessionManagerAsWeakPtr(); protected: @@ -556,8 +549,7 @@ PendingUserSessions pending_user_sessions_; - base::ObserverList<ash::UserSessionStateObserver> - session_state_observer_list_; + base::OnceClosure on_pending_user_session_restore_finished_for_testsing_; base::ObserverList<UserAuthenticatorObserver> authenticator_observer_list_;
diff --git a/chrome/browser/ash/login/startup_utils.cc b/chrome/browser/ash/login/startup_utils.cc index e7b0d7d..6e94f3c7 100644 --- a/chrome/browser/ash/login/startup_utils.cc +++ b/chrome/browser/ash/login/startup_utils.cc
@@ -107,8 +107,8 @@ registry->RegisterBooleanPref(prefs::kOobeComplete, false); registry->RegisterStringPref(prefs::kOobeScreenPending, ""); registry->RegisterTimePref(prefs::kOobeStartTime, base::Time()); - registry->RegisterIntegerPref(::prefs::kDeviceRegistered, -1); - registry->RegisterBooleanPref(::prefs::kEnrollmentRecoveryRequired, false); + registry->RegisterIntegerPref(ash::prefs::kDeviceRegistered, -1); + registry->RegisterBooleanPref(ash::prefs::kEnrollmentRecoveryRequired, false); registry->RegisterStringPref(::prefs::kInitialLocale, "en-US"); registry->RegisterBooleanPref(kDisableHIDDetectionScreenForTests, false); registry->RegisterBooleanPref(prefs::kOobeGuestMetricsEnabled, false); @@ -210,7 +210,7 @@ SaveBoolPreferenceForced(prefs::kOobeComplete, true); // Successful enrollment implies that recovery is not required. - SaveBoolPreferenceForced(::prefs::kEnrollmentRecoveryRequired, false); + SaveBoolPreferenceForced(ash::prefs::kEnrollmentRecoveryRequired, false); // If `kOobeComplete` is already true, the `kAutoEnrollmentCheckExited` pref // is no longer needed as its purpose is to potentially block OOBE completion. @@ -247,8 +247,8 @@ // static bool StartupUtils::IsDeviceRegistered() { - int value = - g_browser_process->local_state()->GetInteger(::prefs::kDeviceRegistered); + int value = g_browser_process->local_state()->GetInteger( + ash::prefs::kDeviceRegistered); if (value > 0) { // Recreate flag file in case it was lost. base::ThreadPool::PostTask( @@ -263,7 +263,7 @@ base::ScopedAllowBlocking allow_blocking; const base::FilePath oobe_complete_flag_path = GetOobeCompleteFlagPath(); bool file_exists = base::PathExists(oobe_complete_flag_path); - SaveIntegerPreferenceForced(::prefs::kDeviceRegistered, + SaveIntegerPreferenceForced(ash::prefs::kDeviceRegistered, file_exists ? 1 : 0); return file_exists; } @@ -282,7 +282,7 @@ // static void StartupUtils::MarkDeviceRegistered(base::OnceClosure done_callback) { - SaveIntegerPreferenceForced(::prefs::kDeviceRegistered, 1); + SaveIntegerPreferenceForced(ash::prefs::kDeviceRegistered, 1); auto* host = LoginDisplayHost::default_host(); if (host) { @@ -309,7 +309,7 @@ // static void StartupUtils::MarkEnrollmentRecoveryRequired() { - SaveBoolPreferenceForced(::prefs::kEnrollmentRecoveryRequired, true); + SaveBoolPreferenceForced(ash::prefs::kEnrollmentRecoveryRequired, true); } // static
diff --git a/chrome/browser/ash/login/test/device_state_mixin.cc b/chrome/browser/ash/login/test/device_state_mixin.cc index 3294d7d..19802a4 100644 --- a/chrome/browser/ash/login/test/device_state_mixin.cc +++ b/chrome/browser/ash/login/test/device_state_mixin.cc
@@ -8,6 +8,7 @@ #include <vector> #include "ash/constants/ash_paths.h" +#include "ash/constants/ash_pref_names.h" #include "base/compiler_specific.h" #include "base/files/file_util.h" #include "base/functional/callback.h" @@ -113,17 +114,17 @@ case DeviceStateMixin::State::OOBE_COMPLETED_CONSUMER_OWNED: case DeviceStateMixin::State::OOBE_COMPLETED_DEMO_MODE: local_state->SetBoolean(prefs::kOobeComplete, true); - local_state->SetInteger(::prefs::kDeviceRegistered, 1); - local_state->SetBoolean(::prefs::kEnrollmentRecoveryRequired, false); + local_state->SetInteger(ash::prefs::kDeviceRegistered, 1); + local_state->SetBoolean(ash::prefs::kEnrollmentRecoveryRequired, false); break; case DeviceStateMixin::State::OOBE_COMPLETED_UNOWNED: case DeviceStateMixin::State::OOBE_COMPLETED_PERMANENTLY_UNOWNED: local_state->SetBoolean(prefs::kOobeComplete, true); - local_state->SetInteger(::prefs::kDeviceRegistered, 0); - local_state->SetBoolean(::prefs::kEnrollmentRecoveryRequired, false); + local_state->SetInteger(ash::prefs::kDeviceRegistered, 0); + local_state->SetBoolean(ash::prefs::kEnrollmentRecoveryRequired, false); break; case DeviceStateMixin::State::BEFORE_OOBE: - local_state->SetInteger(::prefs::kDeviceRegistered, 0); + local_state->SetInteger(ash::prefs::kDeviceRegistered, 0); break; } }
diff --git a/chrome/browser/ash/nearby/nearby_dependencies_provider.cc b/chrome/browser/ash/nearby/nearby_dependencies_provider.cc index cfcf508..f35b1fb 100644 --- a/chrome/browser/ash/nearby/nearby_dependencies_provider.cc +++ b/chrome/browser/ash/nearby/nearby_dependencies_provider.cc
@@ -17,6 +17,7 @@ #include "chrome/browser/ash/nearby/nearby_dependencies_provider_factory.h" #include "chrome/browser/ash/nearby/presence/credential_storage/credential_storage_initializer.h" #include "chrome/browser/nearby_sharing/common/nearby_share_features.h" +#include "chrome/browser/nearby_sharing/common/nearby_share_switches.h" #include "chrome/browser/nearby_sharing/firewall_hole/nearby_connections_firewall_hole_factory.h" #include "chrome/browser/nearby_sharing/mdns/nearby_connections_mdns_manager.h" #include "chrome/browser/nearby_sharing/sharing_mojo_service.h"
diff --git a/chrome/browser/ash/policy/core/device_cloud_policy_store_ash.cc b/chrome/browser/ash/policy/core/device_cloud_policy_store_ash.cc index dd17b75..d414000d 100644 --- a/chrome/browser/ash/policy/core/device_cloud_policy_store_ash.cc +++ b/chrome/browser/ash/policy/core/device_cloud_policy_store_ash.cc
@@ -6,6 +6,7 @@ #include <utility> +#include "ash/constants/ash_pref_names.h" #include "base/files/file_path.h" #include "base/functional/bind.h" #include "base/logging.h" @@ -21,7 +22,6 @@ #include "chrome/browser/ash/policy/dev_mode/dev_mode_policy_util.h" #include "chrome/browser/ash/policy/value_validation/onc_device_policy_value_validator.h" #include "chrome/browser/browser_process.h" -#include "chrome/common/pref_names.h" #include "chromeos/ash/components/install_attributes/install_attributes.h" #include "chromeos/dbus/constants/dbus_paths.h" #include "components/ownership/owner_key_util.h" @@ -49,7 +49,7 @@ // validation now. auto* local_state = g_browser_process->local_state(); return local_state && - !local_state->GetString(prefs::kEnrollmentVersionOS).empty(); + !local_state->GetString(ash::prefs::kEnrollmentVersionOS).empty(); } } // namespace
diff --git a/chrome/browser/ash/policy/core/device_cloud_policy_store_ash_unittest.cc b/chrome/browser/ash/policy/core/device_cloud_policy_store_ash_unittest.cc index ceb501ac..4e9b1450 100644 --- a/chrome/browser/ash/policy/core/device_cloud_policy_store_ash_unittest.cc +++ b/chrome/browser/ash/policy/core/device_cloud_policy_store_ash_unittest.cc
@@ -9,6 +9,7 @@ #include <memory> #include <string> +#include "ash/constants/ash_pref_names.h" #include "ash/constants/ash_switches.h" #include "base/command_line.h" #include "base/compiler_specific.h" @@ -17,7 +18,6 @@ #include "base/task/single_thread_task_runner.h" #include "base/values.h" #include "chrome/browser/ash/settings/device_settings_test_helper.h" -#include "chrome/common/pref_names.h" #include "chrome/test/base/testing_browser_process.h" #include "chromeos/ash/components/dbus/dbus_thread_manager.h" #include "chromeos/ash/components/dbus/device_management/fake_install_attributes_client.h" @@ -311,7 +311,7 @@ TEST_F(DeviceCloudPolicyStoreAshTest, StoreDeviceIdValidationEnabled) { TestingBrowserProcess::GetGlobal()->GetTestingLocalState()->SetManagedPref( - prefs::kEnrollmentVersionOS, base::Value("128")); + ash::prefs::kEnrollmentVersionOS, base::Value("128")); PrepareExistingPolicy(); // Set the device_id created by the policy generator. Expected to be valid. @@ -329,7 +329,7 @@ TEST_F(DeviceCloudPolicyStoreAshTest, StoreDeviceIdValidationEnabledError) { TestingBrowserProcess::GetGlobal()->GetTestingLocalState()->SetManagedPref( - prefs::kEnrollmentVersionOS, base::Value("128")); + ash::prefs::kEnrollmentVersionOS, base::Value("128")); PrepareExistingPolicy(); device_policy_->policy_data().mutable_device_id()->assign("bad-device-id");
diff --git a/chrome/browser/ash/policy/display/display_resolution_handler.cc b/chrome/browser/ash/policy/display/display_resolution_handler.cc index 2816ed5..527f7c3 100644 --- a/chrome/browser/ash/policy/display/display_resolution_handler.cc +++ b/chrome/browser/ash/policy/display/display_resolution_handler.cc
@@ -33,10 +33,10 @@ // Create display config for the internal display using policy settings from // |internal_display_settings_|. - crosapi::mojom::DisplayConfigPropertiesPtr ToDisplayConfigProperties() { - auto new_config = crosapi::mojom::DisplayConfigProperties::New(); + std::optional<ash::DisplayConfigProperties> ToDisplayConfigProperties() { + ash::DisplayConfigProperties new_config; // Converting percentage to factor. - new_config->display_zoom_factor = scale_percentage / 100.0; + new_config.display_zoom_factor = scale_percentage / 100.0; return new_config; } @@ -76,29 +76,29 @@ // Create display config for the external display using policy settings from // |external_display_settings_|. - crosapi::mojom::DisplayConfigPropertiesPtr ToDisplayConfigProperties( + std::optional<ash::DisplayConfigProperties> ToDisplayConfigProperties( const std::vector<crosapi::mojom::DisplayModePtr>& display_modes) { bool found_suitable_mode = false; - auto new_config = crosapi::mojom::DisplayConfigProperties::New(); + ash::DisplayConfigProperties new_config; for (const crosapi::mojom::DisplayModePtr& mode : display_modes) { // Check if the current display mode has required resolution and its // refresh rate is higher than refresh rate of the already found mode. if (IsSuitableDisplayMode(mode) && (!found_suitable_mode || - mode->refresh_rate > new_config->display_mode->refresh_rate)) { - new_config->display_mode = mode->Clone(); + mode->refresh_rate > new_config.display_mode->refresh_rate)) { + new_config.display_mode = mode->Clone(); found_suitable_mode = true; } } // If we couldn't find the required mode and and scale percentage doesn't // need to be changed, we have nothing to do. if (!found_suitable_mode && !scale_percentage) { - return crosapi::mojom::DisplayConfigPropertiesPtr(); + return std::nullopt; } if (scale_percentage) { // Converting percentage to the factor. - new_config->display_zoom_factor = *scale_percentage / 100.0; + new_config.display_zoom_factor = *scale_percentage / 100.0; } return new_config; @@ -207,26 +207,26 @@ continue; } - crosapi::mojom::DisplayConfigPropertiesPtr new_config; + std::optional<ash::DisplayConfigProperties> new_config; if (display_unit_info->is_internal && internal_display_settings_) { new_config = internal_display_settings_->ToDisplayConfigProperties(); } else if (!display_unit_info->is_internal && external_display_settings_) { new_config = external_display_settings_->ToDisplayConfigProperties( DisplayUnitTraits::available_display_modes(display_unit_info)); } - - if (!new_config) + if (!new_config.has_value()) { continue; + } resized_display_ids_.insert(display_id); - crosapi::mojom::DisplayConfigResult result = - cros_display_config.SetDisplayProperties( - display_unit_info->id, std::move(new_config), - crosapi::mojom::DisplayConfigSource::kPolicy); - if (result == crosapi::mojom::DisplayConfigResult::kSuccess) { + ash::DisplayConfigResult result = cros_display_config.SetDisplayProperties( + display_unit_info->id, *new_config, + crosapi::mojom::DisplayConfigSource::kPolicy); + if (result == ash::DisplayConfigResult::kSuccess) { VLOG(1) << "Successfully changed display mode."; } else { - LOG(ERROR) << "Couldn't change display mode. Error code: " << result; + LOG(ERROR) << "Couldn't change display mode. Error code: " + << static_cast<int>(result); } } }
diff --git a/chrome/browser/ash/policy/display/display_rotation_default_handler.cc b/chrome/browser/ash/policy/display/display_rotation_default_handler.cc index fcf04da..aefab51 100644 --- a/chrome/browser/ash/policy/display/display_rotation_default_handler.cc +++ b/chrome/browser/ash/policy/display/display_rotation_default_handler.cc
@@ -111,11 +111,11 @@ // The following sets only the |rotation| property of the display // configuration; no other properties will be affected. - auto config_properties = crosapi::mojom::DisplayConfigProperties::New(); - config_properties->rotation = crosapi::mojom::DisplayRotation::New( - RotationOptionsFromDisplayRotation(display_rotation_default_)); + ash::DisplayConfigProperties config_properties; + config_properties.rotation = + RotationOptionsFromDisplayRotation(display_rotation_default_); cros_display_config.SetDisplayProperties( - display_unit_info->id, std::move(config_properties), + display_unit_info->id, config_properties, crosapi::mojom::DisplayConfigSource::kPolicy); } }
diff --git a/chrome/browser/ash/policy/enrollment/enrollment_config.cc b/chrome/browser/ash/policy/enrollment/enrollment_config.cc index 66b7a000..c14d6f3 100644 --- a/chrome/browser/ash/policy/enrollment/enrollment_config.cc +++ b/chrome/browser/ash/policy/enrollment/enrollment_config.cc
@@ -8,6 +8,7 @@ #include <string> #include <string_view> +#include "ash/constants/ash_pref_names.h" #include "ash/constants/ash_switches.h" #include "base/command_line.h" #include "base/logging.h" @@ -108,14 +109,14 @@ // Regardless what mode is applicable, the enrollment domain is fixed. recovery_config.management_domain = install_attributes.GetDomain(); - if (!local_state->GetBoolean(prefs::kEnrollmentRecoveryRequired)) { + if (!local_state->GetBoolean(ash::prefs::kEnrollmentRecoveryRequired)) { return recovery_config; } if (ash::DeviceSettingsService::IsInitialized() && ash::DeviceSettingsService::Get()->HasDmToken()) { LOG(WARNING) << "False recovery flag."; - local_state->ClearPref(::prefs::kEnrollmentRecoveryRequired); + local_state->ClearPref(ash::prefs::kEnrollmentRecoveryRequired); return recovery_config; } @@ -260,14 +261,14 @@ } const bool pref_enrollment_auto_start_present = - local_state->HasPrefPath(prefs::kDeviceEnrollmentAutoStart); + local_state->HasPrefPath(ash::prefs::kDeviceEnrollmentAutoStart); const bool pref_enrollment_auto_start = - local_state->GetBoolean(prefs::kDeviceEnrollmentAutoStart); + local_state->GetBoolean(ash::prefs::kDeviceEnrollmentAutoStart); const bool pref_enrollment_can_exit_present = - local_state->HasPrefPath(prefs::kDeviceEnrollmentCanExit); + local_state->HasPrefPath(ash::prefs::kDeviceEnrollmentCanExit); const bool pref_enrollment_can_exit = - local_state->GetBoolean(prefs::kDeviceEnrollmentCanExit); + local_state->GetBoolean(ash::prefs::kDeviceEnrollmentCanExit); if (pref_enrollment_auto_start_present && pref_enrollment_auto_start && pref_enrollment_can_exit_present && !pref_enrollment_can_exit) {
diff --git a/chrome/browser/ash/policy/enrollment/enrollment_config_unittest.cc b/chrome/browser/ash/policy/enrollment/enrollment_config_unittest.cc index 68e340bf..ca4e033 100644 --- a/chrome/browser/ash/policy/enrollment/enrollment_config_unittest.cc +++ b/chrome/browser/ash/policy/enrollment/enrollment_config_unittest.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/ash/policy/enrollment/enrollment_config.h" +#include "ash/constants/ash_pref_names.h" #include "base/check_deref.h" #include "base/command_line.h" #include "base/strings/stringprintf.h" @@ -202,7 +203,7 @@ // verify the pref configuration results in the expect behavior on its own. statistics_provider_.ClearMachineFlag( ash::system::kOemIsEnterpriseManagedKey); - local_state_.SetBoolean(prefs::kDeviceEnrollmentAutoStart, true); + local_state_.SetBoolean(ash::prefs::kDeviceEnrollmentAutoStart, true); { const auto config = GetPrescribedConfig(); EXPECT_EQ(EnrollmentConfig::MODE_LOCAL_ADVERTISED, config.mode); @@ -243,7 +244,7 @@ // pref configuration results in the expect behavior on its own. statistics_provider_.ClearMachineFlag( ash::system::kOemIsEnterpriseManagedKey); - local_state_.SetBoolean(prefs::kDeviceEnrollmentCanExit, false); + local_state_.SetBoolean(ash::prefs::kDeviceEnrollmentCanExit, false); { const auto config = GetPrescribedConfig(); EXPECT_EQ(EnrollmentConfig::MODE_LOCAL_FORCED, config.mode); @@ -352,7 +353,7 @@ } // Advertised enrollment gets ignored. - local_state_.SetBoolean(prefs::kDeviceEnrollmentAutoStart, true); + local_state_.SetBoolean(ash::prefs::kDeviceEnrollmentAutoStart, true); statistics_provider_.SetMachineFlag(ash::system::kOemIsEnterpriseManagedKey, true); { @@ -373,7 +374,7 @@ } // If enrollment recovery is on, this is signaled in |config.mode|. - local_state_.SetBoolean(prefs::kEnrollmentRecoveryRequired, true); + local_state_.SetBoolean(ash::prefs::kEnrollmentRecoveryRequired, true); { const auto config = GetPrescribedConfig(); EXPECT_EQ(EnrollmentConfig::MODE_RECOVERY, config.mode);
diff --git a/chrome/browser/ash/policy/enrollment/enrollment_handler.cc b/chrome/browser/ash/policy/enrollment/enrollment_handler.cc index d6cffb8..072bececd 100644 --- a/chrome/browser/ash/policy/enrollment/enrollment_handler.cc +++ b/chrome/browser/ash/policy/enrollment/enrollment_handler.cc
@@ -7,6 +7,7 @@ #include <optional> #include <utility> +#include "ash/constants/ash_pref_names.h" #include "base/base64.h" #include "base/command_line.h" #include "base/functional/bind.h" @@ -32,7 +33,6 @@ #include "chrome/browser/ash/policy/server_backed_state/server_backed_state_keys_broker.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/common/pref_names.h" #include "chromeos/ash/components/attestation/attestation_features.h" #include "chromeos/ash/components/attestation/attestation_flow.h" #include "chromeos/ash/components/dbus/constants/attestation_constants.h" @@ -130,14 +130,14 @@ } } -// Returns the PSM protocol execution result if prefs::kEnrollmentPsmResult is -// set, and its value is within the +// Returns the PSM protocol execution result if ash::prefs::kEnrollmentPsmResult +// is set, and its value is within the // em::DeviceRegisterRequest::PsmExecutionResult enum range. Otherwise, // std::nullopt. std::optional<PsmExecutionResult> GetPsmExecutionResult( const PrefService& local_state) { const PrefService::Preference* has_psm_execution_result_pref = - local_state.FindPreference(prefs::kEnrollmentPsmResult); + local_state.FindPreference(ash::prefs::kEnrollmentPsmResult); if (!has_psm_execution_result_pref || has_psm_execution_result_pref->IsDefaultValue() || @@ -160,11 +160,11 @@ } // Returns the PSM determination timestamp in ms if -// prefs::kEnrollmentPsmDeterminationTime is set. Otherwise, std::nullopt. +// ash::prefs::kEnrollmentPsmDeterminationTime is set. Otherwise, std::nullopt. std::optional<int64_t> GetPsmDeterminationTimestamp( const PrefService& local_state) { const PrefService::Preference* has_psm_determination_timestamp_pref = - local_state.FindPreference(prefs::kEnrollmentPsmDeterminationTime); + local_state.FindPreference(ash::prefs::kEnrollmentPsmDeterminationTime); if (!has_psm_determination_timestamp_pref || has_psm_determination_timestamp_pref->IsDefaultValue()) { @@ -172,7 +172,7 @@ } const base::Time psm_determination_timestamp = - local_state.GetTime(prefs::kEnrollmentPsmDeterminationTime); + local_state.GetTime(ash::prefs::kEnrollmentPsmDeterminationTime); // The PSM determination timestamp should exist at this stage. Because // we already checked the existence of the pref with non-default value. @@ -714,9 +714,9 @@ void EnrollmentHandler::StoreVersion() { DCHECK_EQ(STEP_STORE_VERSION, enrollment_step_); PrefService* prefs = g_browser_process->local_state(); - prefs->SetString(prefs::kEnrollmentVersionOS, + prefs->SetString(ash::prefs::kEnrollmentVersionOS, base::SysInfo::OperatingSystemVersion()); - prefs->SetString(prefs::kEnrollmentVersionBrowser, + prefs->SetString(ash::prefs::kEnrollmentVersionBrowser, version_info::GetVersionNumber()); prefs->CommitPendingWrite();
diff --git a/chrome/browser/ash/policy/enrollment/enrollment_requisition_manager.cc b/chrome/browser/ash/policy/enrollment/enrollment_requisition_manager.cc index 25e9ffe..1454a60 100644 --- a/chrome/browser/ash/policy/enrollment/enrollment_requisition_manager.cc +++ b/chrome/browser/ash/policy/enrollment/enrollment_requisition_manager.cc
@@ -6,6 +6,7 @@ #include <string_view> +#include "ash/constants/ash_pref_names.h" #include "base/logging.h" #include "build/config/chromebox_for_meetings/buildflags.h" #include "build/config/cuttlefish/buildflags.h" @@ -13,7 +14,6 @@ #include "chrome/browser/ash/login/demo_mode/demo_setup_controller.h" #include "chrome/browser/ash/login/startup_utils.h" #include "chrome/browser/browser_process.h" -#include "chrome/common/pref_names.h" #include "chromeos/ash/components/system/statistics_provider.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_service.h" @@ -43,13 +43,13 @@ auto* local_state = g_browser_process->local_state(); auto* provider = StatisticsProvider::GetInstance(); const PrefService::Preference* pref = - local_state->FindPreference(prefs::kDeviceEnrollmentRequisition); + local_state->FindPreference(ash::prefs::kDeviceEnrollmentRequisition); if (pref->IsDefaultValue()) { const std::optional<std::string_view> requisition = provider->GetMachineStatistic(ash::system::kOemDeviceRequisitionKey); if (requisition && !requisition->empty()) { - local_state->SetString(prefs::kDeviceEnrollmentRequisition, + local_state->SetString(ash::prefs::kDeviceEnrollmentRequisition, requisition.value()); if (requisition == kRemoraRequisition || requisition == kSharkRequisition) { @@ -58,12 +58,13 @@ const bool auto_start = StatisticsProvider::FlagValueToBool( provider->GetMachineFlag(ash::system::kOemIsEnterpriseManagedKey), /*default_value=*/false); - local_state->SetBoolean(prefs::kDeviceEnrollmentAutoStart, auto_start); + local_state->SetBoolean(ash::prefs::kDeviceEnrollmentAutoStart, + auto_start); const bool can_exit = StatisticsProvider::FlagValueToBool( provider->GetMachineFlag( ash::system::kOemCanExitEnterpriseEnrollmentKey), /*default_value=*/false); - local_state->SetBoolean(prefs::kDeviceEnrollmentCanExit, can_exit); + local_state->SetBoolean(ash::prefs::kDeviceEnrollmentCanExit, can_exit); } } } @@ -73,7 +74,7 @@ std::string EnrollmentRequisitionManager::GetDeviceRequisition() { const PrefService::Preference* pref = g_browser_process->local_state()->FindPreference( - prefs::kDeviceEnrollmentRequisition); + ash::prefs::kDeviceEnrollmentRequisition); std::string requisition; if (!pref->IsDefaultValue() && pref->GetValue()->is_string()) requisition = pref->GetValue()->GetString(); @@ -93,14 +94,15 @@ auto* local_state = g_browser_process->local_state(); if (requisition.empty()) { - local_state->ClearPref(prefs::kDeviceEnrollmentRequisition); - local_state->ClearPref(prefs::kDeviceEnrollmentAutoStart); - local_state->ClearPref(prefs::kDeviceEnrollmentCanExit); + local_state->ClearPref(ash::prefs::kDeviceEnrollmentRequisition); + local_state->ClearPref(ash::prefs::kDeviceEnrollmentAutoStart); + local_state->ClearPref(ash::prefs::kDeviceEnrollmentCanExit); } else { - local_state->SetString(prefs::kDeviceEnrollmentRequisition, requisition); + local_state->SetString(ash::prefs::kDeviceEnrollmentRequisition, + requisition); if (requisition == kNoRequisition) { - local_state->ClearPref(prefs::kDeviceEnrollmentAutoStart); - local_state->ClearPref(prefs::kDeviceEnrollmentCanExit); + local_state->ClearPref(ash::prefs::kDeviceEnrollmentAutoStart); + local_state->ClearPref(ash::prefs::kDeviceEnrollmentCanExit); } else { SetDeviceEnrollmentAutoStart(); } @@ -145,7 +147,7 @@ std::string EnrollmentRequisitionManager::GetSubOrganization() { const PrefService::Preference* pref = g_browser_process->local_state()->FindPreference( - prefs::kDeviceEnrollmentSubOrganization); + ash::prefs::kDeviceEnrollmentSubOrganization); if (!pref->IsDefaultValue() && pref->GetValue()->is_string()) return pref->GetValue()->GetString(); return std::string(); @@ -156,30 +158,31 @@ const std::string& sub_organization) { if (sub_organization.empty()) g_browser_process->local_state()->ClearPref( - prefs::kDeviceEnrollmentSubOrganization); + ash::prefs::kDeviceEnrollmentSubOrganization); else g_browser_process->local_state()->SetString( - prefs::kDeviceEnrollmentSubOrganization, sub_organization); + ash::prefs::kDeviceEnrollmentSubOrganization, sub_organization); } // static void EnrollmentRequisitionManager::SetDeviceEnrollmentAutoStart() { g_browser_process->local_state()->SetBoolean( - prefs::kDeviceEnrollmentAutoStart, true); - g_browser_process->local_state()->SetBoolean(prefs::kDeviceEnrollmentCanExit, - false); + ash::prefs::kDeviceEnrollmentAutoStart, true); + g_browser_process->local_state()->SetBoolean( + ash::prefs::kDeviceEnrollmentCanExit, false); } // static void EnrollmentRequisitionManager::RegisterPrefs(PrefRegistrySimple* registry) { - registry->RegisterStringPref(prefs::kDeviceEnrollmentRequisition, + registry->RegisterStringPref(ash::prefs::kDeviceEnrollmentRequisition, std::string()); - registry->RegisterStringPref(prefs::kDeviceEnrollmentSubOrganization, + registry->RegisterStringPref(ash::prefs::kDeviceEnrollmentSubOrganization, std::string()); - registry->RegisterBooleanPref(prefs::kDeviceEnrollmentAutoStart, false); - registry->RegisterBooleanPref(prefs::kDeviceEnrollmentCanExit, true); - registry->RegisterStringPref(prefs::kEnrollmentVersionOS, std::string()); - registry->RegisterStringPref(prefs::kEnrollmentVersionBrowser, std::string()); + registry->RegisterBooleanPref(ash::prefs::kDeviceEnrollmentAutoStart, false); + registry->RegisterBooleanPref(ash::prefs::kDeviceEnrollmentCanExit, true); + registry->RegisterStringPref(ash::prefs::kEnrollmentVersionOS, std::string()); + registry->RegisterStringPref(ash::prefs::kEnrollmentVersionBrowser, + std::string()); } } // namespace policy
diff --git a/chrome/browser/ash/policy/enrollment/enrollment_state_fetcher.cc b/chrome/browser/ash/policy/enrollment/enrollment_state_fetcher.cc index 2ea992cf..5bb8041 100644 --- a/chrome/browser/ash/policy/enrollment/enrollment_state_fetcher.cc +++ b/chrome/browser/ash/policy/enrollment/enrollment_state_fetcher.cc
@@ -11,6 +11,7 @@ #include <tuple> #include <variant> +#include "ash/constants/ash_pref_names.h" #include "ash/constants/ash_switches.h" #include "base/check.h" #include "base/memory/raw_ptr.h" @@ -153,7 +154,7 @@ }; void StorePsmError(PrefService* local_state) { - local_state->SetInteger(prefs::kEnrollmentPsmResult, + local_state->SetInteger(ash::prefs::kEnrollmentPsmResult, em::DeviceRegisterRequest::PSM_RESULT_ERROR); } @@ -452,24 +453,24 @@ } void StoreResponse(PrefService* local_state, bool is_member) { - local_state->SetTime(prefs::kEnrollmentPsmDeterminationTime, + local_state->SetTime(ash::prefs::kEnrollmentPsmDeterminationTime, base::Time::Now()); local_state->SetInteger( - prefs::kEnrollmentPsmResult, + ash::prefs::kEnrollmentPsmResult, is_member ? em::DeviceRegisterRequest::PSM_RESULT_SUCCESSFUL_WITH_STATE : em::DeviceRegisterRequest::PSM_RESULT_SUCCESSFUL_WITHOUT_STATE); } void MarkResultIgnoredForTokenBasedEnrollment(PrefService* local_state) { - local_state->SetTime(prefs::kEnrollmentPsmDeterminationTime, + local_state->SetTime(ash::prefs::kEnrollmentPsmDeterminationTime, base::Time::Now()); // TODO(b/331285209): Consider changing name of // PSM_SKIPPED_FOR_FLEX_AUTO_ENROLLMENT (unlikely since it's in a shared // proto), or adding a new value, to remove "Flex" from the name, and // change "skipped" to "ignored", as "skipped" isn't entirely accurate here. local_state->SetInteger( - prefs::kEnrollmentPsmResult, + ash::prefs::kEnrollmentPsmResult, em::DeviceRegisterRequest::PSM_SKIPPED_FOR_FLEX_AUTO_ENROLLMENT); } @@ -1081,8 +1082,8 @@ // static void EnrollmentStateFetcher::RegisterPrefs(PrefRegistrySimple* registry) { - registry->RegisterIntegerPref(prefs::kEnrollmentPsmResult, -1); - registry->RegisterTimePref(prefs::kEnrollmentPsmDeterminationTime, + registry->RegisterIntegerPref(ash::prefs::kEnrollmentPsmResult, -1); + registry->RegisterTimePref(ash::prefs::kEnrollmentPsmDeterminationTime, base::Time()); }
diff --git a/chrome/browser/ash/policy/enrollment/enrollment_state_fetcher_unittest.cc b/chrome/browser/ash/policy/enrollment/enrollment_state_fetcher_unittest.cc index 71cf60ab..941e85f 100644 --- a/chrome/browser/ash/policy/enrollment/enrollment_state_fetcher_unittest.cc +++ b/chrome/browser/ash/policy/enrollment/enrollment_state_fetcher_unittest.cc
@@ -9,6 +9,7 @@ #include <utility> #include <vector> +#include "ash/constants/ash_pref_names.h" #include "ash/constants/ash_switches.h" #include "base/functional/bind.h" #include "base/i18n/time_formatting.h" @@ -357,12 +358,13 @@ ASSERT_TRUE(defaults->GetValue(prefs::kServerBackedDeviceState, &value)); ASSERT_TRUE(value->is_dict()); EXPECT_TRUE(value->GetDict().empty()); - ASSERT_TRUE(defaults->GetValue(prefs::kEnrollmentPsmResult, &value)); + ASSERT_TRUE(defaults->GetValue(ash::prefs::kEnrollmentPsmResult, &value)); EXPECT_EQ(value->GetInt(), -1); ASSERT_TRUE( - defaults->GetValue(prefs::kEnrollmentPsmDeterminationTime, &value)); + defaults->GetValue(ash::prefs::kEnrollmentPsmDeterminationTime, &value)); EXPECT_EQ(value->GetString(), "0"); - ASSERT_TRUE(defaults->GetValue(prefs::kEnrollmentRecoveryRequired, &value)); + ASSERT_TRUE( + defaults->GetValue(ash::prefs::kEnrollmentRecoveryRequired, &value)); EXPECT_EQ(value->GetBool(), false); }
diff --git a/chrome/browser/ash/power/ml/BUILD.gn b/chrome/browser/ash/power/ml/BUILD.gn index e339d44..e1bbb2a 100644 --- a/chrome/browser/ash/power/ml/BUILD.gn +++ b/chrome/browser/ash/power/ml/BUILD.gn
@@ -43,6 +43,7 @@ "//chrome/browser/ash/power", "//chrome/browser/ash/power/ml/smart_dim", "//chrome/browser/profiles:profile", + "//chrome/browser/tab_contents", "//chrome/common:constants", "//chromeos/ash/components/dbus", "//chromeos/ash/components/install_attributes",
diff --git a/chrome/browser/ash/settings/device_settings_service.cc b/chrome/browser/ash/settings/device_settings_service.cc index 0c27159..38168d8 100644 --- a/chrome/browser/ash/settings/device_settings_service.cc +++ b/chrome/browser/ash/settings/device_settings_service.cc
@@ -6,6 +6,7 @@ #include <utility> +#include "ash/constants/ash_pref_names.h" #include "base/check.h" #include "base/check_deref.h" #include "base/check_is_test.h" @@ -18,7 +19,6 @@ #include "chrome/browser/ash/policy/off_hours/device_off_hours_controller.h" #include "chrome/browser/ash/policy/off_hours/off_hours_policy_applier.h" #include "chrome/browser/ash/settings/session_manager_operation.h" -#include "chrome/common/pref_names.h" #include "chromeos/ash/components/install_attributes/install_attributes.h" #include "components/ownership/owner_key_util.h" #include "components/policy/core/common/cloud/cloud_policy_constants.h" @@ -70,7 +70,7 @@ // before that don't have the pref on local state. const bool is_old_enrollment = !local_state || - local_state->GetString(prefs::kEnrollmentVersionOS).empty(); + local_state->GetString(ash::prefs::kEnrollmentVersionOS).empty(); const char* histogram_name; if (is_demo_mode) {
diff --git a/chrome/browser/chrome_browser_application_mac.mm b/chrome/browser/chrome_browser_application_mac.mm index 0e91128e..a1d2080 100644 --- a/chrome/browser/chrome_browser_application_mac.mm +++ b/chrome/browser/chrome_browser_application_mac.mm
@@ -5,6 +5,7 @@ #import "chrome/browser/chrome_browser_application_mac.h" #include <Carbon/Carbon.h> // for <HIToolbox/Events.h> +#include <CoreServices/CoreServices.h> #include "base/apple/call_with_eh_frame.h" #include "base/check.h" @@ -27,6 +28,10 @@ #include "content/public/common/content_features.h" #include "ui/accessibility/ax_mode.h" #include "ui/base/cocoa/accessibility_focus_overrider.h" +#include "ui/views/cocoa/native_widget_mac_ns_window_host.h" + +// https://crbug.com/491147240: Clean up code that is duplicate here and in +// chrome/app_shim/app_shim_application.mm. namespace chrome_browser_application_mac { @@ -115,6 +120,11 @@ } // namespace +@interface NSApplication (SPI) +- (void)_handleCoreEvent:(NSAppleEventDescriptor*)event + withReplyEvent:(NSAppleEventDescriptor*)reply; +@end + @interface BrowserCrApplication () <NativeEventProcessor> { // A counter for enhanced user interface enable (+1) and disable (-1) // requests. @@ -178,6 +188,49 @@ return app; } +- (void)_handleCoreEvent:(NSAppleEventDescriptor*)event + withReplyEvent:(NSAppleEventDescriptor*)reply { + // AppleEvents date back to MacOS System 7, and kAEOpenApplication has been + // used continuously since then to provide context to a newly-launched + // application. When Mac OS X was introduced, NSApplication methods were + // layered on top of these AppleEvents, and within an AppKit app, the official + // way to inspect an AppleEvent such as kAEOpenApplication has been to + // implement an appropriate NSApplicationDelegate method and call + // NSAppleEventManager.sharedAppleEventManager.currentAppleEvent. + // + // Unfortunately, that's not always a viable option. In some cases (and + // specifically in this case), the NSApplication method handling the + // AppleEvent performs further processing before calling its + // NSApplicationDelegate method, and by the time the delegate method is + // invoked, it's too late to intercept the AppleEvent. + // + // The specific parameter needed here is keyAERestoreAppState, whose header + // documentation reads: + // + // "If present in a kAEOpenApplication or kAEReopenApplication AppleEvent, + // with the value kAEYes, then any saved application state should be + // restored; if present and kAENo, then any saved application state should + // not be restored." + // + // One thing to note is that this parameter might be present on either + // kAEOpenApplication or kAEReopenApplication. Those are both kCoreEventClass, + // therefore that is why _handleCoreEvent:withReplyEvent: is overridden, as + // that is the funnel for all incoming kCoreEventClass AppleEvents. + // + // The other thing to note is that Chromium does not care about macOS's + // decision to restore or not restore application state; Chromium has its own + // preference for that. However, if the keyAERestoreAppState parameter is + // present, that means that macOS launched Chromium as relaunching quit apps + // after a system restart, and therefore the existence of that parameter is + // all that needs to be determined. + if ([event paramDescriptorForKeyword:keyAERestoreAppState]) { + views::NativeWidgetMacNSWindowHost:: + MoveWindowsToOriginalSpacesUponRestoration(); + } + + [super _handleCoreEvent:event withReplyEvent:reply]; +} + - (void)finishLaunching { [super finishLaunching];
diff --git a/chrome/browser/chrome_browser_interface_binders_webui_parts_desktop.cc b/chrome/browser/chrome_browser_interface_binders_webui_parts_desktop.cc index c3a064d..138ba6b3 100644 --- a/chrome/browser/chrome_browser_interface_binders_webui_parts_desktop.cc +++ b/chrome/browser/chrome_browser_interface_binders_webui_parts_desktop.cc
@@ -29,11 +29,14 @@ #include "chrome/browser/ui/views/side_panel/history/history_side_panel_coordinator.h" #include "chrome/browser/ui/webui/access_code_cast/access_code_cast.mojom.h" #include "chrome/browser/ui/webui/access_code_cast/access_code_cast_ui.h" +#include "chrome/browser/ui/webui/ai_overlay_dialog/ai_overlay_dialog.mojom.h" +#include "chrome/browser/ui/webui/ai_overlay_dialog/ai_overlay_dialog_untrusted_ui.h" #include "chrome/browser/ui/webui/app_service_internals/app_service_internals.mojom.h" #include "chrome/browser/ui/webui/app_service_internals/app_service_internals_ui.h" #include "chrome/browser/ui/webui/autofill_ml_internals/autofill_ml_internals_ui.h" #include "chrome/browser/ui/webui/color_pipeline_internals/color_pipeline_internals_ui.h" #include "chrome/browser/ui/webui/commerce/shopping_insights_side_panel_ui.h" +#include "chrome/browser/ui/webui/content_annotator_internals/content_annotator_internals_ui.h" #include "chrome/browser/ui/webui/customize_buttons/customize_buttons.mojom.h" #include "chrome/browser/ui/webui/data_sharing/data_sharing.mojom.h" #include "chrome/browser/ui/webui/data_sharing/data_sharing_ui.h" @@ -91,6 +94,7 @@ #include "chrome/browser/ui/webui_browser/webui_browser.h" #include "chrome/browser/ui/webui_browser/webui_browser_ui.h" #include "chrome/common/chrome_features.h" +#include "components/accessibility_annotator/core/logging/accessibility_annotator_internals.mojom.h" #include "components/autofill/core/browser/ml_model/logging/autofill_ml_internals.mojom.h" #include "components/browser_apis/browser_controls/browser_controls_api.mojom.h" #include "components/browser_apis/ui_controllers/toolbar/toolbar_ui_api.mojom.h" @@ -490,6 +494,10 @@ UserEducationInternalsUI>(map); RegisterWebUIControllerInterfaceBinder< + accessibility_annotator_internals::mojom::PageHandlerFactory, + content_annotator_internals::ContentAnnotatorInternalsUI>(map); + + RegisterWebUIControllerInterfaceBinder< ::mojom::app_service_internals::AppServiceInternalsPageHandler, AppServiceInternalsUI>(map); @@ -723,6 +731,11 @@ registry.ForWebUI<glic::SelectionOverlayUntrustedUI>() .Add<glic::selection::SelectionOverlayPageHandlerFactory>(); } + + if (base::FeatureList::IsEnabled(features::kAiOverlayDialog)) { + registry.ForWebUI<AiOverlayDialogUntrustedUI>() + .Add<ai_overlay_dialog::mojom::PageHandlerFactory>(); + } } } // namespace chrome::internal
diff --git a/chrome/browser/chrome_browser_main_mac.mm b/chrome/browser/chrome_browser_main_mac.mm index bd54e3e..79cbbf1 100644 --- a/chrome/browser/chrome_browser_main_mac.mm +++ b/chrome/browser/chrome_browser_main_mac.mm
@@ -149,9 +149,10 @@ // apps after a restart, and puts them all on the current space when an app // is manually quit and relaunched. If Chrome restarted itself, set a flag in // Views to have it restore spaces. - views::NativeWidgetMacNSWindowHost:: - SetMoveWindowsToOriginalSpacesUponRestoration( - local_state->GetBoolean(prefs::kWasRestarted)); + if (local_state->GetBoolean(prefs::kWasRestarted)) { + views::NativeWidgetMacNSWindowHost:: + MoveWindowsToOriginalSpacesUponRestoration(); + } } void ChromeBrowserMainPartsMac::PostCreateMainMessageLoop() {
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index 3438333..0d9f0df 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -933,10 +933,12 @@ // Allow Autoplay if the user provided mic/cam access. This is for cases such // as received-video-call rings occurring before the user interacted with the - // page. - if (base::FeatureList::IsEnabled(media::kAutoplayBypassForMicCamera)) { - const HostContentSettingsMap* const content_settings = - HostContentSettingsMapFactory::GetForProfile(profile); + // page. If there is no content_settings, we cannot provide autoplay (e.g. + // System profile). + const HostContentSettingsMap* const content_settings = + HostContentSettingsMapFactory::GetForProfile(profile); + if (content_settings && + base::FeatureList::IsEnabled(media::kAutoplayBypassForMicCamera)) { const GURL& url = web_contents->GetLastCommittedURL(); if (content_settings->GetContentSetting(
diff --git a/chrome/browser/chromeos/extensions/login_screen/login/shared_session_handler.cc b/chrome/browser/chromeos/extensions/login_screen/login/shared_session_handler.cc index daa0dd1..2db19fe 100644 --- a/chrome/browser/chromeos/extensions/login_screen/login/shared_session_handler.cc +++ b/chrome/browser/chromeos/extensions/login_screen/login/shared_session_handler.cc
@@ -268,9 +268,9 @@ .max_memory_bytes = 1024 * 1024 * 32, }; std::array<uint8_t, kHashKeyLength> result; - crypto::kdf::DeriveKeyScrypt(kScryptParams, base::as_byte_span(password), - base::as_byte_span(salt), result, - MakeCryptoPassKeyForSharedSessionHandler()); + crypto::kdf::Scrypt(kScryptParams, base::as_byte_span(password), + base::as_byte_span(salt), result, + MakeCryptoPassKeyForSharedSessionHandler()); return std::string(base::as_string_view(result)); }
diff --git a/chrome/browser/contextual_cueing/contextual_cueing_helper.cc b/chrome/browser/contextual_cueing/contextual_cueing_helper.cc index af32bb2..a9f1f2e7 100644 --- a/chrome/browser/contextual_cueing/contextual_cueing_helper.cc +++ b/chrome/browser/contextual_cueing/contextual_cueing_helper.cc
@@ -179,6 +179,7 @@ if (glic_nudge_controller) { glic_nudge_controller->UpdateNudgeLabel( web_contents(), std::string(), /*prompt_suggestion=*/std::nullopt, + /*anchored_message_text=*/std::string(), glic::GlicNudgeActivity::kNudgeIgnoredNavigation, base::DoNothing()); } @@ -388,8 +389,6 @@ return; } - std::string cue_label = decision_result.value().cue_label; - std::string prompt_suggestion = decision_result.value().prompt_suggestion; if (IsBrowserBlockingNudges(decision_recorder.get())) { return; } @@ -433,20 +432,23 @@ invocation_source = glic::mojom::InvocationSource::kAutoOpenedForPdf; } - glic_service->ToggleUI(browser_window_interface, - /*prevent_close=*/true, invocation_source, - prompt_suggestion.empty() - ? std::nullopt - : std::make_optional(prompt_suggestion)); + glic_service->ToggleUI( + browser_window_interface, + /*prevent_close=*/true, invocation_source, + decision_result->prompt_suggestion.empty() + ? std::nullopt + : std::make_optional(decision_result->prompt_suggestion)); return; } // Fall through to nudge if side panel open fails. } GetGlicNudgeController()->UpdateNudgeLabel( - web_contents(), cue_label, - prompt_suggestion.empty() ? std::nullopt - : std::make_optional(prompt_suggestion), + web_contents(), decision_result->cue_label, + decision_result->prompt_suggestion.empty() + ? std::nullopt + : std::make_optional(decision_result->prompt_suggestion), + decision_result->anchored_message_text, /*activity=*/std::nullopt, base::BindRepeating(&ContextualCueingService::OnNudgeActivity, contextual_cueing_service_->GetWeakPtr(),
diff --git a/chrome/browser/contextual_cueing/contextual_cueing_helper_interactive_uitest.cc b/chrome/browser/contextual_cueing/contextual_cueing_helper_interactive_uitest.cc index 8f7bdc81..36c4f78c 100644 --- a/chrome/browser/contextual_cueing/contextual_cueing_helper_interactive_uitest.cc +++ b/chrome/browser/contextual_cueing/contextual_cueing_helper_interactive_uitest.cc
@@ -56,6 +56,16 @@ future_.SetValue(); } } + void OnTriggerAnchoredMessage( + std::string label, + std::string anchored_message_text, + std::optional<std::string> prompt_suggestion) override { + last_nudge_label_ = label; + if (!last_nudge_label_.empty()) { + is_showing_nudge_ = true; + future_.SetValue(); + } + } void OnHideGlicNudgeUI() override { is_showing_nudge_ = false; } bool GetIsShowingGlicNudge() override { return is_showing_nudge_; } void WaitUntilValidNudge() { future_.Get(); }
diff --git a/chrome/browser/contextual_tasks/BUILD.gn b/chrome/browser/contextual_tasks/BUILD.gn index 6e27ec07..7f49083 100644 --- a/chrome/browser/contextual_tasks/BUILD.gn +++ b/chrome/browser/contextual_tasks/BUILD.gn
@@ -133,6 +133,7 @@ "contextual_tasks_navigation_throttle.h", "contextual_tasks_page_handler.h", "contextual_tasks_side_panel_coordinator.h", + "contextual_tasks_ui.h", "contextual_tasks_ui_service.h", "contextual_tasks_ui_service_factory.h", "entry_point_eligibility_manager.h", @@ -146,7 +147,6 @@ sources += [ "contextual_tasks_composebox_handler.h", "contextual_tasks_panel_host_desktop_impl.h", - "contextual_tasks_ui.h", "contextual_tasks_web_view.h", ] } @@ -160,14 +160,17 @@ ":mojo_bindings", "//base", "//chrome/browser/tab_list", + "//chrome/common:url_constants", "//components/contextual_search:public", "//components/prefs", "//components/signin/public/identity_manager", "//components/tabs:public", "//content/public/browser", + "//content/public/common", "//third_party/lens_server_proto:lens_overlay_proto", "//third_party/omnibox_proto", "//ui/base/unowned_user_data", + "//ui/webui", ] if (!is_android) { @@ -198,8 +201,10 @@ "contextual_search_session_finder.h", "contextual_tasks_cookie_synchronizer.cc", "contextual_tasks_internals_page_handler.cc", + "contextual_tasks_navigation_throttle.cc", "contextual_tasks_page_handler.cc", "contextual_tasks_side_panel_coordinator.cc", + "contextual_tasks_ui.cc", "contextual_tasks_ui_service.cc", "contextual_tasks_ui_service_factory.cc", "contextual_tasks_url_loader_factory_interceptor.h", @@ -213,9 +218,7 @@ if (!is_android) { sources += [ "contextual_tasks_composebox_handler.cc", - "contextual_tasks_navigation_throttle.cc", "contextual_tasks_panel_host_desktop_impl.cc", - "contextual_tasks_ui.cc", "contextual_tasks_url_loader_factory_interceptor.cc", "contextual_tasks_web_view.cc", ] @@ -237,6 +240,7 @@ "//chrome/browser/feedback:feedback_enum", "//chrome/browser/optimization_guide", "//chrome/browser/profiles:profile", + "//chrome/browser/resources/contextual_tasks:resources", "//chrome/browser/search_engines", "//chrome/browser/signin", "//chrome/browser/tab_list", @@ -256,6 +260,7 @@ "//components/sessions", "//components/shared_highlighting/core/common", "//components/tabs:public", + "//content/public/browser", "//google_apis", "//net", ]
diff --git a/chrome/browser/contextual_tasks/contextual_tasks_composebox_handler_unittest.cc b/chrome/browser/contextual_tasks/contextual_tasks_composebox_handler_unittest.cc index d96a23d..f541a3b 100644 --- a/chrome/browser/contextual_tasks/contextual_tasks_composebox_handler_unittest.cc +++ b/chrome/browser/contextual_tasks/contextual_tasks_composebox_handler_unittest.cc
@@ -1166,6 +1166,7 @@ const auto& param = GetParam(); handler_->SetActiveToolMode(param.tool_mode); + handler_->RecordToolSelectionAction(param.tool_mode); EXPECT_CALL(*mock_controller_, CreateClientToAimRequest(testing::_)) .WillOnce([&](std::unique_ptr<
diff --git a/chrome/browser/contextual_tasks/contextual_tasks_page_handler.cc b/chrome/browser/contextual_tasks/contextual_tasks_page_handler.cc index 06ffb78..e0d6e7d6 100644 --- a/chrome/browser/contextual_tasks/contextual_tasks_page_handler.cc +++ b/chrome/browser/contextual_tasks/contextual_tasks_page_handler.cc
@@ -282,6 +282,7 @@ } } } +#if !BUILDFLAG(IS_ANDROID) chrome::ShowFeedbackPage(page_url, web_ui_controller_->GetProfile(), feedback::kFeedbackSourceAI, /*description_template=*/std::string(), @@ -289,6 +290,7 @@ l10n_util::GetStringUTF8(IDS_LENS_SEND_FEEDBACK), /*category_tag=*/"cobrowse", /*extra_diagnostics=*/std::string()); +#endif } void ContextualTasksPageHandler::OpenOnboardingHelpUi() {
diff --git a/chrome/browser/contextual_tasks/contextual_tasks_side_panel_coordinator.cc b/chrome/browser/contextual_tasks/contextual_tasks_side_panel_coordinator.cc index f794075..e8b6695 100644 --- a/chrome/browser/contextual_tasks/contextual_tasks_side_panel_coordinator.cc +++ b/chrome/browser/contextual_tasks/contextual_tasks_side_panel_coordinator.cc
@@ -299,6 +299,7 @@ browser_window_->GetFeatures().glic_nudge_controller()) { glic_nudge_controller->UpdateNudgeLabel( active_tab_interface->GetContents(), "", std::nullopt, + /*anchored_message_text=*/std::string(), glic::GlicNudgeActivity::kNudgeIgnoredOpenedContextualTasksSidePanel, base::DoNothing()); }
diff --git a/chrome/browser/contextual_tasks/contextual_tasks_ui.cc b/chrome/browser/contextual_tasks/contextual_tasks_ui.cc index 455bf8b..c0e7f2e 100644 --- a/chrome/browser/contextual_tasks/contextual_tasks_ui.cc +++ b/chrome/browser/contextual_tasks/contextual_tasks_ui.cc
@@ -19,7 +19,6 @@ #include "chrome/browser/contextual_search/contextual_search_web_contents_helper.h" #include "chrome/browser/contextual_tasks/active_task_context_provider.h" #include "chrome/browser/contextual_tasks/contextual_search_session_finder.h" -#include "chrome/browser/contextual_tasks/contextual_tasks_composebox_handler.h" #include "chrome/browser/contextual_tasks/contextual_tasks_context_service_factory.h" #include "chrome/browser/contextual_tasks/contextual_tasks_internals_page_handler.h" #include "chrome/browser/contextual_tasks/contextual_tasks_page_handler.h" @@ -32,16 +31,12 @@ #include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_attributes_storage.h" -#include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/signin/identity_manager_factory.h" +#include "chrome/browser/tab_list/tab_list_interface.h" #include "chrome/browser/themes/theme_service.h" #include "chrome/browser/themes/theme_service_factory.h" -#include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/browser_window/public/browser_window_features.h" #include "chrome/browser/ui/browser_window/public/browser_window_interface.h" -#include "chrome/browser/ui/lens/lens_search_controller.h" -#include "chrome/browser/ui/views/frame/browser_view.h" -#include "chrome/browser/ui/webui/cr_components/searchbox/searchbox_handler.h" #include "chrome/browser/ui/webui/new_tab_page/composebox/variations/composebox_fieldtrial.h" #include "chrome/browser/ui/webui/sanitized_image_source.h" #include "chrome/browser/ui/webui/webui_embedding_context.h" @@ -60,7 +55,6 @@ #include "components/lens/lens_features.h" #include "components/lens/lens_overlay_invocation_source.h" #include "components/omnibox/browser/aim_eligibility_service.h" -#include "components/omnibox/browser/searchbox.mojom-forward.h" #include "components/omnibox/common/logger.h" #include "components/prefs/pref_service.h" #include "components/sessions/content/session_tab_helper.h" @@ -79,10 +73,22 @@ #include "google_apis/gaia/gaia_constants.h" #include "google_apis/gaia/google_service_auth_error.h" #include "net/base/backoff_entry.h" +#include "net/base/url_util.h" +#include "net/http/http_response_headers.h" #include "third_party/lens_server_proto/aim_communication.pb.h" #include "ui/base/l10n/l10n_util.h" #include "ui/webui/webui_util.h" +#if !BUILDFLAG(IS_ANDROID) +#include "chrome/browser/contextual_tasks/contextual_tasks_composebox_handler.h" +#include "chrome/browser/profiles/profile_manager.h" // nogncheck crbug.com/483442073 +#include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/lens/lens_search_controller.h" +#include "chrome/browser/ui/views/frame/browser_view.h" +#include "chrome/browser/ui/webui/cr_components/searchbox/searchbox_handler.h" +#include "components/omnibox/browser/searchbox.mojom-forward.h" +#endif + namespace { // A method to add eligibility booleans for context menu items that are shown @@ -113,12 +119,7 @@ } BrowserWindowInterface* FromWebContents(content::WebContents* web_contents) { - BrowserWindow* window = - BrowserWindow::FindBrowserWindowWithWebContents(web_contents); - if (window) { - return window->AsBrowserView()->browser(); - } - return nullptr; + return webui::GetBrowserWindowInterface(web_contents); } std::string GetEncodedHandshakeMessage() { @@ -200,10 +201,14 @@ return; } - ProfileAttributesEntry* entry = - g_browser_process->profile_manager() - ->GetProfileAttributesStorage() - .GetProfileAttributesWithPath(profile->GetPath()); + ProfileAttributesEntry* entry = nullptr; +#if !BUILDFLAG(IS_ANDROID) + // TODO(crbug.com/483442073): Remove the ifdef block once we address the + // cyclic dependency. + entry = g_browser_process->profile_manager() + ->GetProfileAttributesStorage() + .GetProfileAttributesWithPath(profile->GetPath()); +#endif if (!entry) { AddDefaultZeroStateStrings(source); return; @@ -265,8 +270,12 @@ base::BindRepeating(&ContextualTasksUI::ResetEmbeddedPage, weak_ptr_factory_.GetWeakPtr())); // Add a means of loading images fromexternal sources. +#if !BUILDFLAG(IS_ANDROID) + // TODO(crbug.com/483442073): SanitizedImageSource is not available on + // Android. Need to find an alternative. content::URLDataSource::Add(profile, std::make_unique<SanitizedImageSource>(profile)); +#endif content::WebUIDataSource* source = content::WebUIDataSource::CreateAndAdd( web_ui->GetWebContents()->GetBrowserContext(), chrome::kChromeUIContextualTasksHost); @@ -278,10 +287,12 @@ network::mojom::CSPDirectiveName::ChildSrc, "child-src 'self' https://*.google.com;"); +#if !BUILDFLAG(IS_ANDROID) // Add required resources for the searchbox. SearchboxHandler::SetupWebUIDataSource(source, profile, /*enable_voice_search=*/true, /*enable_lens_search=*/false); +#endif // Add strings.js source->UseStringsJs(); @@ -315,8 +326,10 @@ {"oauthErrorDialogBody", IDS_CONTEXTUAL_TASKS_OAUTH_ERROR_DIALOG_BODY}, {"oauthErrorDialogReloadButton", IDS_CONTEXTUAL_TASKS_OAUTH_ERROR_DIALOG_RELOAD_BUTTON}, +#if !BUILDFLAG(IS_ANDROID) {"composeboxHintTextLensOverlay", IDS_LENS_COMPOSEBOX_HINT_TEXT_SELECT_PAGE}, +#endif }; source->AddLocalizedStrings(kLocalizedStrings); source->AddLocalizedString( @@ -335,9 +348,6 @@ source->AddInteger( "composeboxFileMaxSize", contextual_tasks::kContextualTasksNextboxMaxFileSize.Get()); - source->AddInteger( - "composeboxFileMaxCount", - contextual_tasks::kContextualTasksNextboxMaxFileCount.Get()); source->AddBoolean("composeboxNoFlickerSuggestionsFix", false); // Enable typed suggest. source->AddBoolean("composeboxShowTypedSuggest", false); @@ -408,9 +418,6 @@ contextual_tasks::GetIsSteadyComposeboxVoiceSearchEnabled()); source->AddBoolean("composeboxShowContextMenuTabPreviews", false); source->AddBoolean("composeboxContextMenuEnableMultiTabSelection", true); - source->AddBoolean( - "darkMode", - ThemeServiceFactory::GetForProfile(profile)->BrowserUsesDarkColors()); source->AddBoolean("clearAllInputsWhenSubmittingQuery", true); source->AddBoolean("autoSubmitVoiceSearchQuery", contextual_tasks::GetAutoSubmitVoiceSearchQuery()); @@ -433,12 +440,17 @@ contextual_search::ContextualSearchMetricsRecorder:: ContextualSearchSourceToString( contextual_search::ContextualSearchSource::kContextualTasks)); +#if !BUILDFLAG(IS_ANDROID) + source->AddBoolean( + "darkMode", + ThemeServiceFactory::GetForProfile(profile)->BrowserUsesDarkColors()); source->AddLocalizedString( "protectedErrorPageTopLine", IDS_SIDE_PANEL_LENS_OVERLAY_PROTECTED_PAGE_ERROR_FIRST_LINE); source->AddLocalizedString( "protectedErrorPageBottomLine", IDS_SIDE_PANEL_LENS_OVERLAY_PROTECTED_PAGE_ERROR_SECOND_LINE); +#endif source->AddString("userAgentSuffix", contextual_tasks::GetContextualTasksUserAgentSuffix()); @@ -501,6 +513,7 @@ page_handler_ = std::make_unique<ContextualTasksPageHandler>( std::move(page_handler), this, ui_service_, contextual_tasks_service_); +#if !BUILDFLAG(IS_ANDROID) // Determine if the Lens overlay is showing when the page is created. if (auto* browser = GetBrowser()) { if (auto* controller = LensSearchController::FromTabWebContents( @@ -509,6 +522,7 @@ controller->invocation_source()); } } +#endif } void ContextualTasksUI::OnRefreshTokenUpdatedForAccount( @@ -542,10 +556,12 @@ void ContextualTasksUI::SetTaskId(std::optional<base::Uuid> id) { task_id_ = id; PushTaskDetailsToPage(); +#if !BUILDFLAG(IS_ANDROID) // Initialize input state once task id is available. if (composebox_handler_) { composebox_handler_->InitializeInputStateModel(); } +#endif } const std::optional<std::string>& ContextualTasksUI::GetThreadId() { @@ -588,11 +604,13 @@ if (is_ai_page && !was_ai_page_) { auto* browser = GetBrowser(); if (browser) { +#if !BUILDFLAG(IS_ANDROID) if (auto* controller = LensSearchController::FromTabWebContents( browser->GetTabStripModel()->GetActiveWebContents())) { controller->CloseLensAsync( lens::LensOverlayDismissalSource::kContextualTasksQuerySubmitted); } +#endif } } was_ai_page_ = is_ai_page; @@ -662,6 +680,7 @@ return std::make_unique<ContextualTasksUI>(web_ui); } +#if !BUILDFLAG(IS_ANDROID) void ContextualTasksUI::BindInterface( mojo::PendingReceiver<composebox::mojom::PageHandlerFactory> pending_receiver) { @@ -688,6 +707,7 @@ base::Unretained(this))); composebox_handler_->SetPage(std::move(pending_searchbox_page)); } +#endif // !BUILDFLAG(IS_ANDROID) contextual_search::ContextualSearchSessionHandle* ContextualTasksUI::GetOrCreateContextualSessionHandle() { @@ -711,7 +731,7 @@ if (!task_id_) { if (contextual_search_service) { auto session_handle = contextual_search_service->CreateSession( - ntp_composebox::CreateQueryControllerConfigParams(), + contextual_tasks::CreateQueryControllerConfigParams(), contextual_search::ContextualSearchSource::kContextualTasks, lens::LensOverlayInvocationSource::kContextualTasksComposebox); // TODO(crbug.com/469875164): Determine what to do with the return value @@ -726,7 +746,8 @@ // If no valid session exists, maintains context continuity by trying to find // one from affiliated tabs or side panel WebContents. - auto* controller = GetPanelController(); + contextual_tasks::ContextualTasksPanelController* controller = + GetPanelController(); if (!controller || !task_id_.has_value()) { return nullptr; } @@ -820,7 +841,8 @@ // If active tab or tab URL changed since the GetContextForTask() call, do // nothing. - tabs::TabInterface* tab = GetBrowser()->GetActiveTabInterface(); + tabs::TabInterface* tab = + TabListInterface::From(GetBrowser())->GetActiveTab(); if (!tab || tab->GetHandle().raw_value() != tab_id || tab->GetContents()->GetLastCommittedURL() != last_committed_url) { return; @@ -833,7 +855,9 @@ contextual_tasks::CreateURLDeduplicationHelperForContextualTask(); if (context && context->ContainsURL(last_committed_url, url_duplication_helper.get())) { +#if !BUILDFLAG(IS_ANDROID) composebox_handler_->UpdateSuggestedTabContext(nullptr); +#endif return; } @@ -841,6 +865,7 @@ } void ContextualTasksUI::UpdateSuggestedTabContext(tabs::TabInterface* tab) { +#if !BUILDFLAG(IS_ANDROID) content::WebContents* web_contents = tab->GetContents(); auto tab_data = searchbox::mojom::TabInfo::New(); tab_data->tab_id = tab->GetHandle().raw_value(); @@ -849,6 +874,7 @@ tab_data->last_active = std::max(web_contents->GetLastActiveTimeTicks(), web_contents->GetLastInteractionTimeTicks()); composebox_handler_->UpdateSuggestedTabContext(std::move(tab_data)); +#endif } void ContextualTasksUI::OnSidePanelStateChanged() { @@ -861,9 +887,11 @@ lens::CobrowsingDisplayModeParams::COBROWSING_TAB); if (previous_web_ui_state_ != WebUIState::kShownInTab) { previous_web_ui_state_ = WebUIState::kShownInTab; +#if !BUILDFLAG(IS_ANDROID) if (composebox_handler_) { composebox_handler_->UpdateSuggestedTabContext(nullptr); } +#endif } } else { if (previous_web_ui_state_ != WebUIState::kShownInSidePanel && @@ -904,9 +932,11 @@ return false; } +#if !BUILDFLAG(IS_ANDROID) if (!composebox_handler_) { return false; } +#endif if (!tab) { return false; @@ -930,15 +960,18 @@ } tabs::TabInterface* tab = - GetBrowser() ? GetBrowser()->GetActiveTabInterface() : nullptr; + GetBrowser() ? TabListInterface::From(GetBrowser())->GetActiveTab() + : nullptr; GURL last_committed_url = tab ? tab->GetContents()->GetLastCommittedURL() : GURL::EmptyGURL(); if (!CanUpdateSuggestedTabContext(tab, last_committed_url)) { +#if !BUILDFLAG(IS_ANDROID) if (composebox_handler_) { // Inform the handler that the current tab cannot be added as an autochip. composebox_handler_->UpdateSuggestedTabContext(nullptr); } +#endif return; } @@ -996,8 +1029,12 @@ } bool ContextualTasksUI::IsActiveTabContextSuggestionShowing() const { +#if !BUILDFLAG(IS_ANDROID) return composebox_handler_ && composebox_handler_->has_suggested_tab_context(); +#else + return false; +#endif } void ContextualTasksUI::PushTaskDetailsToPage() { @@ -1314,20 +1351,26 @@ } void ContextualTasksUI::PrepareForTaskChange() { +#if !BUILDFLAG(IS_ANDROID) composebox_handler_->ResetInputStateModel(); composebox_handler_->ResetBlocklistedSuggestions(); composebox_handler_->UpdateSuggestedTabContext(nullptr); +#endif } void ContextualTasksUI::OnTaskChanged() { +#if !BUILDFLAG(IS_ANDROID) composebox_handler_->OnTaskChanged(); +#endif if (!IsShownInTab()) { // Update the suggested tab chip. OnActiveTabContextStatusChanged(); } } +#if !BUILDFLAG(IS_ANDROID) // static +// Favicons for WebUI pages are only used on desktop builds. base::RefCountedMemory* ContextualTasksUI::GetFaviconResourceBytes( ui::ResourceScaleFactor scale_factor) { #if BUILDFLAG(GOOGLE_CHROME_BRANDING) @@ -1340,6 +1383,7 @@ return static_cast<base::RefCountedMemory*>( ui::ResourceBundle::GetSharedInstance().LoadDataResourceBytesForScale( IDR_NTP_FAVICON, scale_factor)); -#endif +#endif // BUILDFLAG(GOOGLE_CHROME_BRANDING) } +#endif // !BUILDFLAG(IS_ANDROID) WEB_UI_CONTROLLER_TYPE_IMPL(ContextualTasksUI)
diff --git a/chrome/browser/contextual_tasks/contextual_tasks_ui.h b/chrome/browser/contextual_tasks/contextual_tasks_ui.h index 6c93707..ee81d6ea 100644 --- a/chrome/browser/contextual_tasks/contextual_tasks_ui.h +++ b/chrome/browser/contextual_tasks/contextual_tasks_ui.h
@@ -14,7 +14,7 @@ #include "base/scoped_observation.h" #include "base/timer/timer.h" #include "base/uuid.h" -#include "chrome/browser/contextual_tasks/contextual_tasks_composebox_handler.h" +#include "build/buildflag.h" #include "chrome/browser/contextual_tasks/contextual_tasks_cookie_synchronizer.h" #include "chrome/browser/contextual_tasks/contextual_tasks_internals.mojom.h" #include "chrome/browser/contextual_tasks/contextual_tasks_page_handler.h" @@ -23,6 +23,7 @@ #include "chrome/browser/contextual_tasks/task_info_delegate.h" #include "chrome/common/webui_url_constants.h" #include "components/contextual_search/contextual_search_session_handle.h" +#include "components/contextual_search/input_state_model.h" #include "components/contextual_tasks/public/contextual_task_context.h" #include "components/contextual_tasks/public/contextual_tasks_service.h" #include "components/lens/lens_overlay_invocation_source.h" @@ -38,7 +39,11 @@ #include "third_party/lens_server_proto/aim_communication.pb.h" #include "ui/base/resource/resource_scale_factor.h" #include "ui/webui/mojo_web_ui_controller.h" + +#if !BUILDFLAG(IS_ANDROID) +#include "chrome/browser/contextual_tasks/contextual_tasks_composebox_handler.h" #include "ui/webui/resources/cr_components/composebox/composebox.mojom.h" +#endif class BrowserWindowInterface; @@ -66,7 +71,9 @@ : public contextual_tasks::ContextualTasksUIInterface, public ui::MojoWebUIController, public contextual_tasks::mojom::PageHandlerFactory, +#if !BUILDFLAG(IS_ANDROID) public composebox::mojom::PageHandlerFactory, +#endif public contextual_tasks_internals::mojom:: ContextualTasksInternalsPageHandlerFactory, public signin::IdentityManager::Observer, @@ -103,6 +110,7 @@ ContextualTasksUI& operator=(const ContextualTasksUI&) = delete; ~ContextualTasksUI() override; +#if !BUILDFLAG(IS_ANDROID) // composebox::mojom::PageHandlerFactory: void CreatePageHandler( mojo::PendingRemote<composebox::mojom::Page> pending_page, @@ -112,6 +120,13 @@ mojo::PendingReceiver<searchbox::mojom::PageHandler> pending_searchbox_handler) override; + // Instantiates the implementor of the + // composebox::mojom::PageHandlerFactory mojo interface passing the + // pending receiver that will be internally bound. + void BindInterface( + mojo::PendingReceiver<composebox::mojom::PageHandlerFactory> receiver); +#endif + // contextual_tasks::mojom::PageHandlerFactory: void CreatePageHandler( mojo::PendingRemote<contextual_tasks::mojom::Page> page, @@ -187,12 +202,6 @@ mojo::PendingReceiver<contextual_tasks::mojom::PageHandlerFactory> pending_receiver); - // Instantiates the implementor of the - // composebox::mojom::PageHandlerFactory mojo interface passing the - // pending receiver that will be internally bound. - void BindInterface( - mojo::PendingReceiver<composebox::mojom::PageHandlerFactory> receiver); - // Instantiates the implementor of the contextual_tasks::mojom:: // ContextualTasksInternalsPageHandlerFactory mojo interface passing the // pending receiver that will be internally bound. @@ -218,10 +227,12 @@ void OnRefreshTokenUpdatedForAccount( const CoreAccountInfo& account_info) override; +#if !BUILDFLAG(IS_ANDROID) void SetComposeboxHandlerForTesting( std::unique_ptr<ContextualTasksComposeboxHandler> handler) { composebox_handler_ = std::move(handler); } +#endif // Shows an OAuth error dialog. void ShowOauthErrorDialog(); @@ -281,21 +292,25 @@ contextual_tasks::ContextualTasksPanelController* GetPanelController(); - std::unique_ptr<ContextualTasksComposeboxHandler> composebox_handler_; std::unique_ptr<contextual_tasks::ContextualTasksCookieSynchronizer> cookie_synchronizer_; raw_ptr<contextual_tasks::ContextualTasksUiService> ui_service_; raw_ptr<contextual_tasks::ContextualTasksService> contextual_tasks_service_; - mojo::Receiver<composebox::mojom::PageHandlerFactory> - composebox_page_handler_factory_receiver_{this}; - mojo::Receiver<contextual_tasks::mojom::PageHandlerFactory> contextual_tasks_page_handler_factory_receiver_{this}; std::unique_ptr<ContextualTasksPageHandler> page_handler_; + +#if !BUILDFLAG(IS_ANDROID) + std::unique_ptr<ContextualTasksComposeboxHandler> composebox_handler_; + + mojo::Receiver<composebox::mojom::PageHandlerFactory> + composebox_page_handler_factory_receiver_{this}; + mojo::Remote<composebox::mojom::Page> page_remote_; +#endif std::unique_ptr<InnerFrameCreationObvserver> inner_web_contents_creation_observer_;
diff --git a/chrome/browser/contextual_tasks/contextual_tasks_ui_service.cc b/chrome/browser/contextual_tasks/contextual_tasks_ui_service.cc index 02fa6b9..8d8fe6cd 100644 --- a/chrome/browser/contextual_tasks/contextual_tasks_ui_service.cc +++ b/chrome/browser/contextual_tasks/contextual_tasks_ui_service.cc
@@ -1223,8 +1223,12 @@ Navigate(¶ms); } else { - std::unique_ptr<content::WebContents> web_contents = - controller->DetachWebContentsForTask(task_id); + std::unique_ptr<content::WebContents> web_contents = nullptr; +#if !BUILDFLAG(IS_ANDROID) + // TODO(crbug.com/483442073): Remove TabStripModel once we add missing + // APIs to TabListInterface. + web_contents = controller->DetachWebContentsForTask(task_id); +#endif if (!web_contents) { return; }
diff --git a/chrome/browser/device_identity/chromeos/token_encryptor.cc b/chrome/browser/device_identity/chromeos/token_encryptor.cc index 943b0e5..66b36e3 100644 --- a/chrome/browser/device_identity/chromeos/token_encryptor.cc +++ b/chrome/browser/device_identity/chromeos/token_encryptor.cc
@@ -37,8 +37,8 @@ CHECK(!system_salt.empty()); auto salt = base::as_byte_span(system_salt); - crypto::kdf::DeriveKeyPbkdf2HmacSha1(kPbkdf2Params, salt, salt, key_, - crypto::SubtlePassKey{}); + crypto::kdf::Pbkdf2HmacSha1(kPbkdf2Params, salt, salt, key_, + crypto::SubtlePassKey{}); base::span(nonce_).copy_from(salt.first<kNonceSize>()); }
diff --git a/chrome/browser/devtools/devtools_ui_bindings.cc b/chrome/browser/devtools/devtools_ui_bindings.cc index 0675ec61..5a6fac957 100644 --- a/chrome/browser/devtools/devtools_ui_bindings.cc +++ b/chrome/browser/devtools/devtools_ui_bindings.cc
@@ -784,6 +784,10 @@ return "DevTools"; } +bool DevToolsUIBindings::MayAccessAllCookies() { + return true; +} + namespace { bool IsAnyAidaPoweredFeatureEnabled() { return base::FeatureList::IsEnabled(::features::kDevToolsConsoleInsights) ||
diff --git a/chrome/browser/devtools/devtools_ui_bindings.h b/chrome/browser/devtools/devtools_ui_bindings.h index cc63758..61225d6 100644 --- a/chrome/browser/devtools/devtools_ui_bindings.h +++ b/chrome/browser/devtools/devtools_ui_bindings.h
@@ -119,6 +119,7 @@ ~DevToolsUIBindings() override; std::string GetTypeForMetrics() override; + bool MayAccessAllCookies() override; content::WebContents* web_contents() { return web_contents_; } Profile* profile() { return profile_; }
diff --git a/chrome/browser/devtools/views/devtools_floaty.cc b/chrome/browser/devtools/views/devtools_floaty.cc index ee954c3..36145e7 100644 --- a/chrome/browser/devtools/views/devtools_floaty.cc +++ b/chrome/browser/devtools/views/devtools_floaty.cc
@@ -218,6 +218,8 @@ agent_host_ = nullptr; } + bool MayAccessAllCookies() override { return true; } + // views::WidgetObserver: void OnWidgetDestroying(views::Widget* widget) override { if (agent_host_ && backend_node_id_) { @@ -434,6 +436,8 @@ delete this; } + bool MayAccessAllCookies() override { return true; } + private: raw_ptr<content::BrowserContext> browser_context_; int render_process_id_;
diff --git a/chrome/browser/download/download_danger_prompt.h b/chrome/browser/download/download_danger_prompt.h index 70128bc..ed5a5a9 100644 --- a/chrome/browser/download/download_danger_prompt.h +++ b/chrome/browser/download/download_danger_prompt.h
@@ -7,10 +7,6 @@ #include "base/functional/callback_forward.h" -namespace content { -class WebContents; -} - namespace download { class DownloadItem; } @@ -34,23 +30,6 @@ }; typedef base::OnceCallback<void(Action)> OnDone; - // Return a new self-deleting DownloadDangerPrompt. The returned - // DownloadDangerPrompt* is only used for testing. The caller does not own the - // object and receives no guarantees about lifetime. The prompt message will - // contain some information about the download and its danger. |done| is a - // callback called when the ACCEPT, CANCEL or DISMISS action is invoked. - // |done| may be called with the CANCEL action even when |item| is either no - // longer dangerous or no longer in progress, or if the tab corresponding to - // |web_contents| is closing. - static DownloadDangerPrompt* Create(download::DownloadItem* item, - content::WebContents* web_contents, - OnDone done); - - // Only to be used by tests. Subclasses must override to manually call the - // respective button click handler. - virtual void InvokeActionForTesting(Action action) = 0; - - protected: // Records warning action event consumed by Safe Browsing reports. static void RecordDownloadWarningEvent(Action action, download::DownloadItem* download);
diff --git a/chrome/browser/download/download_danger_prompt_browsertest.cc b/chrome/browser/download/download_danger_prompt_browsertest.cc deleted file mode 100644 index ae76e1f8..0000000 --- a/chrome/browser/download/download_danger_prompt_browsertest.cc +++ /dev/null
@@ -1,301 +0,0 @@ -// Copyright 2012 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/command_line.h" -#include "base/files/file_path.h" -#include "base/functional/bind.h" -#include "base/memory/raw_ptr.h" -#include "build/build_config.h" -#include "chrome/browser/download/download_danger_prompt.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/safe_browsing/download_protection/download_protection_service.h" -#include "chrome/browser/safe_browsing/test_safe_browsing_service.h" -#include "chrome/browser/ui/browser.h" -#include "chrome/browser/ui/browser_commands.h" -#include "chrome/browser/ui/browser_tabstrip.h" -#include "chrome/browser/ui/hats/mock_trust_safety_sentiment_service.h" -#include "chrome/browser/ui/hats/trust_safety_sentiment_service_factory.h" -#include "chrome/browser/ui/tabs/tab_strip_model.h" -#include "chrome/browser/ui/test/test_browser_dialog.h" -#include "chrome/test/base/in_process_browser_test.h" -#include "chrome/test/base/ui_test_utils.h" -#include "components/download/public/common/mock_download_item.h" -#include "components/prefs/pref_service.h" -#include "components/safe_browsing/core/browser/db/database_manager.h" -#include "components/safe_browsing/core/common/proto/csd.pb.h" -#include "content/public/browser/download_item_utils.h" -#include "content/public/test/browser_test.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "url/gurl.h" - -using ::testing::_; -using ::testing::ByRef; -using ::testing::Eq; -using ::testing::Return; -using ::testing::ReturnRef; -using ::testing::SaveArg; - -namespace safe_browsing { - -namespace { - -const char kTestDownloadUrl[] = "http://evildownload.com"; -const char kDownloadResponseToken[] = "default_token"; - -} // namespace - -class DownloadDangerPromptTest : public InProcessBrowserTest { - public: - DownloadDangerPromptTest() - : prompt_(nullptr), - expected_action_(DownloadDangerPrompt::CANCEL), - did_receive_callback_(false), - test_safe_browsing_factory_( - std::make_unique<TestSafeBrowsingServiceFactory>()) {} - - DownloadDangerPromptTest(const DownloadDangerPromptTest&) = delete; - DownloadDangerPromptTest& operator=(const DownloadDangerPromptTest&) = delete; - - ~DownloadDangerPromptTest() override = default; - - void SetUp() override { - SafeBrowsingService::RegisterFactory(test_safe_browsing_factory_.get()); - InProcessBrowserTest::SetUp(); - } - - void TearDown() override { - SafeBrowsingService::RegisterFactory(nullptr); - InProcessBrowserTest::TearDown(); - } - - // Opens a new tab and waits for navigations to finish. If there are pending - // navigations, the constrained prompt might be dismissed when the navigation - // completes. - void OpenNewTab(Browser* browser_to_use) { - ui_test_utils::NavigateToURLWithDisposition( - browser_to_use, GURL("about:blank"), - WindowOpenDisposition::NEW_FOREGROUND_TAB, - ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB | - ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP); - } - - // Opens a new window and waits for navigations to finish. If there are - // pending navigations, the constrained prompt might be dismissed when the - // navigation completes. - void OpenNewWindow(Browser* browser_to_use) { - ui_test_utils::NavigateToURLWithDisposition( - browser_to_use, GURL("about:blank"), WindowOpenDisposition::NEW_WINDOW, - ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP); - } - - void SetUpExpectations( - const DownloadDangerPrompt::Action& expected_action, - const download::DownloadDangerType& danger_type, - const ClientDownloadResponse::Verdict& download_verdict, - const std::string& token, - Browser* browser_to_use) { - content::DownloadItemUtils::AttachInfoForTesting( - &download(), browser_to_use->profile(), nullptr); - did_receive_callback_ = false; - expected_action_ = expected_action; - SetUpDownloadItemExpectations(danger_type, token, download_verdict); - SetUpSafeBrowsingReportExpectations( - expected_action == DownloadDangerPrompt::ACCEPT, download_verdict, - token, browser_to_use); - CreatePrompt(browser_to_use); - } - - void VerifyExpectations(bool should_send_report) { - content::RunAllPendingInMessageLoop(); - // At the end of each test, we expect no more activity from the prompt. The - // prompt shouldn't exist anymore either. - EXPECT_TRUE(did_receive_callback_); - EXPECT_FALSE(prompt_); - - if (should_send_report) { - EXPECT_EQ(expected_serialized_report_, - test_safe_browsing_factory_->test_safe_browsing_service() - ->serialized_download_report()); - } else { - EXPECT_TRUE(test_safe_browsing_factory_->test_safe_browsing_service() - ->serialized_download_report() - .empty()); - } - testing::Mock::VerifyAndClearExpectations(&download_); - test_safe_browsing_factory_->test_safe_browsing_service() - ->ClearDownloadReport(); - } - - void SimulatePromptAction(DownloadDangerPrompt::Action action) { - prompt_->InvokeActionForTesting(action); - } - - download::MockDownloadItem& download() { return download_; } - - DownloadDangerPrompt* prompt() { return prompt_; } - - private: - void SetUpDownloadItemExpectations( - const download::DownloadDangerType& danger_type, - const std::string& token, - const ClientDownloadResponse::Verdict& download_verdict) { - EXPECT_CALL(download_, GetFileNameToReportUser()) - .WillRepeatedly(Return(base::FilePath(FILE_PATH_LITERAL("evil.exe")))); - EXPECT_CALL(download_, GetDangerType()).WillRepeatedly(Return(danger_type)); - auto token_obj = - std::make_unique<DownloadProtectionService::DownloadProtectionData>( - token, download_verdict, ClientDownloadResponse::TailoredVerdict()); - download_.SetUserData(DownloadProtectionService::kDownloadProtectionDataKey, - std::move(token_obj)); - } - - void SetUpSafeBrowsingReportExpectations( - bool did_proceed, - const ClientDownloadResponse::Verdict& download_verdict, - const std::string& token, - Browser* browser_to_use) { - ClientSafeBrowsingReportRequest expected_report; - expected_report.set_url(GURL(kTestDownloadUrl).spec()); - expected_report.set_type( - ClientSafeBrowsingReportRequest::DANGEROUS_DOWNLOAD_BY_API); - expected_report.set_download_verdict(download_verdict); - expected_report.set_did_proceed(did_proceed); - if (!token.empty()) - expected_report.set_token(token); - expected_report.SerializeToString(&expected_serialized_report_); - } - - void CreatePrompt(Browser* browser_to_use) { - prompt_ = DownloadDangerPrompt::Create( - &download_, browser_to_use->tab_strip_model()->GetActiveWebContents(), - base::BindOnce(&DownloadDangerPromptTest::PromptCallback, - base::Unretained(this))); - content::RunAllPendingInMessageLoop(); - } - - void PromptCallback(DownloadDangerPrompt::Action action) { - EXPECT_FALSE(did_receive_callback_); - EXPECT_EQ(expected_action_, action); - did_receive_callback_ = true; - prompt_ = nullptr; - } - - download::MockDownloadItem download_; - raw_ptr<DownloadDangerPrompt> prompt_; - DownloadDangerPrompt::Action expected_action_; - bool did_receive_callback_; - std::unique_ptr<TestSafeBrowsingServiceFactory> test_safe_browsing_factory_; - std::string expected_serialized_report_; -}; - -// Disabled for flaky timeouts on Windows. crbug.com/41150887 -#if BUILDFLAG(IS_WIN) -#define MAYBE_TestAll DISABLED_TestAll -#else -#define MAYBE_TestAll TestAll -#endif -IN_PROC_BROWSER_TEST_F(DownloadDangerPromptTest, MAYBE_TestAll) { - GURL download_url(kTestDownloadUrl); - ON_CALL(download(), GetURL()).WillByDefault(ReturnRef(download_url)); - ON_CALL(download(), GetReferrerUrl()) - .WillByDefault(ReturnRef(GURL::EmptyGURL())); - base::FilePath empty_file_path; - ON_CALL(download(), GetTargetFilePath()) - .WillByDefault(ReturnRef(empty_file_path)); - - OpenNewTab(browser()); - - // If file is downloaded through download api, a confirm download dialog - // instead of a recovery dialog is shown. Clicking the Accept button should - // invoke the ACCEPT action, a report will be sent with type - // DANGEROUS_DOWNLOAD_BY_API. - SetUpExpectations(DownloadDangerPrompt::ACCEPT, - download::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL, - ClientDownloadResponse::DANGEROUS, kDownloadResponseToken, - browser()); - EXPECT_CALL(download(), IsDangerous()).WillRepeatedly(Return(true)); - SimulatePromptAction(DownloadDangerPrompt::ACCEPT); - VerifyExpectations(true); - - // If file is downloaded through download api, a confirm download dialog - // instead of a recovery dialog is shown. Clicking the Cancel button should - // invoke the CANCEL action, a report will NOT be sent with type - // DANGEROUS_DOWNLOAD_BY_API. - SetUpExpectations(DownloadDangerPrompt::CANCEL, - download::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT, - ClientDownloadResponse::UNCOMMON, std::string(), browser()); - EXPECT_CALL(download(), IsDangerous()).WillRepeatedly(Return(true)); - SimulatePromptAction(DownloadDangerPrompt::CANCEL); - VerifyExpectations(false); -} - -// Class for testing interactive dialogs. -class DownloadDangerPromptBrowserTest : public DialogBrowserTest { - protected: - DownloadDangerPromptBrowserTest() : download_url_(kTestDownloadUrl) {} - - DownloadDangerPromptBrowserTest(const DownloadDangerPromptBrowserTest&) = - delete; - DownloadDangerPromptBrowserTest& operator=( - const DownloadDangerPromptBrowserTest&) = delete; - - void RunTest(download::DownloadDangerType danger_type) { - danger_type_ = danger_type; - ShowAndVerifyUi(); - } - - private: - void ShowUi(const std::string& name) override { - ON_CALL(download_, GetURL()).WillByDefault(ReturnRef(download_url_)); - ON_CALL(download_, GetReferrerUrl()) - .WillByDefault(ReturnRef(GURL::EmptyGURL())); - ON_CALL(download_, GetTargetFilePath()) - .WillByDefault(ReturnRef(empty_file_path_)); - ON_CALL(download_, IsDangerous()).WillByDefault(Return(true)); - ON_CALL(download_, GetFileNameToReportUser()) - .WillByDefault(Return(base::FilePath(FILE_PATH_LITERAL("evil.exe")))); - - // Set up test-specific parameters - ON_CALL(download_, GetDangerType()).WillByDefault(Return(danger_type_)); - content::DownloadItemUtils::AttachInfoForTesting( - &download_, browser()->profile(), nullptr); - DownloadDangerPrompt::Create( - &download_, browser()->tab_strip_model()->GetActiveWebContents(), - DownloadDangerPrompt::OnDone()); - } - - const GURL download_url_; - const base::FilePath empty_file_path_; - - download::DownloadDangerType danger_type_; - download::MockDownloadItem download_; -}; - -IN_PROC_BROWSER_TEST_F(DownloadDangerPromptBrowserTest, - InvokeUi_DangerousFileFromApi) { - RunTest(download::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE); -} - -IN_PROC_BROWSER_TEST_F(DownloadDangerPromptBrowserTest, - InvokeUi_DangerousUrlFromApi) { - RunTest(download::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL); -} - -IN_PROC_BROWSER_TEST_F(DownloadDangerPromptBrowserTest, - InvokeUi_UncommonContentFromApi) { - RunTest(download::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT); -} - -IN_PROC_BROWSER_TEST_F(DownloadDangerPromptBrowserTest, - InvokeUi_PotentiallyUnwantedFromApi) { - RunTest(download::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED); -} - -IN_PROC_BROWSER_TEST_F(DownloadDangerPromptBrowserTest, - InvokeUi_AccountCompromiseFromApi) { - RunTest(download::DOWNLOAD_DANGER_TYPE_DANGEROUS_ACCOUNT_COMPROMISE); -} - -} // namespace safe_browsing
diff --git a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/two_cell/EducationalTipModuleTwoCellView.java b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/two_cell/EducationalTipModuleTwoCellView.java index 0b04dbe..3ab7ecb 100644 --- a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/two_cell/EducationalTipModuleTwoCellView.java +++ b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/two_cell/EducationalTipModuleTwoCellView.java
@@ -79,6 +79,7 @@ public void setItem1OnClickListener(OnClickListener listener) { mItem1Layout.setOnClickListener(listener); + mItem1Layout.setOnLongClickListener(v -> false); } public void setItem2Title(String title) { @@ -100,11 +101,11 @@ public void setItem2OnClickListener(OnClickListener listener) { mItem2Layout.setOnClickListener(listener); + mItem2Layout.setOnLongClickListener(v -> false); } private void applyCompletedStyle( TextView titleView, TextView descriptionView, View itemLayout, boolean isCompleted) { - itemLayout.setLongClickable(false); if (isCompleted) { int disabledColor = getContext().getColor(R.color.default_text_color_disabled_list); titleView.setTextColor(disabledColor); @@ -132,6 +133,7 @@ & ~android.graphics.Paint.STRIKE_THRU_TEXT_FLAG); itemLayout.setClickable(true); + SetupListModuleUtils.clearAccessibilityStateDescription(itemLayout); } }
diff --git a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/setup_list/SetupListModuleUtils.java b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/setup_list/SetupListModuleUtils.java index f762c79..0b77cae6 100644 --- a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/setup_list/SetupListModuleUtils.java +++ b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/setup_list/SetupListModuleUtils.java
@@ -260,4 +260,15 @@ .getString(R.string.educational_tip_accessibility_item_completed)); } } + + /** + * Clears the accessibility state description for a Setup List task view. + * + * @param view The view to clear the state description on. + */ + public static void clearAccessibilityStateDescription(View view) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + view.setStateDescription(null); + } + } }
diff --git a/chrome/browser/enterprise/connectors/analysis/files_request_handler.cc b/chrome/browser/enterprise/connectors/analysis/files_request_handler.cc index 6686971..52933e8 100644 --- a/chrome/browser/enterprise/connectors/analysis/files_request_handler.cc +++ b/chrome/browser/enterprise/connectors/analysis/files_request_handler.cc
@@ -17,10 +17,11 @@ #include "chrome/browser/enterprise/connectors/common.h" #include "chrome/browser/enterprise/connectors/reporting/reporting_event_router_factory.h" #include "chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.h" -#include "chrome/browser/safe_browsing/cloud_content_scanning/file_opening_job.h" +#include "chrome/browser/safe_browsing/cloud_content_scanning/file_analysis_request.h" #include "components/enterprise/common/proto/connectors.pb.h" #include "components/enterprise/connectors/core/cloud_content_scanning/binary_upload_service.h" #include "components/enterprise/connectors/core/cloud_content_scanning/deep_scanning_utils.h" +#include "components/enterprise/connectors/core/cloud_content_scanning/file_opening_job.h" #include "components/enterprise/connectors/core/reporting_constants.h" #include "components/file_access/scoped_file_access.h" #include "components/file_access/scoped_file_access_delegate.h" @@ -204,8 +205,8 @@ return false; } -safe_browsing::FileAnalysisRequest* FilesRequestHandler::PrepareFileRequest( - size_t index) { +enterprise_connectors::FileAnalysisRequestBase* +FilesRequestHandler::PrepareFileRequest(size_t index) { DCHECK_LT(index, paths_.size()); base::FilePath path = paths_[index]; auto request = std::make_unique<safe_browsing::FileAnalysisRequest>( @@ -216,7 +217,7 @@ weak_ptr_factory_.GetWeakPtr(), index), base::BindOnce(&FilesRequestHandler::FileRequestStartCallback, weak_ptr_factory_.GetWeakPtr(), index)); - safe_browsing::FileAnalysisRequest* request_raw = request.get(); + enterprise_connectors::FileAnalysisRequestBase* request_raw = request.get(); content_analysis_info_->InitializeRequest(request_raw); request_raw->set_analysis_connector( AccessPointToEnterpriseConnector(access_point_));
diff --git a/chrome/browser/enterprise/connectors/analysis/files_request_handler.h b/chrome/browser/enterprise/connectors/analysis/files_request_handler.h index 5a606d9..11cb6725 100644 --- a/chrome/browser/enterprise/connectors/analysis/files_request_handler.h +++ b/chrome/browser/enterprise/connectors/analysis/files_request_handler.h
@@ -12,22 +12,17 @@ #include "base/functional/callback_forward.h" #include "base/memory/weak_ptr.h" #include "chrome/browser/enterprise/connectors/analysis/request_handler_base.h" -#include "chrome/browser/safe_browsing/cloud_content_scanning/file_opening_job.h" #include "components/enterprise/common/proto/connectors.pb.h" #include "components/enterprise/connectors/core/cloud_content_scanning/binary_upload_request.h" #include "components/enterprise/connectors/core/cloud_content_scanning/binary_upload_service.h" #include "components/enterprise/connectors/core/cloud_content_scanning/common.h" +#include "components/enterprise/connectors/core/cloud_content_scanning/file_opening_job.h" #include "components/file_access/scoped_file_access.h" -namespace safe_browsing { - -class FileAnalysisRequest; -class FileOpeningJob; - -} // namespace safe_browsing - namespace enterprise_connectors { +class FileAnalysisRequestBase; + // Handles deep scanning requests for multiple files which are specified by // `paths_`. Files are scanned in parallel and piped to the BinaryUploadService // `upload_service_`. On completion of the scan, `callback_` is called with the @@ -101,7 +96,8 @@ private: // Prepares an upload request for the file at `path`. If the file // cannot be uploaded it will have a failure verdict added to `result_`. - safe_browsing::FileAnalysisRequest* PrepareFileRequest(size_t index); + enterprise_connectors::FileAnalysisRequestBase* PrepareFileRequest( + size_t index); // Called when the file info for `path` has been fetched. Also begins the // upload process.
diff --git a/chrome/browser/extensions/all_urls_apitest.cc b/chrome/browser/extensions/all_urls_apitest.cc index 0df3169..b1c76f0 100644 --- a/chrome/browser/extensions/all_urls_apitest.cc +++ b/chrome/browser/extensions/all_urls_apitest.cc
@@ -2,22 +2,24 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/check_op.h" #include "base/command_line.h" #include "build/build_config.h" #include "chrome/browser/extensions/extension_apitest.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/browser.h" -#include "chrome/browser/ui/search/ntp_test_utils.h" #include "chrome/common/url_constants.h" #include "components/crx_file/id_util.h" #include "content/public/test/browser_test.h" #include "extensions/browser/extension_registry.h" +#include "extensions/buildflags/buildflags.h" #include "extensions/common/extension.h" #include "extensions/common/extensions_client.h" #include "extensions/test/extension_test_message_listener.h" #include "net/test/embedded_test_server/embedded_test_server.h" +static_assert(BUILDFLAG(ENABLE_EXTENSIONS_CORE)); + namespace extensions { namespace { @@ -52,10 +54,11 @@ } void NavigateAndWait(const std::string& url) { + // The new tab URL would require special handling that would introduce + // dependencies we don't support on desktop Android. But we don't use the + // new tab URL in this test suite. + CHECK_NE(url, chrome::kChromeUINewTabURL); std::string expected_url = url; - if (url == chrome::kChromeUINewTabURL) { - expected_url = ntp_test_utils::GetFinalNtpUrl(profile()).spec(); - } ExtensionTestMessageListener listener_a("content script: " + expected_url); ExtensionTestMessageListener listener_b("execute: " + expected_url); @@ -78,8 +81,6 @@ scoped_refptr<const Extension> execute_script_; }; -// TODO(crbug.com/371432155): Port to desktop Android once chrome.tabs is more -// fully supported. IN_PROC_BROWSER_TEST_F(AllUrlsApiTest, AllowlistedExtension) { AllowlistExtensions(); @@ -101,8 +102,6 @@ // Test that an extension NOT allowlisted for scripting can ask for <all_urls> // and run scripts on non-restricted all pages. -// TODO(crbug.com/371432155): Port to desktop Android once chrome.tabs is more -// fully supported. IN_PROC_BROWSER_TEST_F(AllUrlsApiTest, RegularExtensions) { // Now verify we can script a regular http page. ASSERT_TRUE(StartEmbeddedTestServer());
diff --git a/chrome/browser/extensions/api/debugger/debugger_api.cc b/chrome/browser/extensions/api/debugger/debugger_api.cc index a12b88bb..37b394d 100644 --- a/chrome/browser/extensions/api/debugger/debugger_api.cc +++ b/chrome/browser/extensions/api/debugger/debugger_api.cc
@@ -388,6 +388,7 @@ bool MayAttachToRenderFrameHost( content::RenderFrameHost* render_frame_host) override; bool MayAttachToURL(const GURL& url, bool is_webui) override; + bool MayAccessAllCookies() override; bool IsTrusted() override; bool MayReadLocalFiles() override; bool MayWriteLocalFiles() override; @@ -664,6 +665,10 @@ &error); } +bool ExtensionDevToolsClientHost::MayAccessAllCookies() { + return false; +} + bool ExtensionDevToolsClientHost::IsTrusted() { return ExtensionIsTrusted(*extension_); }
diff --git a/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_apitest.cc b/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_apitest.cc index 9d47f92b..c785728 100644 --- a/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_apitest.cc +++ b/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_apitest.cc
@@ -135,26 +135,24 @@ EXPECT_TRUE(result_catcher.GetNextResult()) << result_catcher.message(); } -#if !BUILDFLAG(IS_ANDROID) -// TODO(crbug.com/371432155): Port to desktop Android when chrome.tabs API is -// available. IN_PROC_BROWSER_TEST_F(DeclarativeNetRequestApiTest, OnRulesMatchedDebug) { ASSERT_TRUE(RunExtensionTest("on_rules_matched_debug")) << message_; } +#if !BUILDFLAG(IS_ANDROID) // TODO(https://crbug.com/491516661): This test uses an MV2 extension because it // explicitly exercises capabilities linked to MV2 (webRequestBlocking). This -// can be updated in the future with e.g. a policy-installed extension. +// can be updated in the future with e.g. a policy-installed extension. Also, +// Android does not support MV2 extensions, so until this test is updated to +// MV3, skip it on Android. IN_PROC_BROWSER_TEST_F(DeclarativeNetRequestApiTest, ModifyHeaders) { ASSERT_TRUE(RunExtensionTest("modify_headers")) << message_; } +#endif // !BUILDFLAG(IS_ANDROID) -// TODO(crbug.com/371432155): Port to desktop Android when chrome.tabs API is -// available. IN_PROC_BROWSER_TEST_F(DeclarativeNetRequestApiTest, GetMatchedRules) { ASSERT_TRUE(RunExtensionTest("get_matched_rules")) << message_; } -#endif // !BUILDFLAG(IS_ANDROID) IN_PROC_BROWSER_TEST_F(DeclarativeNetRequestApiTest, IsRegexSupported) { ASSERT_TRUE(RunExtensionTest("is_regex_supported")) << message_; @@ -193,7 +191,6 @@ ASSERT_TRUE(RunExtensionTest("fenced_frames")) << message_; } -#if !BUILDFLAG(IS_ANDROID) class DeclarativeNetRequestApiPrerenderingTest : public DeclarativeNetRequestApiTest { public: @@ -204,13 +201,10 @@ content::test::ScopedPrerenderFeatureList scoped_feature_list_; }; -// TODO(crbug.com/371432155): Port to desktop Android when chrome.tabs API is -// available. IN_PROC_BROWSER_TEST_F(DeclarativeNetRequestApiPrerenderingTest, PrerenderedPageInterception) { ASSERT_TRUE(RunExtensionTest("prerendering")) << message_; } -#endif class DeclarativeNetRequestLazyApiResponseHeadersTest : public DeclarativeNetRequestApiTest {
diff --git a/chrome/browser/extensions/api/downloads/downloads_api.cc b/chrome/browser/extensions/api/downloads/downloads_api.cc index e1add45..bb889b8 100644 --- a/chrome/browser/extensions/api/downloads/downloads_api.cc +++ b/chrome/browser/extensions/api/downloads/downloads_api.cc
@@ -43,6 +43,7 @@ #include "chrome/browser/download/download_prefs.h" #include "chrome/browser/download/download_query.h" #include "chrome/browser/download/download_stats.h" +#include "chrome/browser/download/download_ui_safe_browsing_util.h" #include "chrome/browser/extensions/api/downloads/download_extension_errors.h" #include "chrome/browser/extensions/chrome_extension_function_details.h" #include "chrome/browser/extensions/window_controller.h" @@ -52,11 +53,14 @@ #include "chrome/browser/platform_util.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/extensions/extensions_dialogs.h" +#include "chrome/browser/ui/hats/trust_safety_sentiment_service.h" +#include "chrome/browser/ui/hats/trust_safety_sentiment_service_factory.h" #include "chrome/common/extensions/api/downloads.h" #include "components/download/public/common/download_danger_type.h" #include "components/download/public/common/download_interrupt_reasons.h" #include "components/download/public/common/download_item.h" #include "components/download/public/common/download_url_parameters.h" +#include "components/safe_browsing/core/common/safe_browsing_prefs.h" #include "components/web_modal/web_contents_modal_dialog_manager.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/render_frame_host.h" @@ -88,8 +92,10 @@ #if BUILDFLAG(ENABLE_EXTENSIONS) #include "chrome/browser/download/download_danger_prompt.h" +#include "chrome/browser/download/download_item_warning_data.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_window.h" +#include "components/safe_browsing/core/common/features.h" #endif static_assert(BUILDFLAG(ENABLE_EXTENSIONS_CORE)); @@ -138,9 +144,12 @@ const char kFinalUrlKey[] = "finalUrl"; const char kFinalUrlRegexKey[] = "finalUrlRegex"; -// Whether the dialog should be accepted without showing it on tests. +// Whether the "open" dialog should be accepted without showing it on tests. bool g_accept_open_dialog_for_testing = false; +// Action to trigger for the "danger" dialog without showing it on tests. +std::optional<DownloadDangerPrompt::Action> g_danger_prompt_action_for_testing; + extensions::api::downloads::DangerType ConvertDangerType( download::DownloadDangerType danger) { switch (danger) { @@ -1393,9 +1402,6 @@ DownloadsAcceptDangerFunction::~DownloadsAcceptDangerFunction() = default; -DownloadsAcceptDangerFunction::OnPromptCreatedCallback* - DownloadsAcceptDangerFunction::on_prompt_created_ = nullptr; - ExtensionFunction::ResponseAction DownloadsAcceptDangerFunction::Run() { std::optional<downloads::AcceptDanger::Params> params = downloads::AcceptDanger::Params::Create(args()); @@ -1404,6 +1410,15 @@ return RespondLater(); } +// static +base::AutoReset<std::optional<DownloadDangerPrompt::Action>> +DownloadsAcceptDangerFunction::TriggerDangerPromptActionForTesting( + DownloadDangerPrompt::Action action) { + CHECK_IS_TEST(); + return base::AutoReset<std::optional<DownloadDangerPrompt::Action>>( + &g_danger_prompt_action_for_testing, action); +} + void DownloadsAcceptDangerFunction::PromptOrWait(int download_id, int retries) { DownloadItem* download_item = GetDownload( browser_context(), include_incognito_information(), download_id); @@ -1442,18 +1457,20 @@ return; } RecordApiFunctions(DownloadsFunctionName::kDownloadsFunctionAcceptDanger); + #if BUILDFLAG(ENABLE_EXTENSIONS) - // DownloadDangerPrompt displays a modal dialog using native widgets that the - // user must either accept or cancel. It cannot be scripted. - DownloadDangerPrompt* prompt = DownloadDangerPrompt::Create( + // For testing, callers can use TriggerDangerPromptActionForTesting() to + // pre-determine the dialog's result. This bypasses showing the dialog. + if (g_danger_prompt_action_for_testing.has_value()) { + CHECK_IS_TEST(); + DangerPromptCallback(download_id, *g_danger_prompt_action_for_testing); + return; + } + + ShowDownloadDangerDialog( download_item, web_contents, base::BindOnce(&DownloadsAcceptDangerFunction::DangerPromptCallback, this, download_id)); - // DownloadDangerPrompt deletes itself - if (on_prompt_created_ && !on_prompt_created_->is_null()) { - std::move(*on_prompt_created_).Run(prompt); - on_prompt_created_ = nullptr; - } // Function finishes in DangerPromptCallback(). #else NOTIMPLEMENTED(); @@ -1474,6 +1491,44 @@ Respond(Error(std::move(error))); return; } + + const bool accept = action == DownloadDangerPrompt::ACCEPT; + Profile* profile = Profile::FromBrowserContext(browser_context()); + // If this download is no longer dangerous, is already canceled or + // completed, don't send any report. + if (download_item->IsDangerous() && !download_item->IsDone()) { + // Survey triggered on ACCEPT action, since this is where the user + // confirms their choice to keep a dangerous download, rather than + // triggering a survey after selecting to KEEP in the downloads page UI. + if (safe_browsing::IsSafeBrowsingSurveysEnabled(*profile->GetPrefs()) && + accept) { + TrustSafetySentimentService* trust_safety_sentiment_service = + TrustSafetySentimentServiceFactory::GetForProfile(profile); + if (trust_safety_sentiment_service) { + trust_safety_sentiment_service->InteractedWithDownloadWarningUI( + DownloadItemWarningData::WarningSurface::DOWNLOAD_PROMPT, + DownloadItemWarningData::WarningAction::PROCEED); + } + } + // Log here for "Shown" unconditionally, and for "Proceed" iff the dialog + // was accepted. This assumes the dialog cannot be dismissed once it is + // shown without taking some action on it. + RecordDownloadDangerPromptHistogram("Shown", *download_item); + if (accept) { + RecordDownloadDangerPromptHistogram("Proceed", *download_item); + } + DownloadDangerPrompt::RecordDownloadWarningEvent(action, download_item); +#if BUILDFLAG(SAFE_BROWSING_AVAILABLE) + // Do not send cancel report since it's not a terminal action. + if (accept) { + SendSafeBrowsingDownloadReport( + safe_browsing::ClientSafeBrowsingReportRequest:: + DANGEROUS_DOWNLOAD_BY_API, + accept, download_item); + } +#endif + } + switch (action) { case DownloadDangerPrompt::ACCEPT: download_item->ValidateDangerousDownload();
diff --git a/chrome/browser/extensions/api/downloads/downloads_api.h b/chrome/browser/extensions/api/downloads/downloads_api.h index df476d5..ffede22 100644 --- a/chrome/browser/extensions/api/downloads/downloads_api.h +++ b/chrome/browser/extensions/api/downloads/downloads_api.h
@@ -169,13 +169,6 @@ class DownloadsAcceptDangerFunction : public ExtensionFunction { public: - using OnPromptCreatedCallback = - base::OnceCallback<void(DownloadDangerPrompt*)>; - static void OnPromptCreatedForTesting( - OnPromptCreatedCallback* callback) { - on_prompt_created_ = callback; - } - DECLARE_EXTENSION_FUNCTION("downloads.acceptDanger", DOWNLOADS_ACCEPTDANGER) DownloadsAcceptDangerFunction(); @@ -185,6 +178,13 @@ ResponseAction Run() override; + // Sets the action to take when a danger prompt is shown in tests. The + // returned AutoReset restores the previous value, which is an empty + // optional if it hasn't been set. + [[nodiscard]] static base::AutoReset< + std::optional<DownloadDangerPrompt::Action>> + TriggerDangerPromptActionForTesting(DownloadDangerPrompt::Action action); + protected: ~DownloadsAcceptDangerFunction() override; void DangerPromptCallback(int download_id, @@ -192,8 +192,6 @@ private: void PromptOrWait(int download_id, int retries); - - static OnPromptCreatedCallback* on_prompt_created_; }; class DownloadsShowFunction : public ExtensionFunction {
diff --git a/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc b/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc index 6aa155d..84951f2 100644 --- a/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc +++ b/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc
@@ -105,7 +105,9 @@ #endif #if BUILDFLAG(SAFE_BROWSING_AVAILABLE) +#include "chrome/browser/safe_browsing/test_safe_browsing_service.h" #include "components/safe_browsing/content/common/file_type_policies_test_util.h" +#include "components/safe_browsing/core/common/proto/csd.pb.h" #endif #endif @@ -4633,54 +4635,141 @@ // TODO(benjhayden) Test that the shelf is shown for download() both with and // without a WebContents. -void OnDangerPromptCreated(DownloadDangerPrompt* prompt) { - prompt->InvokeActionForTesting(DownloadDangerPrompt::ACCEPT); -} - #if BUILDFLAG(SAFE_BROWSING_AVAILABLE) +class DownloadsSafeBrowsingTest : public DownloadExtensionTest { + public: + DownloadsSafeBrowsingTest() + : test_safe_browsing_factory_( + std::make_unique<safe_browsing::TestSafeBrowsingServiceFactory>()) { + } + DownloadsSafeBrowsingTest(const DownloadsSafeBrowsingTest&) = delete; + DownloadsSafeBrowsingTest& operator=(const DownloadsSafeBrowsingTest&) = + delete; + ~DownloadsSafeBrowsingTest() override = default; + + void SetUp() override { + safe_browsing::SafeBrowsingService::RegisterFactory( + test_safe_browsing_factory_.get()); + DownloadExtensionTest::SetUp(); + } + + void TearDown() override { + DownloadExtensionTest::TearDown(); + safe_browsing::SafeBrowsingService::RegisterFactory(nullptr); + } + + // Downloads a file that will be marked dangerous. + DownloadItem* DownloadDangerousFile(int* out_result_id) { + std::optional<base::Value> result = RunFunctionAndReturnResult( + base::MakeRefCounted<DownloadsDownloadFunction>(), + "[{\"url\": \"data:application/x-shockwave-flash,\", \"filename\": " + "\"dangerous.swf\"}]"); + if (!result || !result->is_int()) { + return nullptr; + } + *out_result_id = result->GetInt(); + DownloadItem* item = GetCurrentManager()->GetDownload(*out_result_id); + if (!item) { + return nullptr; + } + if (!WaitFor(downloads::OnChanged::kEventName, + base::StringPrintf("[{\"id\": %d, " + " \"danger\": {" + " \"previous\": \"safe\"," + " \"current\": \"file\"}}]", + *out_result_id))) { + return nullptr; + } + EXPECT_TRUE(item->IsDangerous()); + return item; + } + + // Verifies Safe Browsing report. + void VerifySafeBrowsingReport(bool expect_proceed) { + std::string report_str = + test_safe_browsing_factory_->test_safe_browsing_service() + ->serialized_download_report(); + if (expect_proceed) { + EXPECT_FALSE(report_str.empty()); + safe_browsing::ClientSafeBrowsingReportRequest report; + ASSERT_TRUE(report.ParseFromString(report_str)); + EXPECT_EQ(safe_browsing::ClientSafeBrowsingReportRequest:: + DANGEROUS_DOWNLOAD_BY_API, + report.type()); + EXPECT_TRUE(report.did_proceed()); + } else { + EXPECT_TRUE(report_str.empty()); + } + } + + protected: + std::unique_ptr<safe_browsing::TestSafeBrowsingServiceFactory> + test_safe_browsing_factory_; +}; + // TODO(crbug.com/450662444): Enable this test on desktop Android when the -// DownloadDangerPrompt is implemented. -IN_PROC_BROWSER_TEST_F(DownloadExtensionTest, - DownloadExtensionTest_AcceptDanger) { +// download danger dialog is enabled on it. +IN_PROC_BROWSER_TEST_F(DownloadsSafeBrowsingTest, AcceptDanger) { safe_browsing::FileTypePoliciesTestOverlay scoped_dangerous = safe_browsing::ScopedMarkAllFilesDangerousForTesting(); - // Download a file that will be marked dangerous; click the browser action - // button; the browser action popup will call acceptDanger(); when the - // DownloadDangerPrompt is created, pretend that the user clicks the Accept - // button; wait until the download completes. LoadExtension("downloads_split"); - std::optional<base::Value> result = RunFunctionAndReturnResult( - base::MakeRefCounted<DownloadsDownloadFunction>(), - "[{\"url\": \"data:application/x-shockwave-flash,\", \"filename\": " - "\"dangerous.swf\"}]"); - ASSERT_TRUE(result); - ASSERT_TRUE(result->is_int()); - int result_id = result->GetInt(); - DownloadItem* item = GetCurrentManager()->GetDownload(result_id); + + // When dialog is triggered, this will call the callback with Action::ACCEPT + // without showing the dialog. + auto downloads_danger_dialog_reset = + DownloadsAcceptDangerFunction::TriggerDangerPromptActionForTesting( + DownloadDangerPrompt::Action::ACCEPT); + + int result_id; + DownloadItem* item = DownloadDangerousFile(&result_id); ASSERT_TRUE(item); - ASSERT_TRUE(WaitFor(downloads::OnChanged::kEventName, - base::StringPrintf( - "[{\"id\": %d, " - " \"danger\": {" - " \"previous\": \"safe\"," - " \"current\": \"file\"}}]", - result_id))); - ASSERT_TRUE(item->IsDangerous()); - ScopedCancellingItem canceller(item); + std::unique_ptr<content::DownloadTestObserver> observer( new content::DownloadTestObserverTerminal( GetCurrentManager(), 1, content::DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_IGNORE)); - DownloadsAcceptDangerFunction::OnPromptCreatedCallback callback = - base::BindOnce(&OnDangerPromptCreated); - DownloadsAcceptDangerFunction::OnPromptCreatedForTesting( - &callback); + // Trigger the download, which will show the danger dialog whose callback is + // automatically triggered with the accept action. const GURL url = extension()->GetResourceURL("accept_danger.html"); ASSERT_TRUE(NavigateToURL(GetActiveWebContents(), url)); + // Wait until the download completes. observer->WaitForFinished(); + EXPECT_EQ(DownloadItem::COMPLETE, item->GetState()); + + VerifySafeBrowsingReport(/*expect_proceed=*/true); +} + +// TODO(crbug.com/450662444): Enable this test on desktop Android when the +// download danger dialog is enabled on it. +IN_PROC_BROWSER_TEST_F(DownloadsSafeBrowsingTest, CancelDanger) { + safe_browsing::FileTypePoliciesTestOverlay scoped_dangerous = + safe_browsing::ScopedMarkAllFilesDangerousForTesting(); + + LoadExtension("downloads_split"); + + // When dialog is triggered, this will call the callback with Action::CANCEL + // without showing the dialog. + auto downloads_danger_dialog_reset = + DownloadsAcceptDangerFunction::TriggerDangerPromptActionForTesting( + DownloadDangerPrompt::Action::CANCEL); + + int result_id; + DownloadItem* item = DownloadDangerousFile(&result_id); + ASSERT_TRUE(item); + + // Trigger the download, which will show the danger dialog whose callback is + // automatically triggered with the cancel action. + const GURL url = extension()->GetResourceURL("accept_danger.html"); + ASSERT_TRUE(NavigateToURL(GetActiveWebContents(), url)); + + // Wait until the download is removed. + ASSERT_TRUE(WaitFor(downloads::OnErased::kEventName, + base::StringPrintf("[%d]", result_id))); + + VerifySafeBrowsingReport(/*expect_proceed=*/false); } #endif // BUILDFLAG(SAFE_BROWSING_AVAILABLE)
diff --git a/chrome/browser/extensions/api/settings_private/prefs_util.cc b/chrome/browser/extensions/api/settings_private/prefs_util.cc index b44beab..87a9957 100644 --- a/chrome/browser/extensions/api/settings_private/prefs_util.cc +++ b/chrome/browser/extensions/api/settings_private/prefs_util.cc
@@ -1187,6 +1187,8 @@ (*s_allowlist)[::prefs::kFeatureNotificationsEnabled] = settings_api::PrefType::kBoolean; #endif // BUILDFLAG(GOOGLE_CHROME_BRANDING) + (*s_allowlist)[::prefs::kProcessIsolationEnabled] = + settings_api::PrefType::kBoolean; #endif // BUILDFLAG(IS_WIN) // Import data
diff --git a/chrome/browser/extensions/api/terminal/terminal_private_api.cc b/chrome/browser/extensions/api/terminal/terminal_private_api.cc index e18f3ffc..7a9398b8b 100644 --- a/chrome/browser/extensions/api/terminal/terminal_private_api.cc +++ b/chrome/browser/extensions/api/terminal/terminal_private_api.cc
@@ -13,7 +13,6 @@ #include <vector> #include "ash/constants/ash_pref_names.h" -#include "ash/constants/ash_switches.h" #include "ash/webui/settings/public/constants/routes.mojom.h" #include "base/command_line.h" #include "base/containers/fixed_flat_map.h" @@ -53,6 +52,7 @@ #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/browser_tabstrip.h" #include "chrome/browser/ui/settings_window_manager_chromeos.h" +#include "chrome/common/chrome_switches.h" #include "chrome/common/extensions/api/terminal_private.h" #include "chromeos/ash/components/dbus/cicerone/cicerone_client.h" #include "chromeos/ash/experiences/guest_os/virtual_machines/virtual_machines_util.h" @@ -300,11 +300,11 @@ // Passing --crosh-command overrides any JS process name. base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - if (command_line->HasSwitch(ash::switches::kCroshCommand)) { + if (command_line->HasSwitch(switches::kCroshCommand)) { OpenProcess( user_id_hash, base::CommandLine(base::FilePath( - command_line->GetSwitchValueASCII(ash::switches::kCroshCommand)))); + command_line->GetSwitchValueASCII(switches::kCroshCommand)))); } else if (process_name == kCroshName) { // Ensure crosh is allowed before starting terminal.
diff --git a/chrome/browser/extensions/api/user_scripts/user_scripts_apitest.cc b/chrome/browser/extensions/api/user_scripts/user_scripts_apitest.cc index c26ccd6..69620f4b3 100644 --- a/chrome/browser/extensions/api/user_scripts/user_scripts_apitest.cc +++ b/chrome/browser/extensions/api/user_scripts/user_scripts_apitest.cc
@@ -496,9 +496,6 @@ // extensions_features::kUserScriptUserExtensionToggle testing::Values(true)); -#if BUILDFLAG(ENABLE_EXTENSIONS) -// TODO(crbug.com/40200835): PRE_ tests are not supported on Android and all -// these tests require a PRE_ step. class UserScriptsAPITestWithoutAPIAllowed : public UserScriptsAPITest { public: UserScriptsAPITestWithoutAPIAllowed() = default; @@ -526,9 +523,16 @@ // Tests that registered user scripts are properly ignored when loading // stored dynamic scripts if the API is not allowed. -// TODO(crbug.com/40200835): PRE_ tests are not supported on Android. +// TODO(crbug.com/441364550): Flaky on desktop Android. +#if BUILDFLAG(IS_ANDROID) +#define MAYBE_PRE_UserScriptsDisabledOnStartupIfAPINotAllowed \ + DISABLED_PRE_UserScriptsDisabledOnStartupIfAPINotAllowed +#else +#define MAYBE_PRE_UserScriptsDisabledOnStartupIfAPINotAllowed \ + PRE_UserScriptsDisabledOnStartupIfAPINotAllowed +#endif IN_PROC_BROWSER_TEST_P(UserScriptsAPITestWithoutAPIAllowed, - PRE_UserScriptsDisabledOnStartupIfAPINotAllowed) { + MAYBE_PRE_UserScriptsDisabledOnStartupIfAPINotAllowed) { // Load an extension and register user scripts and a dynamic content script. const Extension* extension = LoadExtension(test_data_dir_.AppendASCII("user_scripts/allowed_tests")); @@ -559,8 +563,16 @@ /*allowed=*/false); } +// TODO(crbug.com/441364550): Flaky on desktop Android. +#if BUILDFLAG(IS_ANDROID) +#define MAYBE_UserScriptsDisabledOnStartupIfAPINotAllowed \ + DISABLED_UserScriptsDisabledOnStartupIfAPINotAllowed +#else +#define MAYBE_UserScriptsDisabledOnStartupIfAPINotAllowed \ + UserScriptsDisabledOnStartupIfAPINotAllowed +#endif IN_PROC_BROWSER_TEST_P(UserScriptsAPITestWithoutAPIAllowed, - UserScriptsDisabledOnStartupIfAPINotAllowed) { + MAYBE_UserScriptsDisabledOnStartupIfAPINotAllowed) { // Wait until the extension loads so we can get it's ID. ASSERT_TRUE(background_started_listener_->WaitUntilSatisfied()); @@ -608,9 +620,6 @@ // for an extension in one profile doesn't enable it for the same extension in // another profile. Also write tests to confirm incognito split/span mode // behavior. - -// TODO(crbug.com/40200835): PRE_ tests are not supported on Android and all -// these tests require a PRE_ step. class MigrateUserScriptsAPITest : public ExtensionApiTest { public: MigrateUserScriptsAPITest() { @@ -680,7 +689,6 @@ // Installs an extension without the user script permission prior to the // migration. -// TODO(crbug.com/40200835): PRE_ tests are not supported on Android. IN_PROC_BROWSER_TEST_F(MigrateUserScriptsAPITest, PRE_ExtensionWithoutPermission_Allowed_AfterMigration) { const Extension* extension = LoadExtension(test_data_dir_.AppendASCII( @@ -710,7 +718,6 @@ // Installs two extensions (one enabled and one disabled) and disables dev mode // prior to the migration. -// TODO(crbug.com/40200835): PRE_ tests are not supported on Android. IN_PROC_BROWSER_TEST_F(MigrateUserScriptsAPITest, PRE_DevModeOff_Disallowed_AfterMigration) { const Extension* enabled_extension = LoadExtension(test_data_dir_.AppendASCII( @@ -792,6 +799,5 @@ EXPECT_TRUE(ExtensionPrefEnabled(disabled_extension_id, UserScriptManager::kUserScriptsAllowedPref)); } -#endif // BUILDFLAG(ENABLE_EXTENSIONS) } // namespace extensions
diff --git a/chrome/browser/extensions/chrome_extension_host_delegate.cc b/chrome/browser/extensions/chrome_extension_host_delegate.cc index dff2177..af4d16a6 100644 --- a/chrome/browser/extensions/chrome_extension_host_delegate.cc +++ b/chrome/browser/extensions/chrome_extension_host_delegate.cc
@@ -115,16 +115,18 @@ // NOTE: This effectively reloads the URL, which is wrong. Unfortunately // this is the best we can do until NavigateParams::contents_to_insert is // supported. See browser_navigator_android.cc or http://crbug.com/441594986. - NavigateParams params(browser, nullptr); + auto params = + std::make_unique<NavigateParams>(browser, /*contents_to_insert=*/nullptr); if (disposition == WindowOpenDisposition::NEW_FOREGROUND_TAB || disposition == WindowOpenDisposition::NEW_BACKGROUND_TAB) { - params.contents_to_insert = std::move(web_contents); + params->contents_to_insert = std::move(web_contents); } else { - params.url = std::move(target_url); - params.transition = ui::PAGE_TRANSITION_LINK; + params->url = std::move(target_url); + params->transition = ui::PAGE_TRANSITION_LINK; } #else - NavigateParams params(browser, std::move(web_contents)); + auto params = + std::make_unique<NavigateParams>(browser, std::move(web_contents)); #endif // The extension_app_id parameter ends up as app_name in the Browser // which causes the Browser to return true for is_app(). This affects @@ -132,27 +134,43 @@ // TODO(mpcomplete): This seems wrong. What if the extension content is // hosted in a tab? if (disposition == WindowOpenDisposition::NEW_POPUP) { - params.app_id = extension_id; + params->app_id = extension_id; } - params.disposition = disposition; - params.window_features = window_features; - params.window_action = NavigateParams::WindowAction::kShowWindow; - params.user_gesture = user_gesture; + params->disposition = disposition; + params->window_features = window_features; + params->window_action = NavigateParams::WindowAction::kShowWindow; + params->user_gesture = user_gesture; + + auto raw_params = params.get(); + #if BUILDFLAG(IS_ANDROID) // Android uses asynchronous navigate in case it creates a new window. // Asynchronous is OK because neither CreateTab() nor NavigateBrowser() need // to synchronously return a value. - Navigate(¶ms, base::DoNothing()); + Navigate(raw_params, + base::BindOnce( + [](bool browser_created, + base::WeakPtr<BrowserWindowInterface> original_browser, + NavigateParams* p, + base::WeakPtr<content::NavigationHandle> handle) { + // Close the initial browser if Navigate created a new one. + if (browser_created && original_browser && + original_browser.get() != p->browser) { + original_browser->GetWindow()->Close(); + } + }, + browser_created, browser->GetWeakPtr(), + base::Owned(params.release()))); #else // Other platforms use synchronous navigate. - Navigate(¶ms); -#endif + Navigate(raw_params); // Close the browser if Navigate created a new one. - if (browser_created && browser != params.browser) { + if (browser_created && browser != raw_params->browser) { browser->GetWindow()->Close(); } +#endif } void ChromeExtensionHostDelegate::ProcessMediaAccessRequest(
diff --git a/chrome/browser/extensions/system_display/DEPS b/chrome/browser/extensions/system_display/DEPS index 7ceddf3..d194caa 100644 --- a/chrome/browser/extensions/system_display/DEPS +++ b/chrome/browser/extensions/system_display/DEPS
@@ -1,5 +1,8 @@ specific_include_rules = { - "display_info_provider_chromeos*": [ + "display_info_provider_utils\\.*": [ + "+ash/display", + ], + "display_info_provider_chromeos\\.*": [ "+ash/display", "+ash/shell.h", "+ash/shell_observer.h",
diff --git a/chrome/browser/extensions/system_display/display_info_provider_chromeos.cc b/chrome/browser/extensions/system_display/display_info_provider_chromeos.cc index 34936b2..a67fa86f7 100644 --- a/chrome/browser/extensions/system_display/display_info_provider_chromeos.cc +++ b/chrome/browser/extensions/system_display/display_info_provider_chromeos.cc
@@ -12,10 +12,13 @@ #include "ash/shell.h" #include "base/functional/bind.h" #include "base/task/single_thread_task_runner.h" +#include "base/types/optional_ref.h" #include "chrome/browser/extensions/system_display/display_info_provider.h" #include "chrome/browser/extensions/system_display/display_info_provider_utils.h" #include "extensions/common/api/system_display.h" #include "ui/display/display.h" +#include "ui/display/display_layout.h" +#include "ui/display/manager/touch_device_manager.h" #include "ui/display/screen.h" #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/rect.h" @@ -35,66 +38,63 @@ FROM_HERE, base::BindOnce(std::move(callback), std::move(error))); } -std::optional<std::string> GetStringResult( - crosapi::mojom::DisplayConfigResult result) { +std::optional<std::string> GetStringResult(ash::DisplayConfigResult result) { switch (result) { - case crosapi::mojom::DisplayConfigResult::kSuccess: + case ash::DisplayConfigResult::kSuccess: return std::nullopt; - case crosapi::mojom::DisplayConfigResult::kInvalidOperationError: + case ash::DisplayConfigResult::kInvalidOperationError: return "Invalid operation"; - case crosapi::mojom::DisplayConfigResult::kInvalidDisplayIdError: + case ash::DisplayConfigResult::kInvalidDisplayIdError: return "Invalid display id"; - case crosapi::mojom::DisplayConfigResult::kUnifiedNotEnabledError: + case ash::DisplayConfigResult::kUnifiedNotEnabledError: return "enableUnifiedDesktop must be called before setting is_unified"; - case crosapi::mojom::DisplayConfigResult::kPropertyValueOutOfRangeError: + case ash::DisplayConfigResult::kPropertyValueOutOfRangeError: return "Property value out of range"; - case crosapi::mojom::DisplayConfigResult:: - kNotSupportedOnInternalDisplayError: + case ash::DisplayConfigResult::kNotSupportedOnInternalDisplayError: return "Not supported for internal displays"; - case crosapi::mojom::DisplayConfigResult::kNegativeValueError: + case ash::DisplayConfigResult::kNegativeValueError: return "Negative values not supported"; - case crosapi::mojom::DisplayConfigResult::kSetDisplayModeError: + case ash::DisplayConfigResult::kSetDisplayModeError: return "Setting the display mode failed"; - case crosapi::mojom::DisplayConfigResult::kInvalidDisplayLayoutError: + case ash::DisplayConfigResult::kInvalidDisplayLayoutError: return "Invalid display layout"; - case crosapi::mojom::DisplayConfigResult::kSingleDisplayError: + case ash::DisplayConfigResult::kSingleDisplayError: return "This mode requires multiple displays"; - case crosapi::mojom::DisplayConfigResult::kMirrorModeSourceIdError: + case ash::DisplayConfigResult::kMirrorModeSourceIdError: return "Mirror mode source id invalid"; - case crosapi::mojom::DisplayConfigResult::kMirrorModeDestIdError: + case ash::DisplayConfigResult::kMirrorModeDestIdError: return "Mirror mode destination id invalid"; - case crosapi::mojom::DisplayConfigResult::kCalibrationNotAvailableError: + case ash::DisplayConfigResult::kCalibrationNotAvailableError: return "Calibration not available"; - case crosapi::mojom::DisplayConfigResult::kCalibrationNotStartedError: + case ash::DisplayConfigResult::kCalibrationNotStartedError: return "Calibration not started"; - case crosapi::mojom::DisplayConfigResult::kCalibrationInProgressError: + case ash::DisplayConfigResult::kCalibrationInProgressError: return "Calibration in progress"; - case crosapi::mojom::DisplayConfigResult::kCalibrationInvalidDataError: + case ash::DisplayConfigResult::kCalibrationInvalidDataError: return "Calibration data invalid"; - case crosapi::mojom::DisplayConfigResult::kCalibrationFailedError: + case ash::DisplayConfigResult::kCalibrationFailedError: return "Calibration failed"; } return "Unknown error"; } -void LogErrorResult(crosapi::mojom::DisplayConfigResult result) { +void LogErrorResult(ash::DisplayConfigResult result) { std::optional<std::string> str_result = GetStringResult(result); - if (!str_result) { - return; + if (str_result) { + LOG(ERROR) << *str_result; } - LOG(ERROR) << *str_result; } -system_display::LayoutPosition GetLayoutPositionFromMojo( - crosapi::mojom::DisplayLayoutPosition position) { +system_display::LayoutPosition GetLayoutPositionFromUi( + display::DisplayPlacement::Position position) { switch (position) { - case crosapi::mojom::DisplayLayoutPosition::kTop: + case display::DisplayPlacement::TOP: return system_display::LayoutPosition::kTop; - case crosapi::mojom::DisplayLayoutPosition::kRight: + case display::DisplayPlacement::RIGHT: return system_display::LayoutPosition::kRight; - case crosapi::mojom::DisplayLayoutPosition::kBottom: + case display::DisplayPlacement::BOTTOM: return system_display::LayoutPosition::kBottom; - case crosapi::mojom::DisplayLayoutPosition::kLeft: + case display::DisplayPlacement::LEFT: return system_display::LayoutPosition::kLeft; } NOTREACHED(); @@ -129,11 +129,11 @@ // Process the 'isUnified' property. if (properties.is_unified && cros_display_config_) { - auto layout_info = crosapi::mojom::DisplayLayoutInfo::New(); - layout_info->layout_mode = *properties.is_unified - ? crosapi::mojom::DisplayLayoutMode::kUnified - : crosapi::mojom::DisplayLayoutMode::kNormal; - crosapi::mojom::DisplayConfigResult result = + ash::DisplayLayoutInfo layout_info; + layout_info.layout_mode = *properties.is_unified + ? ash::DisplayLayoutMode::kUnified + : ash::DisplayLayoutMode::kNormal; + ash::DisplayConfigResult result = cros_display_config_->SetDisplayLayoutInfo(std::move(layout_info)); std::move(callback).Run(GetStringResult(result)); // Note: If other properties are set they will be ignored. @@ -166,15 +166,15 @@ } // Global config properties. - auto config_properties = crosapi::mojom::DisplayConfigProperties::New(); - config_properties->set_primary = + ash::DisplayConfigProperties config_properties; + config_properties.set_primary = properties.is_primary ? *properties.is_primary : false; - if (properties.overscan) { - config_properties->overscan = GetInsets(*properties.overscan); + if (properties.overscan.has_value()) { + config_properties.overscan = GetInsets(*properties.overscan); } - if (properties.rotation) { - config_properties->rotation = crosapi::mojom::DisplayRotation::New( - GetMojomDisplayRotationOptions(*properties.rotation)); + if (properties.rotation.has_value()) { + config_properties.rotation = + GetMojomDisplayRotationOptions(*properties.rotation); } if (properties.bounds_origin_x || properties.bounds_origin_y) { gfx::Point bounds_origin; @@ -191,10 +191,12 @@ bounds_origin.set_y(*properties.bounds_origin_y); } LOG(ERROR) << "Bounds origin: " << bounds_origin.ToString(); - config_properties->bounds_origin = std::move(bounds_origin); + config_properties.bounds_origin = std::move(bounds_origin); } - config_properties->display_zoom_factor = - properties.display_zoom_factor ? *properties.display_zoom_factor : 0; + config_properties.display_zoom_factor = + properties.display_zoom_factor.has_value() + ? *properties.display_zoom_factor + : 0; // Display mode. if (properties.display_mode) { @@ -212,11 +214,11 @@ mojo_display_mode->is_native = api_display_mode.is_native; mojo_display_mode->is_interlaced = api_display_mode.is_interlaced && *(api_display_mode.is_interlaced); - config_properties->display_mode = std::move(mojo_display_mode); + config_properties.display_mode = std::move(mojo_display_mode); } if (cros_display_config_) { - crosapi::mojom::DisplayConfigResult result = + ash::DisplayConfigResult result = cros_display_config_->SetDisplayProperties( display_id_str, std::move(config_properties), crosapi::mojom::DisplayConfigSource::kUser); @@ -229,26 +231,26 @@ CHECK(cros_display_config_); // Generate the new list of layouts. - std::vector<crosapi::mojom::DisplayLayoutPtr> display_layouts; + std::vector<display::DisplayPlacement> display_layouts; for (const system_display::DisplayLayout& layout : layout_list) { - auto display_layout = crosapi::mojom::DisplayLayout::New(); - display_layout->id = layout.id; - display_layout->parent_id = layout.parent_id; - display_layout->position = GetDisplayLayoutPosition(layout.position); - display_layout->offset = layout.offset; + display::DisplayPlacement display_layout; + display_layout.display_id = GetDisplayId(layout.id); + display_layout.parent_display_id = GetDisplayId(layout.parent_id); + display_layout.position = GetDisplayLayoutPosition(layout.position); + display_layout.offset = layout.offset; display_layouts.emplace_back(std::move(display_layout)); } - auto layout_info = crosapi::mojom::DisplayLayoutInfo::New(); - layout_info->layouts = std::move(display_layouts); + ash::DisplayLayoutInfo layout_info; + layout_info.layouts = std::move(display_layouts); // We need to get the current layout info to provide the layout mode. - crosapi::mojom::DisplayLayoutInfoPtr cur_info = + ash::DisplayLayoutInfo cur_info = cros_display_config_->GetDisplayLayoutInfo(); // Copy the existing layout_mode. - layout_info->layout_mode = cur_info->layout_mode; - crosapi::mojom::DisplayConfigResult result = + layout_info.layout_mode = cur_info.layout_mode; + ash::DisplayConfigResult result = cros_display_config_->SetDisplayLayoutInfo(std::move(layout_info)); if (auto r = GetStringResult(result); r.has_value()) { return base::unexpected(*r); @@ -266,7 +268,7 @@ bool single_unified, base::OnceCallback<void(DisplayUnitInfoList result)> callback) { if (cros_display_config_) { - crosapi::mojom::DisplayLayoutInfoPtr layout = + ash::DisplayLayoutInfo layout = cros_display_config_->GetDisplayLayoutInfo(); std::vector<crosapi::mojom::DisplayUnitInfoPtr> info_list = cros_display_config_->GetDisplayUnitInfoList(single_unified); @@ -274,7 +276,7 @@ for (const crosapi::mojom::DisplayUnitInfoPtr& info : info_list) { system_display::DisplayUnitInfo display = GetDisplayUnitInfoFromMojo(*info); - SetDisplayUnitInfoLayoutProperties(*layout, &display); + SetDisplayUnitInfoLayoutProperties(layout, &display); all_displays.push_back(std::move(display)); } base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( @@ -287,15 +289,14 @@ DisplayInfoProviderChromeOS::GetDisplayLayout() { CHECK(cros_display_config_); DisplayInfoProvider::DisplayLayoutList result; - crosapi::mojom::DisplayLayoutInfoPtr info = - cros_display_config_->GetDisplayLayoutInfo(); - if (info->layouts) { - for (crosapi::mojom::DisplayLayoutPtr& layout : *info->layouts) { + ash::DisplayLayoutInfo info = cros_display_config_->GetDisplayLayoutInfo(); + if (info.layouts.has_value()) { + for (const display::DisplayPlacement& layout : *info.layouts) { api::system_display::DisplayLayout display_layout; - display_layout.id = layout->id; - display_layout.parent_id = layout->parent_id; - display_layout.position = GetLayoutPositionFromMojo(layout->position); - display_layout.offset = layout->offset; + display_layout.id = base::NumberToString(layout.display_id); + display_layout.parent_id = base::NumberToString(layout.parent_display_id); + display_layout.position = GetLayoutPositionFromUi(layout.position); + display_layout.offset = layout.offset; result.emplace_back(std::move(display_layout)); } } @@ -305,9 +306,8 @@ bool DisplayInfoProviderChromeOS::OverscanCalibrationStart( const std::string& id) { if (cros_display_config_) { - crosapi::mojom::DisplayConfigResult result = - cros_display_config_->OverscanCalibration( - id, crosapi::mojom::DisplayConfigOperation::kStart, std::nullopt); + ash::DisplayConfigResult result = cros_display_config_->OverscanCalibration( + id, crosapi::mojom::DisplayConfigOperation::kStart, std::nullopt); LogErrorResult(result); } return true; @@ -317,10 +317,8 @@ const std::string& id, const system_display::Insets& delta) { if (cros_display_config_) { - crosapi::mojom::DisplayConfigResult result = - cros_display_config_->OverscanCalibration( - id, crosapi::mojom::DisplayConfigOperation::kAdjust, - GetInsets(delta)); + ash::DisplayConfigResult result = cros_display_config_->OverscanCalibration( + id, crosapi::mojom::DisplayConfigOperation::kAdjust, GetInsets(delta)); LogErrorResult(result); } return true; @@ -329,9 +327,8 @@ bool DisplayInfoProviderChromeOS::OverscanCalibrationReset( const std::string& id) { if (cros_display_config_) { - crosapi::mojom::DisplayConfigResult result = - cros_display_config_->OverscanCalibration( - id, crosapi::mojom::DisplayConfigOperation::kReset, std::nullopt); + ash::DisplayConfigResult result = cros_display_config_->OverscanCalibration( + id, crosapi::mojom::DisplayConfigOperation::kReset, std::nullopt); LogErrorResult(result); } return true; @@ -340,10 +337,8 @@ bool DisplayInfoProviderChromeOS::OverscanCalibrationComplete( const std::string& id) { if (cros_display_config_) { - crosapi::mojom::DisplayConfigResult result = - cros_display_config_->OverscanCalibration( - id, crosapi::mojom::DisplayConfigOperation::kComplete, - std::nullopt); + ash::DisplayConfigResult result = cros_display_config_->OverscanCalibration( + id, crosapi::mojom::DisplayConfigOperation::kComplete, std::nullopt); LogErrorResult(result); } return true; @@ -353,56 +348,55 @@ const std::string& id, ErrorCallback callback) { CallTouchCalibration(id, crosapi::mojom::DisplayConfigOperation::kShowNative, - nullptr, std::move(callback)); + std::nullopt, std::move(callback)); } bool DisplayInfoProviderChromeOS::StartCustomTouchCalibration( const std::string& id) { touch_calibration_target_id_ = id; CallTouchCalibration(id, crosapi::mojom::DisplayConfigOperation::kStart, - nullptr, ErrorCallback()); + std::nullopt, ErrorCallback()); return true; } bool DisplayInfoProviderChromeOS::CompleteCustomTouchCalibration( const api::system_display::TouchCalibrationPairQuad& pairs, const api::system_display::Bounds& bounds) { - auto calibration = crosapi::mojom::TouchCalibration::New(); - calibration->pairs.emplace_back(GetTouchCalibrationPair(pairs.pair1)); - calibration->pairs.emplace_back(GetTouchCalibrationPair(pairs.pair2)); - calibration->pairs.emplace_back(GetTouchCalibrationPair(pairs.pair3)); - calibration->pairs.emplace_back(GetTouchCalibrationPair(pairs.pair4)); - calibration->bounds = gfx::Size(bounds.width, bounds.height); + display::TouchCalibrationData calibration; + calibration.point_pairs[0] = GetTouchCalibrationPair(pairs.pair1); + calibration.point_pairs[1] = GetTouchCalibrationPair(pairs.pair2); + calibration.point_pairs[2] = GetTouchCalibrationPair(pairs.pair3); + calibration.point_pairs[3] = GetTouchCalibrationPair(pairs.pair4); + calibration.bounds = gfx::Size(bounds.width, bounds.height); CallTouchCalibration(touch_calibration_target_id_, crosapi::mojom::DisplayConfigOperation::kComplete, - std::move(calibration), ErrorCallback()); + calibration, ErrorCallback()); return true; } bool DisplayInfoProviderChromeOS::ClearTouchCalibration(const std::string& id) { CallTouchCalibration(id, crosapi::mojom::DisplayConfigOperation::kReset, - nullptr, ErrorCallback()); + std::nullopt, ErrorCallback()); return true; } void DisplayInfoProviderChromeOS::CallTouchCalibration( const std::string& id, crosapi::mojom::DisplayConfigOperation op, - crosapi::mojom::TouchCalibrationPtr calibration, + base::optional_ref<const display::TouchCalibrationData> calibration, ErrorCallback callback) { if (cros_display_config_) { cros_display_config_->TouchCalibration( - id, op, std::move(calibration), + id, op, calibration, base::BindOnce( - [](ErrorCallback callback, - crosapi::mojom::DisplayConfigResult result) { + [](ErrorCallback callback, ash::DisplayConfigResult result) { if (!callback) { return; } - std::move(callback).Run( - result == crosapi::mojom::DisplayConfigResult::kSuccess - ? std::nullopt - : GetStringResult(result)); + std::move(callback).Run(result == + ash::DisplayConfigResult::kSuccess + ? std::nullopt + : GetStringResult(result)); }, std::move(callback))); } @@ -411,31 +405,32 @@ void DisplayInfoProviderChromeOS::SetMirrorMode( const api::system_display::MirrorModeInfo& info, ErrorCallback callback) { - auto display_layout_info = crosapi::mojom::DisplayLayoutInfo::New(); + ash::DisplayLayoutInfo display_layout_info; if (info.mode == api::system_display::MirrorMode::kOff) { - display_layout_info->layout_mode = - crosapi::mojom::DisplayLayoutMode::kNormal; + display_layout_info.layout_mode = ash::DisplayLayoutMode::kNormal; } else { - display_layout_info->layout_mode = - crosapi::mojom::DisplayLayoutMode::kMirrored; + display_layout_info.layout_mode = ash::DisplayLayoutMode::kMirrored; if (info.mode == api::system_display::MirrorMode::kMixed) { if (!info.mirroring_source_id) { RunResultCallback(std::move(callback), "Mirror mode source id invalid"); return; } - if (!info.mirroring_destination_ids) { + if (!info.mirroring_destination_ids.has_value()) { RunResultCallback(std::move(callback), "Mixed mirror mode requires destination ids"); return; } - display_layout_info->mirror_source_id = *info.mirroring_source_id; - display_layout_info->mirror_destination_ids = - std::make_optional<std::vector<std::string>>( - *info.mirroring_destination_ids); + display_layout_info.mirror_source_id = + GetDisplayId(*info.mirroring_source_id); + display_layout_info.mirror_destination_ids.emplace(); + for (const auto& id_str : *info.mirroring_destination_ids) { + display_layout_info.mirror_destination_ids->push_back( + GetDisplayId(id_str)); + } } } if (cros_display_config_) { - crosapi::mojom::DisplayConfigResult result = + ash::DisplayConfigResult result = cros_display_config_->SetDisplayLayoutInfo( std::move(display_layout_info)); std::move(callback).Run(GetStringResult(result));
diff --git a/chrome/browser/extensions/system_display/display_info_provider_chromeos.h b/chrome/browser/extensions/system_display/display_info_provider_chromeos.h index f07b784..63b0e48d 100644 --- a/chrome/browser/extensions/system_display/display_info_provider_chromeos.h +++ b/chrome/browser/extensions/system_display/display_info_provider_chromeos.h
@@ -11,9 +11,10 @@ #include "ash/shell_observer.h" #include "base/memory/weak_ptr.h" #include "base/scoped_observation.h" +#include "base/types/optional_ref.h" #include "chromeos/crosapi/mojom/cros_display_config.mojom.h" #include "extensions/browser/display_info_provider_base.h" -#include "mojo/public/cpp/bindings/associated_receiver.h" +#include "ui/display/manager/touch_device_manager.h" namespace ash { class Shell; @@ -70,10 +71,11 @@ void OnDisplayConfigChanged() override; private: - void CallTouchCalibration(const std::string& id, - crosapi::mojom::DisplayConfigOperation op, - crosapi::mojom::TouchCalibrationPtr calibration, - ErrorCallback callback); + void CallTouchCalibration( + const std::string& id, + crosapi::mojom::DisplayConfigOperation op, + base::optional_ref<const display::TouchCalibrationData> calibration, + ErrorCallback callback); raw_ptr<ash::CrosDisplayConfig> cros_display_config_; base::ScopedObservation<ash::Shell, ash::ShellObserver> shell_observation_{
diff --git a/chrome/browser/extensions/system_display/display_info_provider_utils.cc b/chrome/browser/extensions/system_display/display_info_provider_utils.cc index 640ad41..dac6064 100644 --- a/chrome/browser/extensions/system_display/display_info_provider_utils.cc +++ b/chrome/browser/extensions/system_display/display_info_provider_utils.cc
@@ -4,10 +4,12 @@ #include "chrome/browser/extensions/system_display/display_info_provider_utils.h" +#include "ash/display/cros_display_config.h" #include "base/notreached.h" #include "base/strings/string_number_conversions.h" #include "chromeos/crosapi/mojom/cros_display_config.mojom.h" #include "ui/display/display.h" +#include "ui/display/display_layout.h" #include "ui/display/screen.h" #include "ui/display/types/display_constants.h" @@ -32,18 +34,18 @@ return display; } -crosapi::mojom::DisplayLayoutPosition GetDisplayLayoutPosition( +display::DisplayPlacement::Position GetDisplayLayoutPosition( system_display::LayoutPosition position) { switch (position) { case system_display::LayoutPosition::kTop: - return crosapi::mojom::DisplayLayoutPosition::kTop; + return display::DisplayPlacement::TOP; case system_display::LayoutPosition::kRight: - return crosapi::mojom::DisplayLayoutPosition::kRight; + return display::DisplayPlacement::RIGHT; case system_display::LayoutPosition::kBottom: - return crosapi::mojom::DisplayLayoutPosition::kBottom; + return display::DisplayPlacement::BOTTOM; case system_display::LayoutPosition::kLeft: case system_display::LayoutPosition::kNone: - return crosapi::mojom::DisplayLayoutPosition::kLeft; + return display::DisplayPlacement::LEFT; } NOTREACHED(); } @@ -209,25 +211,22 @@ return info; } -crosapi::mojom::TouchCalibrationPairPtr GetTouchCalibrationPair( +display::TouchCalibrationData::CalibrationPointPair GetTouchCalibrationPair( const system_display::TouchCalibrationPair& pair) { - auto result = crosapi::mojom::TouchCalibrationPair::New(); - result->display_point = - gfx::Point(pair.display_point.x, pair.display_point.y); - result->touch_point = gfx::Point(pair.touch_point.x, pair.touch_point.y); - return result; + return {gfx::Point(pair.display_point.x, pair.display_point.y), + gfx::Point(pair.touch_point.x, pair.touch_point.y)}; } void SetDisplayUnitInfoLayoutProperties( - const crosapi::mojom::DisplayLayoutInfo& layout, + const ash::DisplayLayoutInfo& layout, system_display::DisplayUnitInfo* display) { - display->is_unified = - layout.layout_mode == crosapi::mojom::DisplayLayoutMode::kUnified; - if (layout.mirror_source_id) { - display->mirroring_source_id = *layout.mirror_source_id; - if (layout.mirror_destination_ids) { - for (const std::string& id : *layout.mirror_destination_ids) { - display->mirroring_destination_ids.push_back(id); + display->is_unified = layout.layout_mode == ash::DisplayLayoutMode::kUnified; + if (layout.mirror_source_id.has_value()) { + display->mirroring_source_id = + base::NumberToString(*layout.mirror_source_id); + if (layout.mirror_destination_ids.has_value()) { + for (int64_t id : *layout.mirror_destination_ids) { + display->mirroring_destination_ids.push_back(base::NumberToString(id)); } } }
diff --git a/chrome/browser/extensions/system_display/display_info_provider_utils.h b/chrome/browser/extensions/system_display/display_info_provider_utils.h index 041fcac..c6aabef 100644 --- a/chrome/browser/extensions/system_display/display_info_provider_utils.h +++ b/chrome/browser/extensions/system_display/display_info_provider_utils.h
@@ -5,8 +5,11 @@ #ifndef CHROME_BROWSER_EXTENSIONS_SYSTEM_DISPLAY_DISPLAY_INFO_PROVIDER_UTILS_H_ #define CHROME_BROWSER_EXTENSIONS_SYSTEM_DISPLAY_DISPLAY_INFO_PROVIDER_UTILS_H_ +#include "ash/display/cros_display_config.h" #include "chromeos/crosapi/mojom/cros_display_config.mojom-forward.h" #include "extensions/common/api/system_display.h" +#include "ui/display/display_layout.h" +#include "ui/display/manager/touch_device_manager.h" #include "ui/gfx/geometry/insets.h" namespace display { @@ -23,8 +26,8 @@ // Return empty display object otherwise. display::Display GetDisplayForId(const std::string& display_id_str); -// Converts display layout `position` from extension api to crosapi type. -crosapi::mojom::DisplayLayoutPosition GetDisplayLayoutPosition( +// Converts display layout `position` from extension api to ui type. +display::DisplayPlacement::Position GetDisplayLayoutPosition( api::system_display::LayoutPosition position); // Converts system display `insets` to gfx type. @@ -49,12 +52,12 @@ api::system_display::DisplayUnitInfo GetDisplayUnitInfoFromMojo( const crosapi::mojom::DisplayUnitInfo& mojo_info); -// Converts system display calibration `pair` to crosapi type. -crosapi::mojom::TouchCalibrationPairPtr GetTouchCalibrationPair( +// Converts from the api type of touch calibration pairs to the ui one. +display::TouchCalibrationData::CalibrationPointPair GetTouchCalibrationPair( const api::system_display::TouchCalibrationPair& pair); void SetDisplayUnitInfoLayoutProperties( - const crosapi::mojom::DisplayLayoutInfo& layout, + const ash::DisplayLayoutInfo& layout, api::system_display::DisplayUnitInfo* display); } // namespace extensions
diff --git a/chrome/browser/finds/BUILD.gn b/chrome/browser/finds/BUILD.gn index aa1c4c3..cba8de47 100644 --- a/chrome/browser/finds/BUILD.gn +++ b/chrome/browser/finds/BUILD.gn
@@ -11,6 +11,8 @@ deps = [ "//base", "//chrome/browser/finds/core", + "//chrome/browser/history", + "//chrome/browser/optimization_guide", "//chrome/browser/profiles:profile", ] }
diff --git a/chrome/browser/finds/core/BUILD.gn b/chrome/browser/finds/core/BUILD.gn index 9f5ac521..fd0db4db 100644 --- a/chrome/browser/finds/core/BUILD.gn +++ b/chrome/browser/finds/core/BUILD.gn
@@ -12,7 +12,28 @@ deps = [ "//base", + "//chrome/browser/optimization_guide", "//chrome/browser/profiles:profile", + "//components/history/core/browser", + "//components/optimization_guide/core", + "//components/optimization_guide/proto:optimization_guide_proto", "//content/public/browser", ] } + +source_set("unit_tests") { + testonly = true + sources = [ "finds_service_unittest.cc" ] + deps = [ + ":core", + "//base", + "//base/test:test_support", + "//chrome/browser/optimization_guide:test_support", + "//chrome/test:test_support", + "//components/history/core/browser", + "//components/optimization_guide/core:test_support", + "//content/test:test_support", + "//testing/gmock", + "//testing/gtest", + ] +}
diff --git a/chrome/browser/finds/core/finds_service.cc b/chrome/browser/finds/core/finds_service.cc index d97c2b90..2eaf937 100644 --- a/chrome/browser/finds/core/finds_service.cc +++ b/chrome/browser/finds/core/finds_service.cc
@@ -4,11 +4,57 @@ #include "chrome/browser/finds/core/finds_service.h" +#include "base/functional/bind.h" +#include "base/strings/strcat.h" +#include "base/strings/string_util.h" +#include "base/strings/stringprintf.h" +#include "base/strings/utf_string_conversions.h" +#include "base/time/time.h" +#include "chrome/browser/optimization_guide/optimization_guide_keyed_service.h" +#include "components/history/core/browser/history_service.h" +#include "components/history/core/browser/history_types.h" +#include "components/optimization_guide/core/optimization_guide_util.h" +#include "components/optimization_guide/proto/features/finds.pb.h" +#include "components/optimization_guide/proto/string_value.pb.h" + namespace finds { -FindsService::FindsService() = default; +namespace { -FindsService::~FindsService() = default; +// The duration of history to look back when gathering URLs for theme +// suggestions. +// TODO(crbug.com/493283477): Align with notif cooldown. +constexpr base::TimeDelta kHistoryLookbackInterval = base::Days(7); + +std::string FindsSuggestionResponseToHumanReadableString( + const optimization_guide::proto::FindsSuggestionResponse& response) { + std::vector<std::string> lines; + for (int i = 0; i < response.suggestions_size(); ++i) { + const auto& theme = response.suggestions(i); + lines.push_back(base::StringPrintf("Theme: %s (Type: %d, Score: %lld)", + theme.theme_title().c_str(), + static_cast<int>(theme.theme_type()), + static_cast<int64_t>(theme.score()))); + for (int j = 0; j < theme.suggestions_size(); ++j) { + const auto& suggestion = theme.suggestions(j); + lines.push_back(base::StringPrintf(" - %s: %s", + suggestion.title().c_str(), + suggestion.target_url().c_str())); + } + } + return base::JoinString(lines, "\n"); +} + +} // namespace + +FindsService::FindsService(OptimizationGuideKeyedService* opt_guide_service, + history::HistoryService* history_service) + : opt_guide_service_(opt_guide_service), + history_service_(history_service) {} + +FindsService::~FindsService() { + history_task_tracker_.TryCancelAll(); +} void FindsService::AddObserver(Observer* observer) { observers_.AddObserver(observer); @@ -18,4 +64,86 @@ observers_.RemoveObserver(observer); } +void FindsService::GetModelResponse(base::OnceCallback<void(Result)> callback) { + if (!history_service_) { + std::move(callback).Run({Result::Status::kHistoryServiceUnavailable, + "Error: HistoryService not available."}); + return; + } + + if (!opt_guide_service_) { + std::move(callback).Run( + {Result::Status::kOptimizationGuideUnavailable, + "Error: OptimizationGuideKeyedService not available."}); + return; + } + + history::QueryOptions options; + options.begin_time = base::Time::Now() - kHistoryLookbackInterval; + + history_service_->QueryHistory( + std::u16string(), options, + base::BindOnce(&FindsService::OnHistoryQueryComplete, + weak_ptr_factory_.GetWeakPtr(), std::move(callback)), + &history_task_tracker_); +} + +void FindsService::OnHistoryQueryComplete( + base::OnceCallback<void(Result)> callback, + history::QueryResults results) { + if (!opt_guide_service_) { + std::move(callback).Run( + {Result::Status::kOptimizationGuideUnavailable, + "Error: OptimizationGuideKeyedService not available."}); + return; + } + + if (results.empty()) { + std::move(callback).Run({Result::Status::kEmptyHistory, + "Error: No history available to suggest themes."}); + return; + } + + optimization_guide::proto::FindsSuggestionRequest request; + for (const auto& result : results) { + auto* entry = request.add_entries(); + entry->set_visit_time_usec( + (result.visit_time() - base::Time::UnixEpoch()).InMicroseconds()); + entry->set_title(base::UTF16ToUTF8(result.title())); + entry->set_url(result.url().spec()); + } + + opt_guide_service_->ExecuteModel( + optimization_guide::ModelBasedCapabilityKey::kFinds, request, {}, + base::BindOnce(&FindsService::OnModelExecutionComplete, + weak_ptr_factory_.GetWeakPtr(), std::move(callback))); +} + +void FindsService::OnModelExecutionComplete( + base::OnceCallback<void(Result)> callback, + optimization_guide::OptimizationGuideModelExecutionResult result, + std::unique_ptr<optimization_guide::ModelQualityLogEntry> log_entry) { + if (!result.response.has_value()) { + std::string error_message = + base::StringPrintf("Model execution failed. Error code: %d", + static_cast<int>(result.response.error().error())); + std::move(callback).Run( + {Result::Status::kModelExecutionFailed, error_message}); + return; + } + + auto response = optimization_guide::ParsedAnyMetadata< + optimization_guide::proto::FindsSuggestionResponse>( + result.response.value()); + if (response) { + std::move(callback).Run( + {Result::Status::kSuccess, + FindsSuggestionResponseToHumanReadableString(*response)}); + } else { + std::move(callback).Run( + {Result::Status::kResponseParsingFailed, + "Model execution successful, but failed to parse response."}); + } +} + } // namespace finds
diff --git a/chrome/browser/finds/core/finds_service.h b/chrome/browser/finds/core/finds_service.h index 18d781b..2c2cf4d 100644 --- a/chrome/browser/finds/core/finds_service.h +++ b/chrome/browser/finds/core/finds_service.h
@@ -5,9 +5,22 @@ #ifndef CHROME_BROWSER_FINDS_CORE_FINDS_SERVICE_H_ #define CHROME_BROWSER_FINDS_CORE_FINDS_SERVICE_H_ +#include "base/functional/callback_forward.h" +#include "base/functional/callback_helpers.h" +#include "base/memory/raw_ptr.h" +#include "base/memory/weak_ptr.h" #include "base/observer_list.h" #include "base/supports_user_data.h" +#include "base/task/cancelable_task_tracker.h" #include "components/keyed_service/core/keyed_service.h" +#include "components/optimization_guide/core/model_execution/remote_model_executor.h" + +namespace history { +class HistoryService; +class QueryResults; +} // namespace history + +class OptimizationGuideKeyedService; namespace finds { @@ -20,7 +33,8 @@ virtual void OnOptInCriteriaFulfilled() = 0; }; - FindsService(); + explicit FindsService(OptimizationGuideKeyedService* opt_guide_service, + history::HistoryService* history_service); ~FindsService() override; FindsService(const FindsService&) = delete; @@ -29,8 +43,35 @@ void AddObserver(Observer* observer); void RemoveObserver(Observer* observer); + struct Result { + enum class Status { + kSuccess, + kHistoryServiceUnavailable, + kOptimizationGuideUnavailable, + kEmptyHistory, + kModelExecutionFailed, + kResponseParsingFailed, + }; + Status status; + std::string message; + }; + + void GetModelResponse(base::OnceCallback<void(Result)> callback); + private: + void OnModelExecutionComplete( + base::OnceCallback<void(Result)> callback, + optimization_guide::OptimizationGuideModelExecutionResult result, + std::unique_ptr<optimization_guide::ModelQualityLogEntry> log_entry); + + void OnHistoryQueryComplete(base::OnceCallback<void(Result)> callback, + history::QueryResults results); + + raw_ptr<OptimizationGuideKeyedService> opt_guide_service_; + raw_ptr<history::HistoryService> history_service_; base::ObserverList<Observer> observers_; + base::CancelableTaskTracker history_task_tracker_; + base::WeakPtrFactory<FindsService> weak_ptr_factory_{this}; }; } // namespace finds
diff --git a/chrome/browser/finds/core/finds_service_unittest.cc b/chrome/browser/finds/core/finds_service_unittest.cc new file mode 100644 index 0000000..9c910b7 --- /dev/null +++ b/chrome/browser/finds/core/finds_service_unittest.cc
@@ -0,0 +1,227 @@ +// Copyright 2026 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/finds/core/finds_service.h" + +#include "base/functional/bind.h" +#include "base/memory/raw_ptr.h" +#include "base/test/bind.h" +#include "chrome/browser/optimization_guide/mock_optimization_guide_keyed_service.h" +#include "components/history/core/browser/history_service.h" +#include "components/optimization_guide/proto/features/finds.pb.h" +#include "content/public/test/browser_task_environment.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using ::testing::_; + +namespace history { +class MockHistoryService : public HistoryService { + public: + MockHistoryService() = default; + ~MockHistoryService() override = default; + + MOCK_METHOD(base::CancelableTaskTracker::TaskId, + QueryHistory, + (const std::u16string& text_query, + const QueryOptions& options, + QueryHistoryCallback callback, + base::CancelableTaskTracker* tracker), + (override)); +}; +} // namespace history + +namespace finds { + +class FindsServiceTest : public testing::Test { + public: + FindsServiceTest() = default; + ~FindsServiceTest() override = default; + + void SetUp() override { + opt_guide_service_ = std::make_unique< + testing::NiceMock<MockOptimizationGuideKeyedService>>(); + history_service_ = + std::make_unique<testing::NiceMock<history::MockHistoryService>>(); + service_ = std::make_unique<FindsService>(opt_guide_service_.get(), + history_service_.get()); + } + + protected: + content::BrowserTaskEnvironment task_environment_; + std::unique_ptr<MockOptimizationGuideKeyedService> opt_guide_service_; + std::unique_ptr<history::MockHistoryService> history_service_; + std::unique_ptr<FindsService> service_; +}; + +TEST_F(FindsServiceTest, HistoryServiceUnavailable) { + auto service = + std::make_unique<FindsService>(opt_guide_service_.get(), nullptr); + + bool callback_called = false; + service->GetModelResponse( + base::BindLambdaForTesting([&](FindsService::Result result) { + EXPECT_EQ(FindsService::Result::Status::kHistoryServiceUnavailable, + result.status); + callback_called = true; + })); + EXPECT_TRUE(callback_called); +} + +TEST_F(FindsServiceTest, OptimizationGuideUnavailable) { + auto service = + std::make_unique<FindsService>(nullptr, history_service_.get()); + + bool callback_called = false; + service->GetModelResponse( + base::BindLambdaForTesting([&](FindsService::Result result) { + EXPECT_EQ(FindsService::Result::Status::kOptimizationGuideUnavailable, + result.status); + callback_called = true; + })); + EXPECT_TRUE(callback_called); +} + +TEST_F(FindsServiceTest, EmptyHistory) { + EXPECT_CALL(*history_service_, QueryHistory(_, _, _, _)) + .WillOnce([](const std::u16string& text_query, + const history::QueryOptions& options, + history::HistoryService::QueryHistoryCallback callback, + base::CancelableTaskTracker* tracker) { + std::move(callback).Run(history::QueryResults()); + return base::CancelableTaskTracker::kBadTaskId; + }); + + bool callback_called = false; + service_->GetModelResponse( + base::BindLambdaForTesting([&](FindsService::Result result) { + EXPECT_EQ(FindsService::Result::Status::kEmptyHistory, result.status); + callback_called = true; + })); + EXPECT_TRUE(callback_called); +} + +TEST_F(FindsServiceTest, ModelExecutionFailed) { + EXPECT_CALL(*history_service_, QueryHistory(_, _, _, _)) + .WillOnce([](const std::u16string& text_query, + const history::QueryOptions& options, + history::HistoryService::QueryHistoryCallback callback, + base::CancelableTaskTracker* tracker) { + history::QueryResults results; + std::vector<history::URLResult> urls; + urls.emplace_back(GURL("https://example.com"), base::Time::Now()); + results.SetURLResults(std::move(urls)); + std::move(callback).Run(std::move(results)); + return base::CancelableTaskTracker::kBadTaskId; + }); + + EXPECT_CALL(*opt_guide_service_, ExecuteModel(_, _, _, _)) + .WillOnce([](optimization_guide::ModelBasedCapabilityKey feature, + const google::protobuf::MessageLite& request_metadata, + const optimization_guide::ModelExecutionOptions& + execution_options, + optimization_guide:: + OptimizationGuideModelExecutionResultCallback callback) { + optimization_guide::OptimizationGuideModelExecutionResult result; + result.response = base::unexpected( + optimization_guide::OptimizationGuideModelExecutionError:: + FromModelExecutionError( + optimization_guide::OptimizationGuideModelExecutionError:: + ModelExecutionError::kGenericFailure)); + std::move(callback).Run(std::move(result), nullptr); + }); + + bool callback_called = false; + service_->GetModelResponse( + base::BindLambdaForTesting([&](FindsService::Result result) { + EXPECT_EQ(FindsService::Result::Status::kModelExecutionFailed, + result.status); + callback_called = true; + })); + EXPECT_TRUE(callback_called); +} + +TEST_F(FindsServiceTest, ParsingFailed) { + EXPECT_CALL(*history_service_, QueryHistory(_, _, _, _)) + .WillOnce([](const std::u16string& text_query, + const history::QueryOptions& options, + history::HistoryService::QueryHistoryCallback callback, + base::CancelableTaskTracker* tracker) { + history::QueryResults results; + std::vector<history::URLResult> urls; + urls.emplace_back(GURL("https://example.com"), base::Time::Now()); + results.SetURLResults(std::move(urls)); + std::move(callback).Run(std::move(results)); + return base::CancelableTaskTracker::kBadTaskId; + }); + + EXPECT_CALL(*opt_guide_service_, ExecuteModel(_, _, _, _)) + .WillOnce( + [](optimization_guide::ModelBasedCapabilityKey feature, + const google::protobuf::MessageLite& request_metadata, + const optimization_guide::ModelExecutionOptions& execution_options, + optimization_guide::OptimizationGuideModelExecutionResultCallback + callback) { + optimization_guide::OptimizationGuideModelExecutionResult result; + optimization_guide::proto::Any any; + any.set_type_url("type.googleapis.com/not.a.match"); + result.response = any; + std::move(callback).Run(std::move(result), nullptr); + }); + + bool callback_called = false; + service_->GetModelResponse( + base::BindLambdaForTesting([&](FindsService::Result result) { + EXPECT_EQ(FindsService::Result::Status::kResponseParsingFailed, + result.status); + callback_called = true; + })); + EXPECT_TRUE(callback_called); +} + +TEST_F(FindsServiceTest, Success) { + EXPECT_CALL(*history_service_, QueryHistory(_, _, _, _)) + .WillOnce([](const std::u16string& text_query, + const history::QueryOptions& options, + history::HistoryService::QueryHistoryCallback callback, + base::CancelableTaskTracker* tracker) { + history::QueryResults results; + std::vector<history::URLResult> urls; + urls.emplace_back(GURL("https://example.com"), base::Time::Now()); + results.SetURLResults(std::move(urls)); + std::move(callback).Run(std::move(results)); + return base::CancelableTaskTracker::kBadTaskId; + }); + + EXPECT_CALL(*opt_guide_service_, ExecuteModel(_, _, _, _)) + .WillOnce( + [](optimization_guide::ModelBasedCapabilityKey feature, + const google::protobuf::MessageLite& request_metadata, + const optimization_guide::ModelExecutionOptions& execution_options, + optimization_guide::OptimizationGuideModelExecutionResultCallback + callback) { + optimization_guide::OptimizationGuideModelExecutionResult result; + optimization_guide::proto::FindsSuggestionResponse response; + auto* suggestion = response.add_suggestions(); + suggestion->set_theme_title("Shopping"); + optimization_guide::proto::Any any; + any.set_type_url( + "type.googleapis.com/" + "optimization_guide.proto.FindsSuggestionResponse"); + response.SerializeToString(any.mutable_value()); + result.response = any; + std::move(callback).Run(std::move(result), nullptr); + }); + + bool callback_called = false; + service_->GetModelResponse( + base::BindLambdaForTesting([&](FindsService::Result result) { + EXPECT_EQ(FindsService::Result::Status::kSuccess, result.status); + EXPECT_EQ("Theme: Shopping (Type: 0, Score: 0)", result.message); + callback_called = true; + })); + EXPECT_TRUE(callback_called); +} + +} // namespace finds
diff --git a/chrome/browser/finds/finds_service_factory.cc b/chrome/browser/finds/finds_service_factory.cc index 4eb16759..b1fb24d 100644 --- a/chrome/browser/finds/finds_service_factory.cc +++ b/chrome/browser/finds/finds_service_factory.cc
@@ -5,8 +5,12 @@ #include "chrome/browser/finds/finds_service_factory.h" #include "chrome/browser/finds/core/finds_service.h" +#include "chrome/browser/history/history_service_factory.h" +#include "chrome/browser/optimization_guide/optimization_guide_keyed_service.h" +#include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_selections.h" +#include "components/keyed_service/core/service_access_type.h" namespace finds { @@ -29,14 +33,23 @@ .WithRegular(ProfileSelection::kOriginalOnly) .WithGuest(ProfileSelection::kOriginalOnly) .WithAshInternals(ProfileSelection::kNone) - .Build()) {} + .Build()) { + DependsOn(OptimizationGuideKeyedServiceFactory::GetInstance()); + DependsOn(HistoryServiceFactory::GetInstance()); +} FindsServiceFactory::~FindsServiceFactory() = default; std::unique_ptr<KeyedService> FindsServiceFactory::BuildServiceInstanceForBrowserContext( content::BrowserContext* context) const { - return std::make_unique<FindsService>(); + Profile* profile = Profile::FromBrowserContext(context); + OptimizationGuideKeyedService* opt_guide_service = + OptimizationGuideKeyedServiceFactory::GetForProfile(profile); + history::HistoryService* history_service = + HistoryServiceFactory::GetForProfile(profile, + ServiceAccessType::EXPLICIT_ACCESS); + return std::make_unique<FindsService>(opt_guide_service, history_service); } } // namespace finds
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index 76e0493..b5d7207 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -3835,11 +3835,6 @@ "expiry_milestone": 150 }, { - "name": "enable-openxr-extended", - "owners": [ "alcooper@chromium.org", "bajones@chromium.org", "xr-dev@chromium.org" ], - "expiry_milestone": 150 - }, - { "name": "enable-palm-suppression", "owners": [ "robsc@chromium.org", "napper@chromium.org", "hcutts@chromium.org", "chromeos-tango@google.com" ], // Flag used to test no-full-palm suppression on screen. @@ -3923,6 +3918,11 @@ "expiry_milestone": 145 }, { + "name": "enable-process-isolation-ui", + "owners": [ "wfh@chromium.org", "chrome-platform-security@google.com" ], + "expiry_milestone": 152 + }, + { "name": "enable-process-per-site-up-to-main-frame-threshold", "owners": [ "dtapuska@chromium.org", "blink-network-stack@google.com" ], "expiry_milestone": 145 @@ -4155,6 +4155,14 @@ "expiry_milestone": 150 }, { + "name": "enable-three-dot-menu-back-button", + "owners": [ + "jtanaristy@google.com", + "lazzzis@google.com" + ], + "expiry_milestone": 150 + }, + { "name": "enable-tls13-early-data", "owners": [ "davidben@chromium.org", "svaldez@chromium.org", "bashi@chromium.org" ], "expiry_milestone": 160 @@ -4582,13 +4590,6 @@ "expiry_milestone": -1 }, { - "name": "extensions-toolbar-zero-state-variation", - "owners": [ - "chrome-web-store-consumer-eng-team@google.com" - ], - "expiry_milestone": 130 - }, - { "name": "external-navigation-debug-logs", "owners": [ "mthiesse@chromium.org", "yfriedman@chromium.org" ], // Used by developers for debugging why Chrome fails to launch their app, by @@ -6878,6 +6879,11 @@ "expiry_milestone": 140 }, { + "name": "ntp-animated-doodles", + "owners": [ "giannich@google.com", "rtatum@google.com" ], + "expiry_milestone": 160 + }, + { "name": "ntp-background-color-slider", "owners": [ "pabouchard@google.com", @@ -6919,6 +6925,11 @@ "expiry_milestone": 160 }, { + "name": "ntp-doodle-murals", + "owners": [ "giannich@google.com", "rtatum@google.com" ], + "expiry_milestone": 160 + }, + { "name": "ntp-drive-module", "owners": [ "mahmadi@chromium.org", "tiborg@chromium.org" ], "expiry_milestone": 125
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index f1db737f..ba8e13c 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -1645,6 +1645,11 @@ "offered to pay using their Pix accounts. Users using their devices in " "portrait mode are always offered to pay using their Pix accounts."; +inline constexpr char kEnableProcessIsolationUiName[] = + "Enable Process Isolation UI"; +inline constexpr char kEnableProcessIsolationUiDescription[] = + "Shows the Enable Process Isolation toggle in chrome://settings/system."; + inline constexpr char kEnableStaticQrCodeForPixName[] = "Enable Static Qr Code For Pix"; inline constexpr char kEnableStaticQrCodeForPixDescription[] = @@ -2212,19 +2217,6 @@ inline constexpr char kExtensionDisableUnsupportedDeveloperDescription[] = "When enabled, disable unpacked extensions if developer mode is off."; -inline constexpr char kExtensionsToolbarZeroStateName[] = - "Extensions Toolbar Zero State"; -inline constexpr char kExtensionsToolbarZeroStateDescription[] = - "When enabled, show an IPH to prompt users with zero extensions installed " - "to interact with the Extensions Toolbar Button. Upon the user clicking " - "the toolbar button, display a submenu that suggests exploring the Chrome " - "Web Store."; -inline constexpr char kExtensionsToolbarZeroStateChoicesDisabled[] = "Disabled"; -inline constexpr char kExtensionsToolbarZeroStateVistWebStore[] = - "Visit Chrome Web Store"; -inline constexpr char kExtensionsToolbarZeroStateExploreExtensionsByCategory[] = - "Explore CWS extensions by category"; - inline constexpr char kExtensionsOnChromeUrlsName[] = "Extensions on chrome:// URLs"; inline constexpr char kExtensionsOnChromeUrlsDescription[] = @@ -5942,6 +5934,11 @@ inline constexpr char kTabStripEmptySpaceContextMenuAndroidDescription[] = "Enables the context menu on the empty space of the tab strip."; +inline constexpr char kThreeDotMenuBackButtonName[] = + "Three Dot Menu Back Button"; +inline constexpr char kThreeDotMenuBackButtonDescription[] = + "Enables the Three Dot Menu Back Button on Android."; + inline constexpr char kToolbarSnapshotRefactorName[] = "Toolbar Snapshot Refactor"; inline constexpr char kToolbarSnapshotRefactorDescription[] = @@ -6022,12 +6019,6 @@ inline constexpr char kXsurfaceMetricsReportingDescription[] = "Allows metrics reporting state to be passed to Xsurface"; -inline constexpr char kOpenXRExtendedFeaturesName[] = - "WebXR OpenXR Runtime Extended Features"; -inline constexpr char kOpenXRExtendedFeaturesDescription[] = - "Enables the use of the OpenXR runtime to create WebXR sessions with a " - "broader feature set (e.g. features not currently supported on Desktop)."; - inline constexpr char kOpenXRName[] = "Enable OpenXR WebXR Runtime"; inline constexpr char kOpenXRDescription[] = "Enables the use of the OpenXR runtime to create WebXR sessions."; @@ -6275,6 +6266,14 @@ inline constexpr char kNtpFeatureOptimizationShortcutsRemovalDescription[] = "Enables auto-removal of stale shortcuts from the NTP."; +inline constexpr char kNtpAnimatedDoodlesName[] = "NTP Animated Doodles"; +inline constexpr char kNtpAnimatedDoodlesDescription[] = + "Enables animated Doodles on the NTP."; + +inline constexpr char kNtpDoodleMuralsName[] = "NTP Doodle Murals"; +inline constexpr char kNtpDoodleMuralsDescription[] = + "Enables Doodle Murals on the NTP."; + inline constexpr char kNtpFooterName[] = "NTP Footer"; inline constexpr char kNtpFooterDescription[] = "Adds footer to New Tab Page that encapsulates customize buttons and "
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc index c12d0982..26a5c033 100644 --- a/chrome/browser/flags/android/chrome_feature_list.cc +++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -449,6 +449,7 @@ &kTabWindowManagerReportIndicesMismatch, &kTestDefaultDisabled, &kTestDefaultEnabled, + &kThreeDotMenuBackButton, &kToolbarPhoneAnimationRefactor, &kToolbarSnapshotRefactor, &kToolbarStaleCaptureBugFix, @@ -796,6 +797,7 @@ BASE_FEATURE(kTabWindowManagerReportIndicesMismatch, base::FEATURE_ENABLED_BY_DEFAULT); BASE_FEATURE(kTestDefaultDisabled, base::FEATURE_DISABLED_BY_DEFAULT); BASE_FEATURE(kTestDefaultEnabled, base::FEATURE_ENABLED_BY_DEFAULT); +BASE_FEATURE(kThreeDotMenuBackButton, base::FEATURE_DISABLED_BY_DEFAULT); BASE_FEATURE(kToolbarPhoneAnimationRefactor, base::FEATURE_DISABLED_BY_DEFAULT); BASE_FEATURE(kToolbarSnapshotRefactor, base::FEATURE_DISABLED_BY_DEFAULT); BASE_FEATURE(kToolbarStaleCaptureBugFix, base::FEATURE_ENABLED_BY_DEFAULT);
diff --git a/chrome/browser/flags/android/chrome_feature_list.h b/chrome/browser/flags/android/chrome_feature_list.h index 1cc31e68..94d8edf 100644 --- a/chrome/browser/flags/android/chrome_feature_list.h +++ b/chrome/browser/flags/android/chrome_feature_list.h
@@ -280,6 +280,7 @@ BASE_DECLARE_FEATURE(kTabWindowManagerReportIndicesMismatch); BASE_DECLARE_FEATURE(kTestDefaultDisabled); BASE_DECLARE_FEATURE(kTestDefaultEnabled); +BASE_DECLARE_FEATURE(kThreeDotMenuBackButton); BASE_DECLARE_FEATURE(kToolbarPhoneAnimationRefactor); BASE_DECLARE_FEATURE(kToolbarSnapshotRefactor); BASE_DECLARE_FEATURE(kToolbarStaleCaptureBugFix);
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java index 67fbceb8..dd0c6e9 100644 --- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java +++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -675,6 +675,7 @@ public static final String TASK_MANAGER_CLANK = "TaskManagerClank"; public static final String TEST_DEFAULT_DISABLED = "TestDefaultDisabled"; public static final String TEST_DEFAULT_ENABLED = "TestDefaultEnabled"; + public static final String THREE_DOT_MENU_BACK_BUTTON = "ThreeDotMenuBackButton"; public static final String TOOLBAR_PHONE_ANIMATION_REFACTOR = "ToolbarPhoneAnimationRefactor"; public static final String TOOLBAR_SCROLL_ABLATION = "AndroidToolbarScrollAblation"; public static final String TOOLBAR_SNAPSHOT_REFACTOR = "ToolbarSnapshotRefactor"; @@ -1101,6 +1102,11 @@ public static final CachedFlag sTestDefaultDisabled = newCachedFlag(TEST_DEFAULT_DISABLED, false); public static final CachedFlag sTestDefaultEnabled = newCachedFlag(TEST_DEFAULT_ENABLED, true); + public static final CachedFlag sThreeDotMenuBackButton = + newCachedFlag( + THREE_DOT_MENU_BACK_BUTTON, + /* defaultValue= */ false, + /* defaultValueInTests= */ false); public static final CachedFlag sToolbarPhoneAnimationRefactor = newCachedFlag( TOOLBAR_PHONE_ANIMATION_REFACTOR, @@ -1304,6 +1310,7 @@ sTabStorageSqlitePrototype, sTabStripDensityChangeAndroid, sTabWindowManagerReportIndicesMismatch, + sThreeDotMenuBackButton, sToolbarPhoneAnimationRefactor, sToolbarSnapshotRefactor, sToolbarStaleCaptureBugFix,
diff --git a/chrome/browser/glic/browser_ui/glic_iph_controller_interactive_uitest.cc b/chrome/browser/glic/browser_ui/glic_iph_controller_interactive_uitest.cc index 22c4cd2..746a2fee 100644 --- a/chrome/browser/glic/browser_ui/glic_iph_controller_interactive_uitest.cc +++ b/chrome/browser/glic/browser_ui/glic_iph_controller_interactive_uitest.cc
@@ -139,8 +139,7 @@ scoped_feature_list_.InitWithFeatures( /*enabled_features=*/{}, /*disabled_features=*/{feature_engagement::kIPHGlicTryItFeature, - features::kGlicTrustFirstOnboarding, - features::kGlicMultiInstance}); + features::kGlicTrustFirstOnboarding}); } ~GlicIphControllerTestClassic() override = default; }; @@ -176,8 +175,7 @@ : GlicIphControllerTestBase({feature_engagement::kIPHGlicTryItFeature}) { // enables FRE warming to test that successful IPH will warm the FRE. scoped_feature_list_.InitWithFeatures( - {}, - {features::kGlicTrustFirstOnboarding, features::kGlicMultiInstance}); + {}, {features::kGlicTrustFirstOnboarding}); } ~GlicIphControllerTestTryIt() override = default; @@ -223,7 +221,6 @@ : GlicIphControllerTestBase({feature_engagement::kIPHGlicTryItFeature}) { scoped_feature_list_.InitWithFeatures( {mojom::features::kGlicMultiTab, features::kGlicMultitabUnderlines, - features::kGlicMultiInstance, feature_engagement::kIPHGlicPromoFeature}, {features::kGlicTrustFirstOnboarding}); } @@ -232,7 +229,6 @@ IN_PROC_BROWSER_TEST_F(GlicIphControllerTestMultiInstance, ShowPromoWithCtaEndsInGlicFre) { - ASSERT_TRUE(GlicEnabling::IsMultiInstanceEnabledByFlags()); RunTestSequence(ObserveState(kFreWebUiState, std::ref(GetFreController())), WaitForGlicIph({feature_engagement::kIPHGlicTryItFeature}), PressDefaultPromoButton(), @@ -242,7 +238,6 @@ IN_PROC_BROWSER_TEST_F(GlicIphControllerTestMultiInstance, ShowPromoWithCtaEndsInGlic) { - ASSERT_TRUE(GlicEnabling::IsMultiInstanceEnabledByFlags()); SetFRECompletion(browser()->profile(), prefs::FreStatus::kCompleted); RunTestSequence(WaitForGlicIph({feature_engagement::kIPHGlicTryItFeature}), PressDefaultPromoButton(),
diff --git a/chrome/browser/glic/browser_ui/glic_nudge_controller.cc b/chrome/browser/glic/browser_ui/glic_nudge_controller.cc index 68431df4..eb660867 100644 --- a/chrome/browser/glic/browser_ui/glic_nudge_controller.cc +++ b/chrome/browser/glic/browser_ui/glic_nudge_controller.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/glic/browser_ui/glic_nudge_controller.h" +#include "chrome/browser/contextual_cueing/contextual_cueing_features.h" #include "chrome/browser/glic/browser_ui/glic_nudge_delegate.h" #include "chrome/browser/glic/glic_pref_names.h" #include "chrome/browser/glic/public/glic_keyed_service.h" @@ -31,6 +32,7 @@ content::WebContents* web_contents, const std::string& nudge_label, std::optional<std::string> prompt_suggestion, + const std::string& anchored_message_text, std::optional<GlicNudgeActivity> activity, GlicNudgeActivityCallback callback) { auto* const tab_interface = @@ -67,12 +69,22 @@ } nudge_activity_callback_ = callback; + prompt_suggestion_ = prompt_suggestion; + PrefService* const pref_service = browser_window_interface_->GetProfile()->GetPrefs(); if (pref_service->GetBoolean(glic::prefs::kGlicPinnedToTabstrip)) { + // TODO: The delegate is currently TabStripActionContainer, which is a view + // and shouldn't contain browser business logic. Refactor to use a proper + // BrowserDelegate instead. if (delegate) { if (nudge_label.empty() && delegate->GetIsShowingGlicNudge()) { delegate->OnHideGlicNudgeUI(); + } else if (base::FeatureList::IsEnabled( + contextual_cueing::kUseAnchoredMessage) && + !anchored_message_text.empty()) { + delegate->OnTriggerAnchoredMessage(nudge_label, anchored_message_text, + prompt_suggestion); } else { delegate->OnTriggerGlicNudgeUI(nudge_label); } @@ -85,8 +97,6 @@ } else { OnNudgeActivity(glic::GlicNudgeActivity::kNudgeShown); } - - prompt_suggestion_ = prompt_suggestion; } void GlicNudgeController::OnNudgeActivity(GlicNudgeActivity activity) {
diff --git a/chrome/browser/glic/browser_ui/glic_nudge_controller.h b/chrome/browser/glic/browser_ui/glic_nudge_controller.h index d30eae1..3ff0835 100644 --- a/chrome/browser/glic/browser_ui/glic_nudge_controller.h +++ b/chrome/browser/glic/browser_ui/glic_nudge_controller.h
@@ -59,6 +59,7 @@ void UpdateNudgeLabel(content::WebContents* web_contents, const std::string& nudge_label, std::optional<std::string> prompt_suggestion, + const std::string& anchored_message_text, std::optional<GlicNudgeActivity> activity, GlicNudgeActivityCallback callback);
diff --git a/chrome/browser/glic/browser_ui/glic_nudge_delegate.h b/chrome/browser/glic/browser_ui/glic_nudge_delegate.h index ca6746c..81c9df4 100644 --- a/chrome/browser/glic/browser_ui/glic_nudge_delegate.h +++ b/chrome/browser/glic/browser_ui/glic_nudge_delegate.h
@@ -5,6 +5,7 @@ #ifndef CHROME_BROWSER_GLIC_BROWSER_UI_GLIC_NUDGE_DELEGATE_H_ #define CHROME_BROWSER_GLIC_BROWSER_UI_GLIC_NUDGE_DELEGATE_H_ +#include <optional> #include <string> namespace glic { @@ -12,9 +13,17 @@ class GlicNudgeDelegate { public: virtual ~GlicNudgeDelegate() = 0; - // Called when the glic nudge UI needs to be triggered. `label' holds the - // nudge label. + // Show the tab strip chip nudge with the given label. virtual void OnTriggerGlicNudgeUI(std::string label) = 0; + // Show an anchored message bubble via the page action framework. + // `label` is the clickable chip text. `anchored_message_text` is the bubble + // description. `prompt_suggestion` is the prompt to pass to ToggleUI when the + // cue is clicked, captured at trigger time to avoid races with controller + // state changes (e.g., navigation, tab switch). + virtual void OnTriggerAnchoredMessage( + std::string label, + std::string anchored_message_text, + std::optional<std::string> prompt_suggestion) = 0; // Called when the glic nudge UI needs to be hidden. virtual void OnHideGlicNudgeUI() = 0; // Called when we want to check if the UI is currently showing.
diff --git a/chrome/browser/glic/glic_metrics.cc b/chrome/browser/glic/glic_metrics.cc index 0e3cca4..1ee9657 100644 --- a/chrome/browser/glic/glic_metrics.cc +++ b/chrome/browser/glic/glic_metrics.cc
@@ -389,13 +389,22 @@ } } -void GlicMetrics::OnTrustFirstOnboardingDismissed() { - if (onboarding_shown_time_.is_null() || - enabling_->HasConsentedForProfile(profile_)) { +void GlicMetrics::OnInstanceOpened() { + if (!onboarding_shown_time_.is_null()) { return; } - base::RecordAction(base::UserMetricsAction("Glic.Fre.Dismissed.Onboarding")); + if (GlicEnabling::IsTrustFirstOnboardingEnabledForProfile(profile_)) { + OnTrustFirstOnboardingShown(); + } +} + +void GlicMetrics::OnInstanceClosed() { + if (onboarding_shown_time_.is_null()) { + return; + } + + base::RecordAction(base::UserMetricsAction("Glic.Fre.Dismissed.Onboarding")); base::UmaHistogramLongTimes("Glic.Fre.TotalTime.Dismissed.Onboarding", base::TimeTicks::Now() - onboarding_shown_time_); onboarding_shown_time_ = base::TimeTicks(); @@ -615,9 +624,7 @@ void GlicMetrics::OnGlicWindowStartedOpening(bool attached, mojom::InvocationSource source) { - if (GlicEnabling::IsTrustFirstOnboardingEnabledForProfile(profile_)) { - OnTrustFirstOnboardingShown(); - } + OnInstanceOpened(); base::UmaHistogramEnumeration( "Glic.Session.Open.BrowserActiveState", @@ -780,11 +787,7 @@ scroll_attempt_count_ = 0; } - if (!onboarding_shown_time_.is_null() && - !enabling_->HasConsentedForProfile(profile_)) { - OnTrustFirstOnboardingDismissed(); - } - onboarding_shown_time_ = base::TimeTicks(); + OnInstanceClosed(); glic_window_size_timer_.Stop(); profile_->GetPrefs()->SetTime(prefs::kGlicWindowLastDismissedTime,
diff --git a/chrome/browser/glic/glic_metrics.h b/chrome/browser/glic/glic_metrics.h index 899d756f..09986c4 100644 --- a/chrome/browser/glic/glic_metrics.h +++ b/chrome/browser/glic/glic_metrics.h
@@ -339,12 +339,16 @@ void OnDetachedFromBrowser(AttachChangeReason reason); // ----Public API called by other glic classes----- - // Called when the "Trust-First Onboarding" flow is shown (side panel). - void OnTrustFirstOnboardingShown(); // Called when the user completes the onboarding flow (consents). void OnTrustFirstOnboardingAccept(); - // Called when the user dismisses the onboarding flow without consenting. - void OnTrustFirstOnboardingDismissed(); + // Called when any instance is opened. This method is used to track whether an + // FRE onboarding is going to be shown. If an FRE onboarding is already shown, + // this method is idempotent. + void OnInstanceOpened(); + // Called when any instance is closed. This method is idempotent. If + // trust-first FRE was shown and not accepted, this metric logs a dismiss + // metric, and then clears the bit tracking FRE open. + void OnInstanceClosed(); // Called when the user clicks Accept in the FRE. void OnFreAccepted(); // Called when the glic window starts to open. @@ -366,7 +370,7 @@ void OnWidgetUserResizeStarted(); // Called when the glic window stops being resized by the user. void OnWidgetUserResizeEnded(); - // Called when the glic window finishes closing. + // Called when the detached glic window finishes closing. void OnGlicWindowClose(Browser* last_active_browser, std::optional<display::Display> display, const gfx::Rect& glic_bounds); @@ -418,6 +422,11 @@ void SetWebClientMode(mojom::WebClientMode mode); private: + // Called when the "Trust-First Onboarding" flow is shown (side panel). This + // relies on the assumption that the logic governing when this method is + // called matches the logic for showing the trust-first FRE. + void OnTrustFirstOnboardingShown(); + // Called when `impression_timer_` fires. void OnImpressionTimerFired();
diff --git a/chrome/browser/glic/glic_metrics_unittest.cc b/chrome/browser/glic/glic_metrics_unittest.cc index 4c37477..e9abd4e 100644 --- a/chrome/browser/glic/glic_metrics_unittest.cc +++ b/chrome/browser/glic/glic_metrics_unittest.cc
@@ -1148,7 +1148,7 @@ 1); // Closing without accept triggers "Dismissed". - metrics()->OnGlicWindowClose(nullptr, std::nullopt, gfx::Rect()); + metrics()->OnInstanceClosed(); EXPECT_EQ( user_action_tester().GetActionCount("Glic.Fre.Dismissed.Onboarding"), 1); histogram_tester().ExpectTotalCount("Glic.Fre.TotalTime.Dismissed.Onboarding",
diff --git a/chrome/browser/glic/glic_selection_observer.cc b/chrome/browser/glic/glic_selection_observer.cc index 35ed3da..2ab265ee 100644 --- a/chrome/browser/glic/glic_selection_observer.cc +++ b/chrome/browser/glic/glic_selection_observer.cc
@@ -122,6 +122,7 @@ if (selected_text.empty()) { if (auto* controller = bwi->GetFeatures().glic_nudge_controller()) { controller->UpdateNudgeLabel(web_contents(), "", std::nullopt, + /*anchored_message_text=*/std::string(), GlicNudgeActivity::kNudgeDismissed, base::DoNothing()); } @@ -182,6 +183,7 @@ IDS_GLIC_SELECTION_TELL_ME_ABOUT, selected_text); controller->UpdateNudgeLabel(web_contents(), base::UTF16ToUTF8(label), std::make_optional(base::UTF16ToUTF8(title)), + /*anchored_message_text=*/std::string(), std::nullopt, base::DoNothing()); } }
diff --git a/chrome/browser/glic/public/glic_passkeys.h b/chrome/browser/glic/public/glic_passkeys.h index 3e950ef..23594d5 100644 --- a/chrome/browser/glic/public/glic_passkeys.h +++ b/chrome/browser/glic/public/glic_passkeys.h
@@ -32,6 +32,8 @@ friend class extensions::PdfViewerPrivateGlicSummarizeFunction; friend class ::PasswordChangeFromCheckupDelegate; friend class GlicInternalsPageHandler; + friend class GlicInstanceCoordinatorBrowserTest; + friend class GlicInstanceCoordinatorTrustFirstOnboardingArm1BrowserTest; }; using InvokeWithAutoSubmitPasskey =
diff --git a/chrome/browser/glic/service/glic_instance_coordinator_browsertest.cc b/chrome/browser/glic/service/glic_instance_coordinator_browsertest.cc index d90bf71..fada707 100644 --- a/chrome/browser/glic/service/glic_instance_coordinator_browsertest.cc +++ b/chrome/browser/glic/service/glic_instance_coordinator_browsertest.cc
@@ -218,6 +218,11 @@ #endif } + protected: + static InvokeWithAutoSubmitPasskey GetPassKey() { + return InvokeWithAutoSubmitPasskeyProvider::GetPassKey(); + } + private: base::test::ScopedFeatureList feature_list_; }; @@ -483,6 +488,40 @@ } } +IN_PROC_BROWSER_TEST_F( + GlicInstanceCoordinatorTrustFirstOnboardingArm1BrowserTest, + AutoSubmitIsDiverted) { + tabs::TabInterface* tab = GetTabListInterface()->GetActiveTab(); + + base::test::TestFuture<void> success_future; + GlicInvokeOptions options(mojom::InvocationSource::kOsButton); + options.on_success = success_future.GetCallback(); + + coordinator().InvokeWithAutoSubmit(GetPassKey(), tab, std::move(options)); + + EXPECT_TRUE(success_future.Wait()); + EXPECT_TRUE(coordinator().GetInstanceForTab(tab)); +} + +IN_PROC_BROWSER_TEST_F( + GlicInstanceCoordinatorTrustFirstOnboardingArm1BrowserTest, + AutoSubmitNotDivertedWhenFreCompleted) { + // Simulate FRE completion. + GetProfile()->GetPrefs()->SetInteger( + prefs::kGlicCompletedFre, static_cast<int>(prefs::FreStatus::kCompleted)); + + tabs::TabInterface* tab = GetTabListInterface()->GetActiveTab(); + + base::test::TestFuture<void> success_future; + GlicInvokeOptions options(mojom::InvocationSource::kOsButton); + options.on_success = success_future.GetCallback(); + + coordinator().InvokeWithAutoSubmit(GetPassKey(), tab, std::move(options)); + + EXPECT_TRUE(success_future.Wait()); + EXPECT_TRUE(coordinator().GetInstanceForTab(tab)); +} + IN_PROC_BROWSER_TEST_F(GlicInstanceCoordinatorBrowserTest, WebClientLinkClickDaisyChaining) { auto* instance = OpenGlicForActiveTab(); @@ -1159,6 +1198,20 @@ EXPECT_TRUE(coordinator().GetInstanceForTab(tab)); } +IN_PROC_BROWSER_TEST_F(GlicInstanceCoordinatorBrowserTest, + InvokeWithAutoSubmitSuccess) { + tabs::TabInterface* tab = GetTabListInterface()->GetActiveTab(); + + base::test::TestFuture<void> success_future; + GlicInvokeOptions options(mojom::InvocationSource::kOsButton); + options.on_success = success_future.GetCallback(); + + coordinator().InvokeWithAutoSubmit(GetPassKey(), tab, std::move(options)); + + EXPECT_TRUE(success_future.Wait()); + EXPECT_TRUE(coordinator().GetInstanceForTab(tab)); +} + #if !BUILDFLAG(IS_ANDROID) #if BUILDFLAG(IS_LINUX) #define MAYBE_WidgetClosedDuringDragDoesNotCrash \
diff --git a/chrome/browser/glic/service/glic_instance_impl.cc b/chrome/browser/glic/service/glic_instance_impl.cc index a8b5fba..33596563 100644 --- a/chrome/browser/glic/service/glic_instance_impl.cc +++ b/chrome/browser/glic/service/glic_instance_impl.cc
@@ -399,9 +399,7 @@ if (!embedder) { return; } - if (GlicEnabling::IsTrustFirstOnboardingEnabledForProfile(profile_)) { - service_->metrics()->OnTrustFirstOnboardingDismissed(); - } + service_->metrics()->OnInstanceClosed(); instance_metrics_.OnClose(); embedder->Close(options); } @@ -411,9 +409,6 @@ glic::mojom::InvocationSource source, std::optional<std::string> prompt_suggestion, bool auto_send) { - if (GlicEnabling::IsTrustFirstOnboardingEnabledForProfile(profile_)) { - service_->metrics()->OnTrustFirstOnboardingShown(); - } instance_metrics_.OnToggle(source, options, IsShowing()); EmbedderKey key = GetEmbedderKey(options); // Close instance on toggle when it has an active embedder. @@ -423,6 +418,9 @@ } return false; } + + service_->metrics()->OnInstanceOpened(); + // We assume that a toggle is user initiated so focus on show. options.focus_on_show = true; options.prompt_suggestion = prompt_suggestion;
diff --git a/chrome/browser/glic/service/glic_invoke_handler.cc b/chrome/browser/glic/service/glic_invoke_handler.cc index 916713dbf..603b3a9b3 100644 --- a/chrome/browser/glic/service/glic_invoke_handler.cc +++ b/chrome/browser/glic/service/glic_invoke_handler.cc
@@ -11,9 +11,10 @@ #include "base/functional/callback_helpers.h" #include "base/task/sequenced_task_runner.h" #include "chrome/browser/glic/host/host.h" +#include "chrome/browser/glic/public/glic_enabling.h" #include "chrome/browser/glic/service/glic_instance_helper.h" #include "chrome/browser/glic/service/glic_instance_impl.h" - +#include "chrome/common/chrome_features.h" namespace glic { constexpr base::TimeDelta kDefaultTimeout = base::Minutes(1); @@ -68,12 +69,25 @@ SendToClient(); } +bool GlicInvokeHandler::RequiresAutoSubmitIncompatibleFre() const { + if (GlicEnabling::HasConsentedForProfile(instance_->profile())) { + return false; + } + return GlicEnabling::IsTrustFirstOnboardingEnabledForProfile( + instance_->profile()) && + features::kGlicTrustFirstOnboardingArmParam.Get() == 1; +} + void GlicInvokeHandler::SendToClient() { if (!instance_->host().IsReady()) { OnError(GlicInvokeError::kTimeout); return; } + if (auto_submit_passkey_ && RequiresAutoSubmitIncompatibleFre()) { + auto_submit_passkey_ = std::nullopt; + } + if (auto_submit_passkey_) { instance_->host().InvokeWithAutoSubmit( *auto_submit_passkey_, CreateMojoOptions(),
diff --git a/chrome/browser/glic/service/glic_invoke_handler.h b/chrome/browser/glic/service/glic_invoke_handler.h index edf2fdf..97af7ff 100644 --- a/chrome/browser/glic/service/glic_invoke_handler.h +++ b/chrome/browser/glic/service/glic_invoke_handler.h
@@ -56,6 +56,8 @@ private: void SendToClient(); mojom::InvokeOptionsPtr CreateMojoOptions(); + bool RequiresAutoSubmitIncompatibleFre() const; + // May delete this. void OnSuccess(); void OnTabClosed(tabs::TabInterface* tab);
diff --git a/chrome/browser/glic/service/metrics/glic_instance_metrics_ui_test.cc b/chrome/browser/glic/service/metrics/glic_instance_metrics_ui_test.cc index e11e742..98499c4 100644 --- a/chrome/browser/glic/service/metrics/glic_instance_metrics_ui_test.cc +++ b/chrome/browser/glic/service/metrics/glic_instance_metrics_ui_test.cc
@@ -125,4 +125,42 @@ 1); } +class GlicFreMetricsTest : public test::InteractiveGlicTest { + public: + GlicFreMetricsTest() { + scoped_feature_list_.InitWithFeatures( + {features::kGlicTrustFirstOnboarding, features::kGlicMultiInstance, + mojom::features::kGlicMultiTab, features::kGlicMultitabUnderlines}, + {}); + } + ~GlicFreMetricsTest() override = default; + + void SetUpOnMainThread() override { + test::InteractiveGlicTest::SetUpOnMainThread(); + browser()->profile()->GetPrefs()->SetInteger( + glic::prefs::kGlicCompletedFre, + static_cast<int>(glic::prefs::FreStatus::kNotStarted)); + } + + protected: + base::UserActionTester user_action_tester_; + + private: + base::test::ScopedFeatureList scoped_feature_list_; +}; + +IN_PROC_BROWSER_TEST_F(GlicFreMetricsTest, FreShownAndDismissed) { + RunTestSequence( + ToggleGlicWindow(GlicWindowMode::kAttached), + WaitForAndInstrumentGlic(GlicInstrumentMode::kHostAndContents), + Wait(START_TIMER_MS + base::Milliseconds(10)), + ToggleGlicWindow(GlicWindowMode::kAttached), + WaitForHide(test::kGlicHostElementId)); + + EXPECT_EQ(user_action_tester_.GetActionCount("Glic.Fre.Shown"), 1); + EXPECT_EQ(user_action_tester_.GetActionCount("Glic.Fre.Accept"), 0); + EXPECT_EQ(user_action_tester_.GetActionCount("Glic.Fre.Dismissed.Onboarding"), + 1); +} + } // namespace glic
diff --git a/chrome/browser/history/java/src/org/chromium/chrome/browser/history/AppFilterMediator.java b/chrome/browser/history/java/src/org/chromium/chrome/browser/history/AppFilterMediator.java index e05c0be..2bf1e8c 100644 --- a/chrome/browser/history/java/src/org/chromium/chrome/browser/history/AppFilterMediator.java +++ b/chrome/browser/history/java/src/org/chromium/chrome/browser/history/AppFilterMediator.java
@@ -5,7 +5,6 @@ package org.chromium.chrome.browser.history; import static org.chromium.build.NullUtil.assertNonNull; -import static org.chromium.build.NullUtil.assumeNonNull; import androidx.annotation.VisibleForTesting; @@ -56,7 +55,7 @@ if (currentApp != null) { assert currentApp.id != null : "App id should be non-null."; mSelectedModel = getModelForAppId(currentApp.id); - assumeNonNull(mSelectedModel); + if (mSelectedModel == null) return; mSelectedModel.set(AppFilterProperties.SELECTED, true); } }
diff --git a/chrome/browser/hub/BUILD.gn b/chrome/browser/hub/BUILD.gn index b922e37e..e7b2330 100644 --- a/chrome/browser/hub/BUILD.gn +++ b/chrome/browser/hub/BUILD.gn
@@ -64,6 +64,7 @@ "//chrome/browser/tab:java", "//chrome/browser/ui/android/actions:java", "//chrome/browser/ui/android/appmenu:java", + "//chrome/browser/ui/android/bottombar:java", "//chrome/browser/ui/android/edge_to_edge:java", "//chrome/browser/ui/android/layouts:java", "//chrome/browser/ui/android/theme:java", @@ -85,6 +86,7 @@ "//chrome/browser/back_press/android:java", "//chrome/browser/profiles/android:java", "//chrome/browser/tab:java", + "//chrome/browser/ui/android/bottombar:java", "//chrome/browser/ui/android/edge_to_edge:java", "//chrome/browser/ui/android/searchactivityutils:java", "//chrome/browser/ui/android/toolbar:java", @@ -122,6 +124,7 @@ "//base:base_junit_test_support", "//chrome/browser/flags:java", "//chrome/browser/ui/android/actions:java", + "//chrome/browser/ui/android/bottombar:java", "//chrome/browser/ui/android/strings:ui_strings_grd", "//chrome/browser/ui/android/theme:java", "//chrome/test/android:chrome_java_unit_test_support",
diff --git a/chrome/browser/hub/internal/BUILD.gn b/chrome/browser/hub/internal/BUILD.gn index 55285da..e129ca79 100644 --- a/chrome/browser/hub/internal/BUILD.gn +++ b/chrome/browser/hub/internal/BUILD.gn
@@ -146,6 +146,7 @@ "//chrome/browser/flags:java", "//chrome/browser/hub:java", "//chrome/browser/ui/android/actions:java", + "//chrome/browser/ui/android/bottombar:java", "//chrome/browser/ui/android/layouts:java", "//chrome/browser/ui/android/night_mode:night_mode_java_test_support", "//chrome/browser/ui/android/strings:ui_strings_grd", @@ -211,6 +212,7 @@ "//chrome/browser/profiles/android:java", "//chrome/browser/tab:java", "//chrome/browser/ui/android/actions:java", + "//chrome/browser/ui/android/bottombar:java", "//chrome/browser/ui/android/edge_to_edge:java", "//chrome/browser/ui/android/layouts:java", "//chrome/browser/ui/android/searchactivityutils:java",
diff --git a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/EmptyHubBottomToolbarDelegate.java b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/EmptyHubBottomToolbarDelegate.java index 554332d..b7a59a3 100644 --- a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/EmptyHubBottomToolbarDelegate.java +++ b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/EmptyHubBottomToolbarDelegate.java
@@ -6,6 +6,7 @@ import android.content.Context; import android.view.LayoutInflater; +import android.view.View; import android.view.ViewGroup; import org.chromium.base.supplier.NonNullObservableSupplier; @@ -61,4 +62,7 @@ public void destroy() { // No resources to clean up in the empty implementation } + + @Override + public void attachBottomBarView(View view) {} }
diff --git a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomBarBottomToolbarDelegateImpl.java b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomBarBottomToolbarDelegateImpl.java index 0315a4b..b710d2c 100644 --- a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomBarBottomToolbarDelegateImpl.java +++ b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomBarBottomToolbarDelegateImpl.java
@@ -6,6 +6,7 @@ import android.content.Context; import android.view.LayoutInflater; +import android.view.View; import android.view.ViewGroup; import org.chromium.base.supplier.NonNullObservableSupplier; @@ -53,11 +54,20 @@ container, /* attachToRoot= */ false); - container.addView(mHubBottomToolbarView); + ViewGroup.LayoutParams params = + new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); + container.addView(mHubBottomToolbarView, params); return mHubBottomToolbarView; } + /** Attaches the provided bottom bar view to the container. */ + @Override + public void attachBottomBarView(View view) { + mHubBottomToolbarView.addView(view); + } + @Override public boolean isBottomToolbarEnabled() { return true;
diff --git a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomBarBottomToolbarDelegateImplUnitTest.java b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomBarBottomToolbarDelegateImplUnitTest.java index ea64a30..544448e 100644 --- a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomBarBottomToolbarDelegateImplUnitTest.java +++ b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomBarBottomToolbarDelegateImplUnitTest.java
@@ -9,6 +9,7 @@ import static org.junit.Assert.assertTrue; import android.app.Activity; +import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; @@ -80,4 +81,21 @@ delegate.destroy(); } + + @Test + public void testAttachBottomBarView() { + HubBottomBarBottomToolbarDelegateImpl delegate = + new HubBottomBarBottomToolbarDelegateImpl(mActivity); + HubBottomToolbarView parentView = + delegate.initializeBottomToolbarView( + mActivity, mContainer, mPaneManager, mHubColorMixer); + + View childView = new View(mActivity); + delegate.attachBottomBarView(childView); + + assertEquals(1, parentView.getChildCount()); + assertEquals(childView, parentView.getChildAt(0)); + + delegate.destroy(); + } }
diff --git a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarCoordinator.java b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarCoordinator.java index e15320fb..7dbc129 100644 --- a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarCoordinator.java +++ b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarCoordinator.java
@@ -7,6 +7,7 @@ import static org.chromium.chrome.browser.hub.HubColorMixer.COLOR_MIXER; import android.content.Context; +import android.view.View; import android.view.ViewGroup; import org.chromium.base.supplier.MonotonicObservableSupplier; @@ -83,4 +84,9 @@ mEdgeToEdgePadAdjuster = null; } } + + /** Attaches the provided bottom bar view to the container. */ + public void attachBottomBarView(View view) { + mDelegate.attachBottomBarView(view); + } }
diff --git a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarCoordinatorUnitTest.java b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarCoordinatorUnitTest.java index 265339e..b824d64 100644 --- a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarCoordinatorUnitTest.java +++ b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarCoordinatorUnitTest.java
@@ -129,4 +129,24 @@ coordinator.destroy(); } + + @Test + public void testAttachBottomBarView() { + HubBottomToolbarDelegate emptyDelegate = spy(new EmptyHubBottomToolbarDelegate()); + HubBottomToolbarCoordinator coordinator = + new HubBottomToolbarCoordinator( + mActivity, + mContainer, + mPaneManager, + mHubColorMixer, + emptyDelegate, + mEdgeToEdgeSupplier); + + View childView = new View(mActivity); + coordinator.attachBottomBarView(childView); + + verify(emptyDelegate).attachBottomBarView(childView); + + coordinator.destroy(); + } }
diff --git a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarDelegate.java b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarDelegate.java index 195fcca..7c53439 100644 --- a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarDelegate.java +++ b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarDelegate.java
@@ -5,6 +5,7 @@ package org.chromium.chrome.browser.hub; import android.content.Context; +import android.view.View; import android.view.ViewGroup; import org.chromium.base.supplier.NonNullObservableSupplier; @@ -58,4 +59,7 @@ /** Cleans up resources and unregisters any observers or callbacks. */ void destroy(); + + /** Attaches the provided bottom bar view to the container. */ + void attachBottomBarView(View view); }
diff --git a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubCoordinator.java b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubCoordinator.java index 77cf0c1b..97b56c5 100644 --- a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubCoordinator.java +++ b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubCoordinator.java
@@ -369,6 +369,13 @@ return mHubPaneHostCoordinator.getSnackbarContainer(); } + /** Attaches the provided bottom bar view to the container. */ + public void attachBottomBarView(View view) { + if (mHubBottomToolbarCoordinator != null) { + mHubBottomToolbarCoordinator.attachBottomBarView(view); + } + } + private @Nullable Pane getFocusedPane() { return mPaneManager.getFocusedPaneSupplier().get(); }
diff --git a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubManagerFactory.java b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubManagerFactory.java index 319d2b8..ce4db72 100644 --- a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubManagerFactory.java +++ b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubManagerFactory.java
@@ -15,6 +15,7 @@ import org.chromium.chrome.browser.profiles.ProfileProvider; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.toolbar.menu_button.MenuButtonCoordinator; +import org.chromium.chrome.browser.ui.bottombar.BottomBarHostManager; import org.chromium.chrome.browser.ui.edge_to_edge.EdgeToEdgeController; import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager; import org.chromium.chrome.browser.ui.searchactivityutils.SearchActivityClient; @@ -50,6 +51,7 @@ BackPressManager backPressManager, MenuOrKeyboardActionController menuOrKeyboardActionController, SnackbarManager snackbarManager, + BottomBarHostManager bottomBarHostManager, NullableObservableSupplier<Tab> tabSupplier, MenuButtonCoordinator menuButtonCoordinator, HubShowPaneHelper hubShowPaneHelper, @@ -64,6 +66,7 @@ backPressManager, menuOrKeyboardActionController, snackbarManager, + bottomBarHostManager, tabSupplier, menuButtonCoordinator, hubShowPaneHelper,
diff --git a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubManagerImpl.java b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubManagerImpl.java index 17ccc07..237b9a4 100644 --- a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubManagerImpl.java +++ b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubManagerImpl.java
@@ -19,6 +19,7 @@ import org.chromium.base.supplier.ObservableSuppliers; import org.chromium.base.supplier.OneshotSupplier; import org.chromium.base.supplier.SettableNonNullObservableSupplier; +import org.chromium.build.annotations.EnsuresNonNull; import org.chromium.build.annotations.MonotonicNonNull; import org.chromium.build.annotations.NullMarked; import org.chromium.build.annotations.Nullable; @@ -26,6 +27,8 @@ import org.chromium.chrome.browser.profiles.ProfileProvider; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.toolbar.menu_button.MenuButtonCoordinator; +import org.chromium.chrome.browser.ui.bottombar.BottomBarConfigUtils; +import org.chromium.chrome.browser.ui.bottombar.BottomBarHostManager; import org.chromium.chrome.browser.ui.edge_to_edge.EdgeToEdgeController; import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager; import org.chromium.chrome.browser.ui.searchactivityutils.SearchActivityClient; @@ -60,6 +63,7 @@ private final MonotonicObservableSupplier<EdgeToEdgeController> mEdgeToEdgeSupplier; private final SearchActivityClient mSearchActivityClient; private final HubColorMixer mHubColorMixer; + private final @Nullable BottomBarHostManager mBottomBarHostManager; // This is effectively NonNull and final once the HubLayout is initialized. private @MonotonicNonNull HubLayoutController mHubLayoutController; @@ -78,6 +82,7 @@ BackPressManager backPressManager, MenuOrKeyboardActionController menuOrKeyboardActionController, SnackbarManager snackbarManager, + @Nullable BottomBarHostManager bottomBarHostManager, NullableObservableSupplier<Tab> tabSupplier, MenuButtonCoordinator menuButtonCoordinator, HubShowPaneHelper hubShowPaneHelper, @@ -91,6 +96,7 @@ mBackPressManager = backPressManager; mMenuOrKeyboardActionController = menuOrKeyboardActionController; mSnackbarManager = snackbarManager; + mBottomBarHostManager = bottomBarHostManager; mTabSupplier = tabSupplier; mMenuButtonCoordinator = menuButtonCoordinator; mHubShowPaneHelper = hubShowPaneHelper; @@ -200,10 +206,19 @@ public void onHubLayoutShow() { mHubVisibilitySupplier.set(true); ensureHubCoordinatorIsInitialized(); + + if (mBottomBarHostManager != null && BottomBarConfigUtils.shouldShowOnGts()) { + mBottomBarHostManager.takeOwnership( + BottomBarHostManager.Host.HUB, mHubCoordinator::attachBottomBarView); + } } @Override public void onHubLayoutDoneHiding() { + if (mBottomBarHostManager != null && BottomBarConfigUtils.shouldShowOnGts()) { + mBottomBarHostManager.resetOwnership(); + } + // TODO(crbug.com/40283238): Consider deferring this destruction till after a timeout. mHubContainerView.removeAllViews(); mHubVisibilitySupplier.set(false); @@ -230,6 +245,7 @@ return mHubColorMixer; } + @EnsuresNonNull("mHubCoordinator") private void ensureHubCoordinatorIsInitialized() { if (mHubCoordinator != null) return;
diff --git a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubManagerImplUnitTest.java b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubManagerImplUnitTest.java index 5691edd..8732459f 100644 --- a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubManagerImplUnitTest.java +++ b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubManagerImplUnitTest.java
@@ -48,6 +48,7 @@ import org.chromium.chrome.browser.toolbar.menu_button.MenuButtonCoordinator; import org.chromium.chrome.browser.ui.actions.DisplayButtonData; import org.chromium.chrome.browser.ui.actions.FullButtonData; +import org.chromium.chrome.browser.ui.bottombar.BottomBarHostManager; import org.chromium.chrome.browser.ui.edge_to_edge.EdgeToEdgeController; import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager; import org.chromium.chrome.browser.ui.searchactivityutils.SearchActivityClient; @@ -86,6 +87,7 @@ @Mock private Profile mProfile; @Mock private Tracker mTracker; @Mock private SearchActivityClient mSearchActivityClient; + @Mock private BottomBarHostManager mBottomBarHostManager; private final MonotonicObservableSupplier<Integer> mPreviousLayoutTypeSupplier = ObservableSuppliers.alwaysNull(); @@ -157,6 +159,48 @@ @Test @SmallTest + public void testHubControllerWithBottomBarHostManager() { + org.chromium.chrome.browser.flags.ChromeFeatureList.sAndroidBottomBarShowBottomBarOnGts + .setForTesting(true); + + PaneListBuilder builder = + new PaneListBuilder(new DefaultPaneOrderController()) + .registerPane( + PaneId.TAB_SWITCHER, + LazyOneshotSupplier.fromValue(mTabSwitcherPane)) + .registerPane( + PaneId.INCOGNITO_TAB_SWITCHER, + LazyOneshotSupplier.fromValue(mIncognitoTabSwitcherPane)); + HubManagerImpl hubManager = + new HubManagerImpl( + mActivity, + mProfileProviderSupplier, + builder, + mBackPressManager, + mMenuOrKeyboardActionController, + mSnackbarManager, + mBottomBarHostManager, + mTabSupplier, + mMenuButtonCoordinator, + mHubShowPaneHelper, + mEdgeToEdgeSupplier, + mSearchActivityClient, + /* xrSpaceModeObservableSupplier= */ null, + /* defaultPaneId= */ PaneId.TAB_SWITCHER); + hubManager.getPaneManager().focusPane(PaneId.TAB_SWITCHER); + + HubController hubController = hubManager.getHubController(); + hubController.setHubLayoutController(mHubLayoutController); + + hubController.onHubLayoutShow(); + verify(mBottomBarHostManager).takeOwnership(eq(BottomBarHostManager.Host.HUB), any()); + + hubController.onHubLayoutDoneHiding(); + verify(mBottomBarHostManager).resetOwnership(); + } + + @Test + @SmallTest public void testCreatesPaneManager() { PaneListBuilder builder = new PaneListBuilder(new DefaultPaneOrderController()) @@ -174,6 +218,7 @@ mBackPressManager, mMenuOrKeyboardActionController, mSnackbarManager, + mBottomBarHostManager, mTabSupplier, mMenuButtonCoordinator, mHubShowPaneHelper, @@ -208,6 +253,7 @@ mBackPressManager, mMenuOrKeyboardActionController, mSnackbarManager, + mBottomBarHostManager, mTabSupplier, mMenuButtonCoordinator, mHubShowPaneHelper, @@ -273,6 +319,7 @@ mBackPressManager, mMenuOrKeyboardActionController, mSnackbarManager, + mBottomBarHostManager, mTabSupplier, mMenuButtonCoordinator, mHubShowPaneHelper, @@ -314,6 +361,7 @@ mBackPressManager, mMenuOrKeyboardActionController, mSnackbarManager, + mBottomBarHostManager, mTabSupplier, mMenuButtonCoordinator, mHubShowPaneHelper, @@ -359,6 +407,7 @@ mBackPressManager, mMenuOrKeyboardActionController, mSnackbarManager, + mBottomBarHostManager, mTabSupplier, mMenuButtonCoordinator, mHubShowPaneHelper, @@ -411,6 +460,7 @@ mBackPressManager, mMenuOrKeyboardActionController, mSnackbarManager, + mBottomBarHostManager, mTabSupplier, mMenuButtonCoordinator, mHubShowPaneHelper,
diff --git a/chrome/browser/idle/BUILD.gn b/chrome/browser/idle/BUILD.gn new file mode 100644 index 0000000..8f67eb5 --- /dev/null +++ b/chrome/browser/idle/BUILD.gn
@@ -0,0 +1,26 @@ +import("//build/config/chromeos/ui_mode.gni") + +source_set("idle") { + visibility = [ + "//chrome/browser/*", + "//chrome/test/*", + ] + + public = [ "idle_detection_permission_context.h" ] + + sources = [ "idle_detection_permission_context.cc" ] + + public_deps = [ + "//base", + "//components/permissions", + "//components/visibility_timer", + ] + + deps = [ + "//chrome/browser/profiles:profile", + "//components/content_settings/browser", + "//content/public/browser", + "//services/network/public/mojom", + "//url", + ] +}
diff --git a/chrome/browser/idle/idle_detection_permission_context.cc b/chrome/browser/idle/idle_detection_permission_context.cc index 9d1abd5..f3809fb 100644 --- a/chrome/browser/idle/idle_detection_permission_context.cc +++ b/chrome/browser/idle/idle_detection_permission_context.cc
@@ -7,11 +7,11 @@ #include "base/functional/bind.h" #include "base/location.h" #include "base/rand_util.h" -#include "chrome/browser/visibility_timer_tab_helper.h" #include "components/content_settings/browser/page_specific_content_settings.h" #include "components/permissions/permission_decision.h" #include "components/permissions/permission_prompt_decision.h" #include "components/permissions/permission_request_id.h" +#include "components/visibility_timer/visibility_timer_tab_helper.h" #include "content/public/browser/browser_context.h" #include "services/network/public/mojom/permissions_policy/permissions_policy_feature.mojom.h" #include "url/gurl.h" @@ -59,8 +59,9 @@ // Random number of seconds in the range [1.0, 2.0). double delay_seconds = 1.0 + 1.0 * base::RandDouble(); - VisibilityTimerTabHelper::CreateForWebContents(web_contents); - VisibilityTimerTabHelper::FromWebContents(web_contents) + visibility_timer::VisibilityTimerTabHelper::CreateForWebContents( + web_contents); + visibility_timer::VisibilityTimerTabHelper::FromWebContents(web_contents) ->PostTaskAfterVisibleDelay( FROM_HERE, base::BindOnce(
diff --git a/chrome/browser/idle/idle_detection_permission_context_unittest.cc b/chrome/browser/idle/idle_detection_permission_context_unittest.cc index e80f964c..aee811b 100644 --- a/chrome/browser/idle/idle_detection_permission_context_unittest.cc +++ b/chrome/browser/idle/idle_detection_permission_context_unittest.cc
@@ -105,10 +105,11 @@ // Time elapsed whilst hidden is not counted. // n.b. This line also clears out any old scheduled timer tasks. This is // important, because otherwise Timer::Reset (triggered by - // VisibilityTimerTabHelper::WasShown) may choose to re-use an existing - // scheduled task, and when it fires Timer::RunScheduledTask will call - // TimeTicks::Now() (which unlike task_environment()->NowTicks(), we can't - // fake), and miscalculate the remaining delay at which to fire the timer. + // visibility_timer::VisibilityTimerTabHelper::WasShown) may choose to re-use + // an existing scheduled task, and when it fires Timer::RunScheduledTask will + // call TimeTicks::Now() (which unlike task_environment()->NowTicks(), we + // can't fake), and miscalculate the remaining delay at which to fire the + // timer. task_environment()->FastForwardBy(base::Days(1)); EXPECT_EQ(0, permission_context.permission_set_count());
diff --git a/chrome/browser/lookalikes/safety_tip_web_contents_observer.cc b/chrome/browser/lookalikes/safety_tip_web_contents_observer.cc index ccb2ffd..694cfef 100644 --- a/chrome/browser/lookalikes/safety_tip_web_contents_observer.cc +++ b/chrome/browser/lookalikes/safety_tip_web_contents_observer.cc
@@ -87,58 +87,6 @@ } } -// Safety Tips does not use starts_active (since flagged sites are so rare to -// begin with), so this function records the same metric as "SafetyTipShown", -// but does so after the flag check, which may impact flag recording. -void RecordPostFlagCheckHistogram(security_state::SafetyTipStatus status) { - UMA_HISTOGRAM_ENUMERATION("Security.SafetyTips.SafetyTipShown_AfterFlag", - status); -} - -// Records a histogram that embeds the safety tip status along with whether the -// navigation was initiated cross- or same-origin. -void RecordSafetyTipStatusWithInitiatorOriginInfo( - const std::optional<url::Origin>& committed_initiator_origin, - const GURL& committed_url, - const GURL& current_url, - security_state::SafetyTipStatus status) { - std::string suffix; - if (committed_url != current_url) { - // So long as we only record this metric following DidFinishNavigation, not - // OnVisibilityChanged, this should rarely happen. It would mean that a new - // navigation committed in this web contents before the safety tip check - // completed. This is possible only when engaged_sites is out of date - // (forcing an async update). In that scenario, there may be a race - // condition between the async safety tip check completing and the next call - // to DidFinishNavigation. - suffix = "UnexpectedUrl"; - } else if (!committed_initiator_origin.has_value()) { - // The initiator origin has no value in cases like omnibox-initiated, or - // outside-of-Chrome-initiated, navigations. - suffix = "Unknown"; - } else if (committed_initiator_origin.value().CanBeDerivedFrom(current_url)) { - // This is assumed to mean that the user has clicked on a same-origin link - // on a lookalike page, resulting in another lookalike navigation. - suffix = "SameOrigin"; - } else if (lookalikes::GetETLDPlusOne( - committed_initiator_origin.value().host()) == - lookalikes::GetETLDPlusOne(current_url.GetHost())) { - // The user has clicked on a link on a page, and it's bumped to another - // page on the same eTLD+1. If that happens and this is a non-none and - // non-ignored status, that implies that the first eTLD+1 load didn't - // trigger the warning, this subsequent page load did, implying that it was - // triggered by a different subdomain. - suffix = "SameRegDomain"; - } else { - // This is assumed to mean that the user has clicked on a link from a - // non-lookalike page, newly triggering the safety tip. - suffix = "CrossOrigin"; - } - - base::UmaHistogramEnumeration( - "Security.SafetyTips.StatusWithInitiator." + suffix, status); -} - } // namespace SafetyTipWebContentsObserver::~SafetyTipWebContentsObserver() = default; @@ -252,16 +200,6 @@ SafetyTipCheckResult result) { UMA_HISTOGRAM_ENUMERATION("Security.SafetyTips.SafetyTipShown", result.safety_tip_status); - base::UmaHistogramEnumeration( - called_from_visibility_check - ? "Security.SafetyTips.ReputationCheckComplete.VisibilityChanged" - : "Security.SafetyTips.ReputationCheckComplete.DidFinishNavigation", - result.safety_tip_status); - if (!called_from_visibility_check) { - RecordSafetyTipStatusWithInitiatorOriginInfo( - last_committed_initiator_origin_, last_committed_url_, result.url, - result.safety_tip_status); - } // Set this field independent of whether the feature to show the UI is // enabled/disabled. Metrics code uses this field and we want to record @@ -288,8 +226,6 @@ if (result.safety_tip_status == security_state::SafetyTipStatus::kLookalikeIgnored) { - UMA_HISTOGRAM_ENUMERATION("Security.SafetyTips.SafetyTipIgnoredPageLoad", - result.safety_tip_status); FinalizeSafetyTipCheckWhenTipNotShown(record_ukm_if_tip_not_shown, result, navigation_source_id); return; @@ -304,8 +240,6 @@ /*is_new_heuristic=*/false)); } - RecordPostFlagCheckHistogram(result.safety_tip_status); - base::OnceCallback<void(SafetyTipInteraction)> close_callback = base::BindOnce(OnSafetyTipClosed, result, navigation_source_id, profile_, result.url, result.safety_tip_status,
diff --git a/chrome/browser/media/webrtc/BUILD.gn b/chrome/browser/media/webrtc/BUILD.gn index 36df39f..842c395 100644 --- a/chrome/browser/media/webrtc/BUILD.gn +++ b/chrome/browser/media/webrtc/BUILD.gn
@@ -99,6 +99,7 @@ "//build:buildflag_header_h", "//chrome/browser:browser_public_dependencies", "//chrome/browser/profiles:profile", + "//chrome/browser/tab_contents", "//chrome/common:mojo_bindings", "//components/content_settings/core/common", "//components/keyed_service/core",
diff --git a/chrome/browser/nearby_sharing/certificates/BUILD.gn b/chrome/browser/nearby_sharing/certificates/BUILD.gn index 26363e72..bfa0269 100644 --- a/chrome/browser/nearby_sharing/certificates/BUILD.gn +++ b/chrome/browser/nearby_sharing/certificates/BUILD.gn
@@ -26,7 +26,6 @@ ] public_deps = [ - "//ash/constants", "//third_party/nearby:encrypted_metadata_proto", "//third_party/nearby:rpc_resources_proto", ]
diff --git a/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager_impl.cc b/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager_impl.cc index b14b454..456e6cc 100644 --- a/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager_impl.cc +++ b/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager_impl.cc
@@ -7,7 +7,6 @@ #include <array> #include <string> -#include "ash/constants/ash_switches.h" #include "base/command_line.h" #include "base/containers/flat_map.h" #include "base/feature_list.h" @@ -24,6 +23,7 @@ #include "chrome/browser/nearby_sharing/client/nearby_share_client.h" #include "chrome/browser/nearby_sharing/common/nearby_share_features.h" #include "chrome/browser/nearby_sharing/common/nearby_share_prefs.h" +#include "chrome/browser/nearby_sharing/common/nearby_share_switches.h" #include "chromeos/ash/components/nearby/common/client/nearby_http_result.h" #include "chromeos/ash/components/nearby/common/scheduling/nearby_scheduler_factory.h" #include "chromeos/ash/services/nearby/public/mojom/nearby_share_settings.mojom.h" @@ -65,13 +65,12 @@ // return the default |kNearbyShareNumPrivateCertificates|. size_t NumPrivateCertificates() { base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - if (!command_line->HasSwitch( - ash::switches::kNearbyShareNumPrivateCertificates)) { + if (!command_line->HasSwitch(switches::kNearbyShareNumPrivateCertificates)) { return kNearbyShareNumPrivateCertificates; } std::string num_certificates_str = command_line->GetSwitchValueASCII( - ash::switches::kNearbyShareNumPrivateCertificates); + switches::kNearbyShareNumPrivateCertificates); int num_certificates = 0; if (!base::StringToInt(num_certificates_str, &num_certificates) || num_certificates < 1) {
diff --git a/chrome/browser/nearby_sharing/certificates/nearby_share_private_certificate.cc b/chrome/browser/nearby_sharing/certificates/nearby_share_private_certificate.cc index 6231e04..e4171df6 100644 --- a/chrome/browser/nearby_sharing/certificates/nearby_share_private_certificate.cc +++ b/chrome/browser/nearby_sharing/certificates/nearby_share_private_certificate.cc
@@ -12,7 +12,6 @@ #include <utility> #include <vector> -#include "ash/constants/ash_switches.h" #include "base/base64url.h" #include "base/command_line.h" #include "base/containers/span.h" @@ -23,6 +22,7 @@ #include "base/strings/string_view_util.h" #include "chrome/browser/nearby_sharing/certificates/common.h" #include "chrome/browser/nearby_sharing/certificates/constants.h" +#include "chrome/browser/nearby_sharing/common/nearby_share_switches.h" #include "chromeos/ash/components/nearby/common/proto/timestamp.pb.h" #include "components/cross_device/logging/logging.h" #include "crypto/aead.h" @@ -130,13 +130,13 @@ base::TimeDelta GetCertificateValidityPeriod() { base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); if (!command_line->HasSwitch( - ash::switches::kNearbyShareCertificateValidityPeriodHours)) { + switches::kNearbyShareCertificateValidityPeriodHours)) { return kNearbyShareCertificateValidityPeriod; } std::string certificate_validity_period_hours_str = command_line->GetSwitchValueASCII( - ash::switches::kNearbyShareCertificateValidityPeriodHours); + switches::kNearbyShareCertificateValidityPeriodHours); int certificate_validity_period_hours = 0; if (!base::StringToInt(certificate_validity_period_hours_str, &certificate_validity_period_hours) ||
diff --git a/chrome/browser/nearby_sharing/client/BUILD.gn b/chrome/browser/nearby_sharing/client/BUILD.gn index 19752b3..340fd061 100644 --- a/chrome/browser/nearby_sharing/client/BUILD.gn +++ b/chrome/browser/nearby_sharing/client/BUILD.gn
@@ -14,7 +14,6 @@ ] deps = [ - "//ash/constants", "//base", "//chrome/browser/nearby_sharing/common", "//chromeos/ash/components/nearby/common/client", @@ -58,7 +57,6 @@ deps = [ ":client", - "//ash/constants", "//base", "//base/test:test_support", "//chrome/browser/nearby_sharing/common",
diff --git a/chrome/browser/nearby_sharing/client/nearby_share_client_impl.cc b/chrome/browser/nearby_sharing/client/nearby_share_client_impl.cc index c8779ac..56d27e4 100644 --- a/chrome/browser/nearby_sharing/client/nearby_share_client_impl.cc +++ b/chrome/browser/nearby_sharing/client/nearby_share_client_impl.cc
@@ -6,13 +6,13 @@ #include <memory> -#include "ash/constants/ash_switches.h" #include "base/base64url.h" #include "base/command_line.h" #include "base/functional/bind.h" #include "base/memory/ptr_util.h" #include "base/strings/string_number_conversions.h" #include "chrome/browser/nearby_sharing/client/nearby_share_http_notifier.h" +#include "chrome/browser/nearby_sharing/common/nearby_share_switches.h" #include "chromeos/ash/components/nearby/common/client/nearby_api_call_flow_impl.h" #include "chromeos/ash/components/nearby/common/client/nearby_http_result.h" #include "components/cross_device/logging/logging.h" @@ -46,11 +46,10 @@ // |request_path|. GURL CreateV1RequestUrl(const std::string& request_path) { base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - GURL google_apis_url = - command_line->HasSwitch(ash::switches::kNearbyShareHTTPHost) - ? GURL(command_line->GetSwitchValueASCII( - ash::switches::kNearbyShareHTTPHost)) - : GURL(kDefaultNearbyShareV1HTTPHost); + GURL google_apis_url = command_line->HasSwitch(switches::kNearbyShareHTTPHost) + ? GURL(command_line->GetSwitchValueASCII( + switches::kNearbyShareHTTPHost)) + : GURL(kDefaultNearbyShareV1HTTPHost); return google_apis_url.Resolve(kNearbyShareV1Path + request_path); }
diff --git a/chrome/browser/nearby_sharing/client/nearby_share_client_impl_unittest.cc b/chrome/browser/nearby_sharing/client/nearby_share_client_impl_unittest.cc index 882d39dd..10f9601 100644 --- a/chrome/browser/nearby_sharing/client/nearby_share_client_impl_unittest.cc +++ b/chrome/browser/nearby_sharing/client/nearby_share_client_impl_unittest.cc
@@ -2,13 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/nearby_sharing/client/nearby_share_client_impl.h" - #include <string> #include <utility> #include <vector> -#include "ash/constants/ash_switches.h" #include "base/command_line.h" #include "base/functional/bind.h" #include "base/memory/ptr_util.h" @@ -19,7 +16,9 @@ #include "base/test/task_environment.h" #include "base/test/test_future.h" #include "chrome/browser/nearby_sharing/client/nearby_share_client.h" +#include "chrome/browser/nearby_sharing/client/nearby_share_client_impl.h" #include "chrome/browser/nearby_sharing/client/nearby_share_http_notifier.h" +#include "chrome/browser/nearby_sharing/common/nearby_share_switches.h" #include "chromeos/ash/components/nearby/common/client/nearby_api_call_flow.h" #include "chromeos/ash/components/nearby/common/client/nearby_api_call_flow_impl.h" #include "chromeos/ash/components/nearby/common/client/nearby_http_result.h" @@ -177,7 +176,7 @@ void SetUp() override { base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( - ash::switches::kNearbyShareHTTPHost, kTestGoogleApisUrl); + switches::kNearbyShareHTTPHost, kTestGoogleApisUrl); identity_test_environment_.MakePrimaryAccountAvailable( kEmail, signin::ConsentLevel::kSignin);
diff --git a/chrome/browser/nearby_sharing/common/BUILD.gn b/chrome/browser/nearby_sharing/common/BUILD.gn index 3b28a35..38c1bbb 100644 --- a/chrome/browser/nearby_sharing/common/BUILD.gn +++ b/chrome/browser/nearby_sharing/common/BUILD.gn
@@ -14,6 +14,8 @@ "nearby_share_prefs.h", "nearby_share_resource_getter.cc", "nearby_share_resource_getter.h", + "nearby_share_switches.cc", + "nearby_share_switches.h", ] public_deps = [ "//base" ]
diff --git a/chrome/browser/nearby_sharing/common/nearby_share_switches.cc b/chrome/browser/nearby_sharing/common/nearby_share_switches.cc new file mode 100644 index 0000000..7bf0086 --- /dev/null +++ b/chrome/browser/nearby_sharing/common/nearby_share_switches.cc
@@ -0,0 +1,27 @@ +// 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. + +#include "chrome/browser/nearby_sharing/common/nearby_share_switches.h" + +namespace switches { + +// Overrides the default validity period for Nearby Share certificates. Value +// must be larger than 0. +const char kNearbyShareCertificateValidityPeriodHours[] = + "nearby-share-certificate-validity-period-hours"; + +// Overrides the default device ID to provide a stable ID in test environments. +// By default we generate a random 10-character string. +const char kNearbyShareDeviceID[] = "nearby-share-device-id"; + +// Overrides the default URL for Google APIs (https://www.googleapis.com) used +// by Nearby Share +const char kNearbyShareHTTPHost[] = "nearbysharing-http-host"; + +// Overrides the default number of private certificates generated. Value must be +// larger than 0. +const char kNearbyShareNumPrivateCertificates[] = + "nearby-share-num-private-certificates"; + +} // namespace switches
diff --git a/chrome/browser/nearby_sharing/common/nearby_share_switches.h b/chrome/browser/nearby_sharing/common/nearby_share_switches.h new file mode 100644 index 0000000..787cb75 --- /dev/null +++ b/chrome/browser/nearby_sharing/common/nearby_share_switches.h
@@ -0,0 +1,19 @@ +// 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. + +#ifndef CHROME_BROWSER_NEARBY_SHARING_COMMON_NEARBY_SHARE_SWITCHES_H_ +#define CHROME_BROWSER_NEARBY_SHARING_COMMON_NEARBY_SHARE_SWITCHES_H_ + +namespace switches { + +// All switches in alphabetical order. The switches should be documented +// alongside the definition of their values in the .cc file. +extern const char kNearbyShareCertificateValidityPeriodHours[]; +extern const char kNearbyShareDeviceID[]; +extern const char kNearbyShareHTTPHost[]; +extern const char kNearbyShareNumPrivateCertificates[]; + +} // namespace switches + +#endif // CHROME_BROWSER_NEARBY_SHARING_COMMON_NEARBY_SHARE_SWITCHES_H_
diff --git a/chrome/browser/nearby_sharing/local_device_data/BUILD.gn b/chrome/browser/nearby_sharing/local_device_data/BUILD.gn index 0306e2a9..8f3e82d1 100644 --- a/chrome/browser/nearby_sharing/local_device_data/BUILD.gn +++ b/chrome/browser/nearby_sharing/local_device_data/BUILD.gn
@@ -16,10 +16,7 @@ "nearby_share_local_device_data_manager_impl.h", ] - public_deps = [ - "//ash/constants", - "//chromeos/ash/services/nearby/public/mojom", - ] + public_deps = [ "//chromeos/ash/services/nearby/public/mojom" ] deps = [ "//base",
diff --git a/chrome/browser/nearby_sharing/local_device_data/nearby_share_local_device_data_manager_impl.cc b/chrome/browser/nearby_sharing/local_device_data/nearby_share_local_device_data_manager_impl.cc index 6062d0d..4b15dbd8 100644 --- a/chrome/browser/nearby_sharing/local_device_data/nearby_share_local_device_data_manager_impl.cc +++ b/chrome/browser/nearby_sharing/local_device_data/nearby_share_local_device_data_manager_impl.cc
@@ -7,7 +7,6 @@ #include <string> #include <utility> -#include "ash/constants/ash_switches.h" #include "base/command_line.h" #include "base/functional/bind.h" #include "base/memory/ptr_util.h" @@ -16,6 +15,7 @@ #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/nearby_sharing/common/nearby_share_prefs.h" +#include "chrome/browser/nearby_sharing/common/nearby_share_switches.h" #include "chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater.h" #include "chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater_impl.h" #include "chrome/grit/generated_resources.h" @@ -115,8 +115,8 @@ return id; base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - if (command_line->HasSwitch(ash::switches::kNearbyShareDeviceID)) { - id = command_line->GetSwitchValueASCII(ash::switches::kNearbyShareDeviceID); + if (command_line->HasSwitch(switches::kNearbyShareDeviceID)) { + id = command_line->GetSwitchValueASCII(switches::kNearbyShareDeviceID); } else { for (size_t i = 0; i < kDeviceIdLength; ++i) id += kAlphaNumericChars[base::RandGenerator(kAlphaNumericChars.size())];
diff --git a/chrome/browser/new_tab_page/feature_promo_helper/new_tab_page_feature_promo_helper_unittest.cc b/chrome/browser/new_tab_page/feature_promo_helper/new_tab_page_feature_promo_helper_unittest.cc index 8f094a1..27b85f4 100644 --- a/chrome/browser/new_tab_page/feature_promo_helper/new_tab_page_feature_promo_helper_unittest.cc +++ b/chrome/browser/new_tab_page/feature_promo_helper/new_tab_page_feature_promo_helper_unittest.cc
@@ -94,7 +94,7 @@ *user_education(), MaybeShowFeaturePromo(user_education::test::MatchFeaturePromoParams( feature_engagement::kIPHDesktopCustomizeChromeExperimentFeature))) - .Times(1); + .WillOnce(testing::Return(true)); helper()->SetDefaultSearchProviderIsGoogleForTesting(true); helper()->MaybeShowFeaturePromo( feature_engagement::kIPHDesktopCustomizeChromeExperimentFeature, tab());
diff --git a/chrome/browser/notifications/notification_permission_context.cc b/chrome/browser/notifications/notification_permission_context.cc index e0f5a5b..1787328 100644 --- a/chrome/browser/notifications/notification_permission_context.cc +++ b/chrome/browser/notifications/notification_permission_context.cc
@@ -15,7 +15,6 @@ #include "build/build_config.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/visibility_timer_tab_helper.h" #include "components/content_settings/browser/page_specific_content_settings.h" #include "components/content_settings/core/browser/host_content_settings_map.h" #include "components/content_settings/core/common/content_settings_pattern.h" @@ -23,6 +22,7 @@ #include "components/permissions/permission_decision.h" #include "components/permissions/permission_prompt_decision.h" #include "components/permissions/permission_request_id.h" +#include "components/visibility_timer/visibility_timer_tab_helper.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/permission_descriptor_util.h" #include "content/public/browser/permission_request_description.h" @@ -176,8 +176,9 @@ if (browser_context()->IsOffTheRecord()) { // Random number of seconds in the range [1.0, 2.0). double delay_seconds = 1.0 + 1.0 * base::RandDouble(); - VisibilityTimerTabHelper::CreateForWebContents(web_contents); - VisibilityTimerTabHelper::FromWebContents(web_contents) + visibility_timer::VisibilityTimerTabHelper::CreateForWebContents( + web_contents); + visibility_timer::VisibilityTimerTabHelper::FromWebContents(web_contents) ->PostTaskAfterVisibleDelay( FROM_HERE, base::BindOnce(
diff --git a/chrome/browser/notifications/notification_permission_context_unittest.cc b/chrome/browser/notifications/notification_permission_context_unittest.cc index 749d5f6..37c55eff 100644 --- a/chrome/browser/notifications/notification_permission_context_unittest.cc +++ b/chrome/browser/notifications/notification_permission_context_unittest.cc
@@ -436,10 +436,10 @@ // Time elapsed whilst hidden is not counted. // n.b. This line also clears out any old scheduled timer tasks. This is // important, because otherwise Timer::Reset (triggered by - // VisibilityTimerTabHelper::WasShown) may choose to re-use an existing - // scheduled task, and when it fires Timer::RunScheduledTask will call - // TimeTicks::Now() (which unlike task_runner->NowTicks(), we can't fake), - // and miscalculate the remaining delay at which to fire the timer. + // visibility_timer::VisibilityTimerTabHelper::WasShown) may choose to re-use + // an existing scheduled task, and when it fires Timer::RunScheduledTask will + // call TimeTicks::Now() (which unlike task_runner->NowTicks(), we can't + // fake), and miscalculate the remaining delay at which to fire the timer. task_runner->FastForwardBy(base::Days(1)); EXPECT_EQ(0, permission_context.permission_set_count());
diff --git a/chrome/browser/optimization_guide/android/optimization_guide_bridge_unittest.cc b/chrome/browser/optimization_guide/android/optimization_guide_bridge_unittest.cc index f7e782f..acd6457 100644 --- a/chrome/browser/optimization_guide/android/optimization_guide_bridge_unittest.cc +++ b/chrome/browser/optimization_guide/android/optimization_guide_bridge_unittest.cc
@@ -64,7 +64,7 @@ -> std::unique_ptr<KeyedService> { return std::make_unique<MockOptimizationGuideKeyedService>(); }))); - j_test_ = JOptimizationGuideBridgeNativeUnitTestClass::Constructor( + j_test_ = JOptimizationGuideBridgeNativeUnitTestClass::New( env_, optimization_guide_keyed_service_->GetJavaObject()); }
diff --git a/chrome/browser/password_manager/android/grouped_affiliations/acknowledge_grouped_credential_sheet_bridge.cc b/chrome/browser/password_manager/android/grouped_affiliations/acknowledge_grouped_credential_sheet_bridge.cc index 677c1ace..77dfced3d 100644 --- a/chrome/browser/password_manager/android/grouped_affiliations/acknowledge_grouped_credential_sheet_bridge.cc +++ b/chrome/browser/password_manager/android/grouped_affiliations/acknowledge_grouped_credential_sheet_bridge.cc
@@ -31,11 +31,9 @@ void Create(const gfx::NativeWindow window_android, AcknowledgeGroupedCredentialSheetBridge* bridge) override { - java_bridge_.Reset( - JAcknowledgeGroupedCredentialSheetBridgeClass::Constructor( - base::android::AttachCurrentThread(), - reinterpret_cast<intptr_t>(bridge), - window_android->GetJavaObject())); + java_bridge_.Reset(JAcknowledgeGroupedCredentialSheetBridgeClass::New( + base::android::AttachCurrentThread(), + reinterpret_cast<intptr_t>(bridge), window_android->GetJavaObject())); } void Show(const std::string& current_hostname,
diff --git a/chrome/browser/password_manager/password_change/password_change_from_checkup_delegate.cc b/chrome/browser/password_manager/password_change/password_change_from_checkup_delegate.cc index 677c9cf..11644ad2 100644 --- a/chrome/browser/password_manager/password_change/password_change_from_checkup_delegate.cc +++ b/chrome/browser/password_manager/password_change/password_change_from_checkup_delegate.cc
@@ -189,8 +189,7 @@ return; } - glic::GlicKeyedService* glic_service = glic::GlicKeyedService::Get( - Profile::FromBrowserContext(originator_->GetBrowserContext())); + glic::GlicKeyedService* glic_service = GetGlicService(); if (!glic_service) { return; } @@ -238,13 +237,8 @@ actuation_web_contents_ = new_contents->GetWeakPtr(); actor_task_state_subscription_ = actor_service->AddTaskStateChangedCallback(base::BindRepeating( - &PasswordChangeFromCheckupDelegate::OnActorTaskStateChanged, + &PasswordChangeFromCheckupDelegate::OnFindFormTaskStateChanged, base::Unretained(this))); - - // TODO(crbug.com/485620841): Return focus to the settings tab right after - // invoking in the newly opened tab. Do this when the Invoke API fully wires - // up `additional_context`. Currently, if Invoke is called on a background - // tab, it will not start the flow unless the user goes to the tab. } } @@ -256,10 +250,10 @@ Profile::FromBrowserContext(originator_->GetBrowserContext())); } -void PasswordChangeFromCheckupDelegate::OnActorTaskStateChanged( +void PasswordChangeFromCheckupDelegate::OnFindFormTaskStateChanged( actor::TaskId task_id, actor::ActorTask::State new_state) { - if (!actor_task_id_ && new_state == actor::ActorTask::State::kCreated) { + if (!find_form_task_id_ && new_state == actor::ActorTask::State::kCreated) { actor::ActorKeyedService* actor_service = actor::ActorKeyedService::Get(Profile::FromBrowserContext( actuation_web_contents_->GetBrowserContext())); @@ -271,27 +265,22 @@ if (!actor_task_for_actuation) { return; } - actor_task_id_ = actor_task_for_actuation->id(); + + find_form_task_id_ = actor_task_for_actuation->id(); return; } - if (actor_task_id_ && *actor_task_id_ != task_id) { - // Ignore tasks unrelated to the password change flow. - return; + if (find_form_task_id_ && *find_form_task_id_ != task_id) { + return; // Ignore unrelated tasks } if (IsTaskInterrupted(new_state)) { - // Focus the actuation tab when there is an interruption so the user can - // complete the flow. ActivateTabForWebContents(actuation_web_contents_.get()); - } else if (actor_state_.has_value() && - IsTaskResumed(actor_state_.value(), new_state)) { - // Return focus to the original tab. + } else if (find_form_task_state_.has_value() && + IsTaskResumed(find_form_task_state_.value(), new_state)) { ActivateTabForWebContents(originator_.get()); } - // When the task reaches `kFinished` it is assumed that the change password - // form was found. if (new_state == actor::ActorTask::State::kFinished) { actor_task_state_subscription_ = {}; auto* client = ChromePasswordManagerClient::FromWebContents( @@ -308,8 +297,7 @@ .Build(); } - // Set the new state. - actor_state_ = new_state; + find_form_task_state_ = new_state; } void PasswordChangeFromCheckupDelegate::OnChangePasswordFormManagerFound( @@ -341,4 +329,116 @@ void PasswordChangeFromCheckupDelegate::OnChangePasswordFormSubmitted( ChangePasswordFormFillingSubmissionHelper::SubmissionResult result) { submission_helper_.reset(); + + // If the form submission failed, do not trigger a verification task. + if (!result.has_value()) { + return; + } + + saved_form_manager_ = std::move(result).value(); + if (!actuation_web_contents_) { + return; + } + + glic::GlicKeyedService* glic_service = GetGlicService(); + if (!glic_service) { + return; + } + + tabs::TabInterface* tab_interface = + tabs::TabInterface::MaybeGetFromContents(actuation_web_contents_.get()); + if (!tab_interface) { + return; + } + + verification_task_id_ = std::nullopt; + verification_task_created_ = false; + + glic::GlicInvokeOptions options(glic::mojom::InvocationSource::kSharedTab); + // TODO(crbug.com/485620841): Read this from internal. + options.prompts.push_back( + "I just filled and submitted a change password form in order to change " + "my password. Tell me if this was successful or not, if it was not " + "successful and there are extra steps needed, complete the extra steps " + "in my behalf."); + + options.additional_context = glic::mojom::AdditionalContext::New(); + sessions::SessionTabHelper* session_tab_helper = + sessions::SessionTabHelper::FromWebContents( + actuation_web_contents_.get()); + if (session_tab_helper) { + options.additional_context->tab_id = session_tab_helper->session_id().id(); + } + + glic_service->InvokeWithAutoSubmit( + glic::InvokeWithAutoSubmitPasskeyProvider::GetPassKey(), tab_interface, + std::move(options)); + + actor::ActorKeyedService* actor_service = + actor::ActorKeyedService::Get(Profile::FromBrowserContext( + actuation_web_contents_->GetBrowserContext())); + if (actor_service) { + actor_task_state_subscription_ = + actor_service->AddTaskStateChangedCallback(base::BindRepeating( + &PasswordChangeFromCheckupDelegate::OnVerificationTaskStateChanged, + base::Unretained(this))); + } + + // If no task is created after 5 seconds, we assume that it was a successful + // change since and no extra steps are needed. + verification_timer_.Start( + FROM_HERE, base::Seconds(5), + base::BindOnce(&PasswordChangeFromCheckupDelegate::OnVerificationTimeout, + weak_ptr_factory_.GetWeakPtr())); +} + +void PasswordChangeFromCheckupDelegate::OnVerificationTaskStateChanged( + actor::TaskId task_id, + actor::ActorTask::State new_state) { + if (!verification_task_id_) { + actor::ActorKeyedService* actor_service = + actor::ActorKeyedService::Get(Profile::FromBrowserContext( + actuation_web_contents_->GetBrowserContext())); + CHECK(actor_service); + + actor::ActorTask* actor_task = + actor_service->GetTaskFromTab(*tabs::TabInterface::MaybeGetFromContents( + actuation_web_contents_.get())); + + if (!actor_task) { + return; + } + + verification_task_id_ = actor_task->id(); + verification_task_created_ = true; + // A task was created, so stopping the timer to not trigger + // the password being saved. + verification_timer_.Stop(); + return; + } + + // Ignore unrelated tasks. + if (verification_task_id_ && *verification_task_id_ != task_id) { + return; + } + + // If the task for verifification finishes, we assume success. + if (new_state == actor::ActorTask::State::kFinished) { + actor_task_state_subscription_ = {}; + HandleMaybeSuccessfulPasswordChange(); + } +} + +void PasswordChangeFromCheckupDelegate::OnVerificationTimeout() { + if (!verification_task_created_) { + actor_task_state_subscription_ = {}; + HandleMaybeSuccessfulPasswordChange(); + } +} + +void PasswordChangeFromCheckupDelegate::HandleMaybeSuccessfulPasswordChange() { + if (saved_form_manager_) { + saved_form_manager_->Save(); + saved_form_manager_.reset(); + } }
diff --git a/chrome/browser/password_manager/password_change/password_change_from_checkup_delegate.h b/chrome/browser/password_manager/password_change/password_change_from_checkup_delegate.h index 0f17e4d8..c3ba4f7 100644 --- a/chrome/browser/password_manager/password_change/password_change_from_checkup_delegate.h +++ b/chrome/browser/password_manager/password_change/password_change_from_checkup_delegate.h
@@ -5,10 +5,12 @@ #ifndef CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_CHANGE_PASSWORD_CHANGE_FROM_CHECKUP_DELEGATE_H_ #define CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_CHANGE_PASSWORD_CHANGE_FROM_CHECKUP_DELEGATE_H_ +#include <memory> #include <string> #include "base/callback_list.h" #include "base/memory/weak_ptr.h" +#include "base/timer/timer.h" #include "chrome/browser/actor/actor_keyed_service.h" #include "chrome/browser/password_manager/password_change/change_password_form_filling_submission_helper.h" #include "url/gurl.h" @@ -44,14 +46,9 @@ bool HasActorTaskSubscriptionForTesting() const { return !!actor_task_state_subscription_; } - // TODO(crbug.com/485620841): Check a different state when the form is - // submitted. - bool IsCleanedUpAfterTaskFinishedForTesting() const { - return !submission_helper_; - } - std::optional<actor::ActorTask::State> GetActorTaskState() const { - return actor_state_; + std::optional<actor::ActorTask::State> GetFindFormTaskState() const { + return find_form_task_state_; } #endif @@ -61,27 +58,37 @@ glic::GlicKeyedService* GetGlicService(); - void OnActorTaskStateChanged(actor::TaskId task_id, - actor::ActorTask::State state); + void OnFindFormTaskStateChanged(actor::TaskId task_id, + actor::ActorTask::State state); void OnChangePasswordFormManagerFound( password_manager::PasswordFormManager* form_manager); void OnChangePasswordFormSubmitted( ChangePasswordFormFillingSubmissionHelper::SubmissionResult result); + void OnVerificationTaskStateChanged(actor::TaskId task_id, + actor::ActorTask::State state); + void OnVerificationTimeout(); + void HandleMaybeSuccessfulPasswordChange(); + base::WeakPtr<content::WebContents> originator_; base::WeakPtr<content::WebContents> actuation_web_contents_; std::u16string username_; std::u16string current_password_; - std::optional<actor::TaskId> actor_task_id_; base::CallbackListSubscription actor_task_state_subscription_; std::unique_ptr<ChangePasswordFormFillingSubmissionHelper> submission_helper_; std::unique_ptr<ChangePasswordFormWaiter> form_waiter_; - std::optional<actor::ActorTask::State> actor_state_ = std::nullopt; + std::optional<actor::TaskId> find_form_task_id_; + std::optional<actor::ActorTask::State> find_form_task_state_ = std::nullopt; + + std::optional<actor::TaskId> verification_task_id_; + std::unique_ptr<password_manager::PasswordFormManager> saved_form_manager_; + bool verification_task_created_ = false; + base::OneShotTimer verification_timer_; base::WeakPtrFactory<PasswordChangeFromCheckupDelegate> weak_ptr_factory_{ this};
diff --git a/chrome/browser/password_manager/password_change_from_checkup_browsertest.cc b/chrome/browser/password_manager/password_change_from_checkup_browsertest.cc index faed056..5a20a47b 100644 --- a/chrome/browser/password_manager/password_change_from_checkup_browsertest.cc +++ b/chrome/browser/password_manager/password_change_from_checkup_browsertest.cc
@@ -59,7 +59,7 @@ } // namespace class PasswordChangeFromCheckupDelegateBrowserTest - : public InProcessBrowserTest { + : public PasswordManagerBrowserTestBase { public: void SetUpBrowserContextKeyedServices( content::BrowserContext* context) override { @@ -68,9 +68,8 @@ } void SetUpOnMainThread() override { - InProcessBrowserTest::SetUpOnMainThread(); + PasswordManagerBrowserTestBase::SetUpOnMainThread(); host_resolver()->AddRule("example.com", "127.0.0.1"); - ASSERT_TRUE(embedded_test_server()->Start()); } private: @@ -166,10 +165,17 @@ actor::ActorTask::StoppedReason::kTaskComplete); run_loop.Run(); - EXPECT_TRUE(base::test::RunUntil( - [&]() { return !delegate->HasActorTaskSubscriptionForTesting(); })); - EXPECT_TRUE(base::test::RunUntil( - [&]() { return delegate->IsCleanedUpAfterTaskFinishedForTesting(); })); + // After the form is submitted a verification task is created + // and finished. + actor::TaskId verification_task_id = actor_service->CreateTask( + actor::TestTaskSourceInfo(), actor::NoEnterprisePolicyChecker()); + actor_service->StopTask(verification_task_id, + actor::ActorTask::StoppedReason::kTaskComplete); + + // Wait for the new password to be saved. + WaitForPasswordStore(); + CheckThatCredentialsStored(/*username=*/"testuser", /*password=*/"testpass"); + EXPECT_FALSE(delegate->HasActorTaskSubscriptionForTesting()); } IN_PROC_BROWSER_TEST_F(PasswordChangeFromCheckupDelegateBrowserTest, @@ -209,7 +215,7 @@ // tab into focus. EXPECT_EQ(browser()->tab_strip_model()->GetActiveWebContents(), actuation_contents); - EXPECT_EQ(delegate->GetActorTaskState(), + EXPECT_EQ(delegate->GetFindFormTaskState(), actor::ActorTask::State::kPausedByActor); actor_service->StopTask(task_id, @@ -253,7 +259,7 @@ // originator tab into focus. EXPECT_EQ(browser()->tab_strip_model()->GetActiveWebContents(), originator_contents); - EXPECT_EQ(delegate->GetActorTaskState(), actor::ActorTask::State::kActing); + EXPECT_EQ(delegate->GetFindFormTaskState(), actor::ActorTask::State::kActing); // Clean up. actor_service->StopTask(task_id,
diff --git a/chrome/browser/permissions/BUILD.gn b/chrome/browser/permissions/BUILD.gn index d6b5469..cc4cd3c 100644 --- a/chrome/browser/permissions/BUILD.gn +++ b/chrome/browser/permissions/BUILD.gn
@@ -80,6 +80,7 @@ "//chrome/browser/engagement", "//chrome/browser/favicon", "//chrome/browser/geolocation", + "//chrome/browser/idle", "//chrome/browser/metrics", "//chrome/browser/nfc", "//chrome/browser/optimization_guide", @@ -91,6 +92,7 @@ "//chrome/browser/serial", "//chrome/browser/storage", "//chrome/browser/storage_access_api", + "//chrome/browser/tab_contents", "//chrome/browser/top_level_storage_access_api:permissions", "//chrome/browser/translate", "//chrome/browser/ui/hats",
diff --git a/chrome/browser/platform_experience/win b/chrome/browser/platform_experience/win index d93f2de..eae77b9 160000 --- a/chrome/browser/platform_experience/win +++ b/chrome/browser/platform_experience/win
@@ -1 +1 @@ -Subproject commit d93f2deda5040ed4675535a608ee89cf92d208cc +Subproject commit eae77b923c7cb4953c2ed0a228942f9129e9a48e
diff --git a/chrome/browser/resources/ai_overlay_dialog/BUILD.gn b/chrome/browser/resources/ai_overlay_dialog/BUILD.gn index 9f07a8f1..a57bece 100644 --- a/chrome/browser/resources/ai_overlay_dialog/BUILD.gn +++ b/chrome/browser/resources/ai_overlay_dialog/BUILD.gn
@@ -18,7 +18,13 @@ ts_deps = [ "//third_party/lit/v3_0:build_ts", "//ui/webui/resources/js:build_ts", + "//ui/webui/resources/mojo:build_ts", ] + mojo_files_deps = [ + "//chrome/browser/ui/webui/ai_overlay_dialog:mojo_bindings_ts__generator", + ] + mojo_files = [ "$root_gen_dir/chrome/browser/ui/webui/ai_overlay_dialog/ai_overlay_dialog.mojom-webui.ts" ] + webui_context_type = "untrusted" }
diff --git a/chrome/browser/resources/ai_overlay_dialog/app.ts b/chrome/browser/resources/ai_overlay_dialog/app.ts index 3a80faa..cdaaf97 100644 --- a/chrome/browser/resources/ai_overlay_dialog/app.ts +++ b/chrome/browser/resources/ai_overlay_dialog/app.ts
@@ -4,6 +4,7 @@ import {CrLitElement} from '//resources/lit/v3_0/lit.rollup.js'; +import {PageHandlerFactory, PageHandlerRemote} from './ai_overlay_dialog.mojom-webui.js'; import {getCss} from './app.css.js'; import {getHtml} from './app.html.js'; @@ -31,7 +32,39 @@ protected accessor isListening: boolean = false; + private pageHandler: PageHandlerRemote; + + // API key to use to connect to backend. Only used for development when + // provided on command line. + private apiKey: string = ''; + + // If onStateClick_ happens before the API key mojo returns, this will turn + // to true and invoke the state change after the key becomes available. + private queueStateChange: boolean = false; + + constructor() { + super(); + + // Setup Mojo connection + this.pageHandler = new PageHandlerRemote(); + const factory = PageHandlerFactory.getRemote(); + factory.createPageHandler(this.pageHandler.$.bindNewPipeAndPassReceiver()); + + this.pageHandler.getApiKey().then(({apiKey}) => { + this.apiKey = apiKey; + if (this.queueStateChange) { + this.onStateClick_(); + this.queueStateChange = false; + } + }); + } + protected onStateClick_() { + if (!this.apiKey) { + console.warn('API key not yet available'); + this.queueStateChange = true; + return; + } this.isListening = !this.isListening; } }
diff --git a/chrome/browser/resources/chrome_finds_internals/app.html.ts b/chrome/browser/resources/chrome_finds_internals/app.html.ts index 7cf11806..994dd28 100644 --- a/chrome/browser/resources/chrome_finds_internals/app.html.ts +++ b/chrome/browser/resources/chrome_finds_internals/app.html.ts
@@ -35,16 +35,17 @@ <textarea id="prompt-input" rows="10" .value="${this.prompt_}" @input="${this.onPromptInput_}" placeholder="Paste prompt here..."></textarea> - <div class="button-row"> <cr-button id="start-btn" class="action-button" @click="${this.onStartClick_}">Start</cr-button> + <cr-button id="run-finds-model-btn" class="action-button" + @click="${ + this.onRunFindsModelClick_}">Run FindsService Model</cr-button> <cr-button id="reset-btn" @click="${this.onResetClick_}"> Reset to Default Prompt </cr-button> <cr-button id="dump-history-btn" @click="${this.onDumpHistoryClick_}"> Dump History to JSON </cr-button> - </div> </section> <section id="history-dump-section" ?hidden="${!this.historyJson_}">
diff --git a/chrome/browser/resources/chrome_finds_internals/app.ts b/chrome/browser/resources/chrome_finds_internals/app.ts index 1a176663..54c45ba3 100644 --- a/chrome/browser/resources/chrome_finds_internals/app.ts +++ b/chrome/browser/resources/chrome_finds_internals/app.ts
@@ -77,6 +77,11 @@ this.handler_.start(this.prompt_, this.historyCount_); } + protected onRunFindsModelClick_() { + this.appendLog_('Running FindsService Model...'); + this.handler_.getFindsServiceModelResponse(); + } + protected onResetClick_() { this.prompt_ = DEFAULT_PROMPT; this.appendLog_('Prompt reset to default.');
diff --git a/chrome/browser/resources/content_annotator_internals/BUILD.gn b/chrome/browser/resources/content_annotator_internals/BUILD.gn index 3b864cbc..bc7e42b 100644 --- a/chrome/browser/resources/content_annotator_internals/BUILD.gn +++ b/chrome/browser/resources/content_annotator_internals/BUILD.gn
@@ -5,6 +5,7 @@ import("//ui/webui/resources/tools/build_webui.gni") assert(!is_android) + build_webui("build") { grd_prefix = "content_annotator_internals" @@ -13,9 +14,13 @@ ts_files = [ "app.ts", "app.html.ts", + "browser_proxy.ts", ] css_files = [ "app.css" ] + mojo_files_deps = [ "//components/accessibility_annotator/core/logging:mojo_bindings_ts__generator" ] + mojo_files = [ "$root_gen_dir/components/accessibility_annotator/core/logging/accessibility_annotator_internals.mojom-webui.ts" ] + # Enable the proper webui_context_type depending on whether implementing # a chrome:// or chrome-untrusted:// page. webui_context_type = "trusted" @@ -23,5 +28,6 @@ ts_deps = [ "//third_party/lit/v3_0:build_ts", "//ui/webui/resources/js:build_ts", + "//ui/webui/resources/mojo:build_ts", ] }
diff --git a/chrome/browser/resources/content_annotator_internals/app.html.ts b/chrome/browser/resources/content_annotator_internals/app.html.ts index 8f9a1ce..77b86b6 100644 --- a/chrome/browser/resources/content_annotator_internals/app.html.ts +++ b/chrome/browser/resources/content_annotator_internals/app.html.ts
@@ -8,6 +8,9 @@ export function getHtml(this: ContentAnnotatorInternalsAppElement) { return html` -<h1>Content Annotator Internals</h1> -<div id="example-div">${this.message_}</div>`; + <h1>Content Annotator Internals</h1> + <div id="example-div">${this.message_}</div> + <h2>Log File Content:</h2> + <pre>${this.logContent_}</pre> + `; }
diff --git a/chrome/browser/resources/content_annotator_internals/app.ts b/chrome/browser/resources/content_annotator_internals/app.ts index 80af8b6..598c882e 100644 --- a/chrome/browser/resources/content_annotator_internals/app.ts +++ b/chrome/browser/resources/content_annotator_internals/app.ts
@@ -9,6 +9,8 @@ import {getCss} from './app.css.js'; import {getHtml} from './app.html.js'; +import {BrowserProxyImpl} from './browser_proxy.js'; +import type {BrowserProxy} from './browser_proxy.js'; export class ContentAnnotatorInternalsAppElement extends CrLitElement { static get is() { @@ -26,10 +28,28 @@ static override get properties() { return { message_: {type: String}, + logContent_: {type: String}, }; } protected accessor message_: string = loadTimeData.getString('message'); + protected accessor logContent_: string = 'Loading log content...'; + private browserProxy_: BrowserProxy = BrowserProxyImpl.getInstance(); + + override connectedCallback() { + super.connectedCallback(); + this.loadLogContent_(); + } + + private async loadLogContent_() { + try { + const result = await this.browserProxy_.handler.getAnnotatedContent(); + this.logContent_ = + result.content ?? 'Error retrieving annotated content.'; + } catch (e) { + this.logContent_ = `Error loading log: ${e}`; + } + } } declare global {
diff --git a/chrome/browser/resources/content_annotator_internals/browser_proxy.ts b/chrome/browser/resources/content_annotator_internals/browser_proxy.ts new file mode 100644 index 0000000..7227d22 --- /dev/null +++ b/chrome/browser/resources/content_annotator_internals/browser_proxy.ts
@@ -0,0 +1,34 @@ +// Copyright 2026 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import {PageCallbackRouter, PageHandlerFactory, PageHandlerRemote} from './accessibility_annotator_internals.mojom-webui.js'; +import type {PageHandlerInterface} from './accessibility_annotator_internals.mojom-webui.js'; + +export interface BrowserProxy { + callbackRouter: PageCallbackRouter; + handler: PageHandlerInterface; +} + +export class BrowserProxyImpl implements BrowserProxy { + callbackRouter: PageCallbackRouter; + handler: PageHandlerInterface; + + private constructor() { + this.callbackRouter = new PageCallbackRouter(); + this.handler = new PageHandlerRemote(); + PageHandlerFactory.getRemote().createPageHandler( + this.callbackRouter.$.bindNewPipeAndPassRemote(), + (this.handler as PageHandlerRemote).$.bindNewPipeAndPassReceiver()); + } + + static getInstance(): BrowserProxy { + return instance || (instance = new BrowserProxyImpl()); + } + + static setInstance(proxy: BrowserProxy) { + instance = proxy; + } +} + +let instance: BrowserProxy|null = null;
diff --git a/chrome/browser/resources/contextual_tasks/app.css b/chrome/browser/resources/contextual_tasks/app.css index 078cd76..cce71e9 100644 --- a/chrome/browser/resources/contextual_tasks/app.css +++ b/chrome/browser/resources/contextual_tasks/app.css
@@ -389,6 +389,11 @@ width: var(--composebox-width); } +:host(:not([is-shown-in-tab_])) #composebox { + inset-inline-start: 0; + margin: 0 auto; +} + :host([is-zero-state_]) #composebox { animation: zero-state-intro 600ms ease forwards;
diff --git a/chrome/browser/resources/contextual_tasks/composebox.css b/chrome/browser/resources/contextual_tasks/composebox.css index 18a01d8..8154eb2 100644 --- a/chrome/browser/resources/contextual_tasks/composebox.css +++ b/chrome/browser/resources/contextual_tasks/composebox.css
@@ -229,9 +229,14 @@ #composebox::part(input), #composebox::part(smart-compose) { + min-height: 48px; padding-inline-start: var(--g-input-left-spacing); } +#composebox::part(context-menu-and-tools) { + min-height: var(--cr-icon-button-size); +} + #composebox::part(input)::placeholder { color: revert; }
diff --git a/chrome/browser/resources/contextual_tasks/composebox.html.ts b/chrome/browser/resources/contextual_tasks/composebox.html.ts index f3e3678..6e59cf5 100644 --- a/chrome/browser/resources/contextual_tasks/composebox.html.ts +++ b/chrome/browser/resources/contextual_tasks/composebox.html.ts
@@ -47,7 +47,7 @@ > <cr-composebox id="composebox" - ?autofocus="${false}" + .autofocus="${false}" carousel-on-top_ entrypoint-name="ContextualTasks" searchbox-layout-mode="TallBottomContext"
diff --git a/chrome/browser/resources/feedback/report_unsafe_site.html b/chrome/browser/resources/feedback/report_unsafe_site.html index e799b99..4ed96c4 100644 --- a/chrome/browser/resources/feedback/report_unsafe_site.html +++ b/chrome/browser/resources/feedback/report_unsafe_site.html
@@ -1,5 +1,5 @@ <!DOCTYPE HTML> -<html> +<html dir="$i18n{textdirection}"> <head> <title>$i18n{reportUnsafeSiteDialogTitle}</title> <meta charset="utf-8">
diff --git a/chrome/browser/resources/glic/selection_overlay/glic_selection_overlay.html.ts b/chrome/browser/resources/glic/selection_overlay/glic_selection_overlay.html.ts index ce2ede48..08c5caa 100644 --- a/chrome/browser/resources/glic/selection_overlay/glic_selection_overlay.html.ts +++ b/chrome/browser/resources/glic/selection_overlay/glic_selection_overlay.html.ts
@@ -31,6 +31,8 @@ <post-selection-renderer id="postSelectionRenderer" .selectionOverlayRect="${this.selectionOverlayRect}" .regionSelectedGlowEnabled="${this.enableRegionSelectedGlow}" + .activeRegionId="${this.activeRegionId}" + @activate-region="${this.onActivateRegion}" background-gradient-hidden> </post-selection-renderer> <region-selection id="regionSelectionLayer" .theme="${this.theme}"
diff --git a/chrome/browser/resources/glic/selection_overlay/glic_selection_overlay.ts b/chrome/browser/resources/glic/selection_overlay/glic_selection_overlay.ts index f2bf90d..9d375bb 100644 --- a/chrome/browser/resources/glic/selection_overlay/glic_selection_overlay.ts +++ b/chrome/browser/resources/glic/selection_overlay/glic_selection_overlay.ts
@@ -133,6 +133,9 @@ if (this.selectionElements.postSelectionRenderer.handleGestureStart( this.currentGesture)) { this.draggingRespondent = DragFeature.POST_SELECTION; + } else { + this.activeRegionId = ''; + this.selectionElements.postSelectionRenderer.clearSelection(); } } @@ -154,6 +157,8 @@ if (this.draggingRespondent === DragFeature.NONE) { this.setCursorToCrosshair(); this.draggingRespondent = DragFeature.MANUAL_REGION; + + this.activeRegionId = ''; this.selectionElements.postSelectionRenderer.clearSelection(); // TODO(crbug.com/421002691): follow the convention where the layer
diff --git a/chrome/browser/resources/lens/overlay/lens_overlay_app.ts b/chrome/browser/resources/lens/overlay/lens_overlay_app.ts index d677c024..59b05b7 100644 --- a/chrome/browser/resources/lens/overlay/lens_overlay_app.ts +++ b/chrome/browser/resources/lens/overlay/lens_overlay_app.ts
@@ -488,7 +488,7 @@ // Setup a listener on the suggestions container to change the shimmer when // the searchbox changes sizes or the selection overlay changes size. this.searchboxBoundingClientRectObserver.observe( - this.$.searchbox.getSuggestionsElement()); + this.$.searchbox.getDropdownElement()); this.searchboxBoundingClientRectObserver.observe(this.$.selectionOverlay); } @@ -512,11 +512,11 @@ this.focusShimmerOnSearchbox(); this.searchboxSuggestionCount = - this.$.searchbox.getSuggestionsElement().selectableMatchElements.length; + this.$.searchbox.getDropdownElement().selectableMatchElements.length; } private focusShimmerOnSearchbox() { - const suggestionsContainer = this.$.searchbox.getSuggestionsElement(); + const suggestionsContainer = this.$.searchbox.getDropdownElement(); const areSuggestionsShowing = suggestionsContainer.offsetWidth * suggestionsContainer.offsetHeight > 0;
diff --git a/chrome/browser/resources/lens/overlay/post_selection_renderer.html b/chrome/browser/resources/lens/overlay/post_selection_renderer.html index 9d917a3..180dd00c 100644 --- a/chrome/browser/resources/lens/overlay/post_selection_renderer.html +++ b/chrome/browser/resources/lens/overlay/post_selection_renderer.html
@@ -160,8 +160,50 @@ position: absolute; opacity: 0; } + + .static-region { + position: absolute; + /* Uses the exact same Houdini paint worklet as the active Lens region. + This ensures the borders and corner handles look visually identical. */ + background-image: paint(post-selection); + forced-color-adjust: none; + /* Enable pointer events so the user can click this static box to + re-activate it. */ + pointer-events: auto; + z-index: 5; + cursor: pointer; + } + + .static-region-cutout { + position: absolute; + /* It covers the entire overlay area. */ + inset: 0; + height: 100%; + width: 100%; + z-index: 2; + pointer-events: none; + object-fit: contain; + } </style> <div id="postSelectionScrim" style$="[[getScrimStyleProperties(height, width)]]"></div> +<template is="dom-if" if="[[multiRegionSelectionEnabled]]"> + <template is="dom-repeat" items="[[staticRegions]]"> + <canvas + class="static-region-cutout" + data-id$="[[item.id]]" + height="[[canvasPhysicalHeight]]" + width="[[canvasPhysicalWidth]]" + style$="clip-path: [[item.clipPath]]; height: [[canvasHeight]]px; + width: [[canvasWidth]]px;"> + </canvas> + <div class="static-region" + data-id$="[[item.id]]" + on-pointerdown="onStaticRegionPointerdown" + style$="left: [[item.left]]; top: [[item.top]]; + width: [[item.width]]; height: [[item.height]];"> + </div> + </template> +</template> <div hidden$="[[!hasSelection(height, width)]]"> <canvas id="backgroundImageCanvas"
diff --git a/chrome/browser/resources/lens/overlay/post_selection_renderer.ts b/chrome/browser/resources/lens/overlay/post_selection_renderer.ts index 0bcf027..f68a9ed 100644 --- a/chrome/browser/resources/lens/overlay/post_selection_renderer.ts +++ b/chrome/browser/resources/lens/overlay/post_selection_renderer.ts
@@ -16,6 +16,7 @@ import {ScreenshotBitmapBrowserProxyImpl} from './screenshot_bitmap_browser_proxy.js'; import {renderScreenshot} from './screenshot_utils.js'; import {RegionSource, SelectionOverlayBaseHandler} from './selection_overlay_base_handler.js'; +import type {SelectedRegion} from './selection_overlay_base_handler.js'; import {focusShimmerOnRegion, ShimmerControlRequester, unfocusShimmer} from './selection_utils.js'; import type {GestureEvent} from './selection_utils.js'; import {toPercent, toPixels} from './values_converter.js'; @@ -29,6 +30,15 @@ height: number; } +export interface StaticRegion { + id: string; + left: string; + top: string; + width: string; + height: string; + clipPath: string; +} + // The target currently being dragged on by the user. enum DragTarget { NONE, @@ -115,10 +125,22 @@ type: Array, value: () => ['topLeft', 'topRight', 'bottomRight', 'bottomLeft'], }, - canvasHeight: Number, - canvasWidth: Number, - canvasPhysicalHeight: Number, - canvasPhysicalWidth: Number, + canvasHeight: { + type: Number, + reflectToAttribute: true, + }, + canvasWidth: { + type: Number, + reflectToAttribute: true, + }, + canvasPhysicalHeight: { + type: Number, + reflectToAttribute: true, + }, + canvasPhysicalWidth: { + type: Number, + reflectToAttribute: true, + }, regionSelectedGlowEnabled: { type: Boolean, reflectToAttribute: true, @@ -140,9 +162,34 @@ reflectToAttribute: true, value: false, }, + multiRegionSelectionEnabled: { + type: Boolean, + value: () => loadTimeData.getBoolean('enableMultiRegionSelection'), + reflectToAttribute: true, + }, + staticRegions: { + type: Array, + value: () => [], + }, + activeRegionId: { + type: String, + value: '', + reflectToAttribute: true, + }, + selectedRegions: { + type: Array, + value: () => [], + }, }; } + static get observers() { + return [ + 'calculateStaticRegions(' + + 'selectedRegions.*, activeRegionId, multiRegionSelectionEnabled)', + ]; + } + private eventTracker_: EventTracker = new EventTracker(); // The bounds of the current selection declare private top: number; @@ -164,7 +211,13 @@ declare private selectionOverlayRect: DOMRect; // Whether the background gradient should be hidden. declare private backgroundGradientHidden: boolean; + declare private multiRegionSelectionEnabled: boolean; + declare private staticRegions: StaticRegion[]; + declare private activeRegionId: string; + declare private selectedRegions: SelectedRegion[]; + private currentScreenshot: ImageBitmap|null = null; + private renderedCanvasElements_: Set<HTMLCanvasElement> = new Set(); private context: CanvasRenderingContext2D; // Listener IDs for events tracked from the browser. private listenerIds: number[]; @@ -179,7 +232,7 @@ private newBoxAnimation: Animation|null = null; private animateOnResize = false; // Whether to darken the post selection scrim. - declare private shouldDarkenScrim; + declare private shouldDarkenScrim: boolean; // Whether to enable corner sliders for keyboard control. declare private cornerSlidersEnabled: boolean; // Timeout for calling handleGestureEnd() after a slider change. @@ -192,11 +245,22 @@ super.connectedCallback(); ScreenshotBitmapBrowserProxyImpl.getInstance().fetchScreenshot( (screenshot: ImageBitmap) => { - renderScreenshot(this.$.backgroundImageCanvas, screenshot); + this.currentScreenshot = screenshot; + // renderScreenshot detaches the bitmap, so we create a copy to keep + // the original alive for the static region canvases. + createImageBitmap(screenshot).then(bmp => { + renderScreenshot(this.$.backgroundImageCanvas, bmp); + }); + this.renderStaticRegionCanvases(); }); ScreenshotBitmapBrowserProxyImpl.getInstance().addOnOverlayReshownListener( (screenshot: ImageBitmap) => { - renderScreenshot(this.$.backgroundImageCanvas, screenshot); + this.currentScreenshot = screenshot; + this.renderedCanvasElements_.clear(); + createImageBitmap(screenshot).then(bmp => { + renderScreenshot(this.$.backgroundImageCanvas, bmp); + }); + this.renderStaticRegionCanvases(); }); this.eventTracker_.add( document, 'render-post-selection', @@ -227,6 +291,8 @@ this.clearRegionSelection.bind(this)), this.baseHandler.addSetPostRegionSelectionListener( this.setSelection.bind(this)), + this.baseHandler.addMultiRegionSelectionListener( + this.onMultiRegionSelectionUpdated.bind(this)), ]; } @@ -234,10 +300,103 @@ super.disconnectedCallback(); this.eventTracker_.removeAll(); this.resizeObserver.unobserve(this); - this.listenerIds.forEach(id => assert(this.baseHandler.removeListener(id))); + this.listenerIds.forEach(id => { + if (id !== -1) { + this.baseHandler.removeListener(id); + } + }); this.listenerIds = []; } + private onStaticRegionPointerdown(event: PointerEvent) { + const target = event.target as HTMLElement; + const id = target.dataset['id']; + if (id) { + this.dispatchEvent(new CustomEvent( + 'activate-region', {bubbles: true, composed: true, detail: {id}})); + event.stopPropagation(); + } + } + + private onMultiRegionSelectionUpdated(regions: SelectedRegion[]) { + this.selectedRegions = regions; + this.calculateStaticRegions(); + } + + private calculateStaticRegions() { + if (!this.multiRegionSelectionEnabled) { + this.staticRegions = []; + return; + } + + this.staticRegions = + this.selectedRegions.filter(r => r.id !== this.activeRegionId) + .map(r => this.selectedRegionToStaticRegion(r)); + + this.updateCornerDimensions(); + // Ensure canvases are rendered for the new regions. We use + // requestAnimationFrame to allow the dom-repeat to stamp the new canvases + // before we try to draw to them. + requestAnimationFrame(() => { + this.renderStaticRegionCanvases(); + }); + } + + private selectedRegionToStaticRegion(region: SelectedRegion): StaticRegion { + const widthPercent = region.region.width * 100; + const heightPercent = region.region.height * 100; + const leftPercent = (region.region.x - region.region.width / 2) * 100; + const topPercent = (region.region.y - region.region.height / 2) * 100; + + const rightOffset = 100 - (leftPercent + widthPercent); + const bottomOffset = 100 - (topPercent + heightPercent); + + const cornerWidth = 'var(--post-selection-corner-width)'; + const cornerRadius = 'var(--post-selection-cutout-corner-radius, 8px)'; + + return { + id: region.id, + left: `calc(${leftPercent}% - ${cornerWidth})`, + top: `calc(${topPercent}% - ${cornerWidth})`, + width: `calc(${widthPercent}% + (2 * ${cornerWidth}))`, + height: `calc(${heightPercent}% + (2 * ${cornerWidth}))`, + clipPath: `inset(${topPercent}% ${rightOffset}% ${bottomOffset}% ${ + leftPercent}% round ${cornerRadius})`, + }; + } + + private renderStaticRegionCanvases() { + if (!this.multiRegionSelectionEnabled || !this.currentScreenshot) { + return; + } + + const canvases = this.shadowRoot!.querySelectorAll<HTMLCanvasElement>( + '.static-region-cutout'); + + // Prune any canvases that were removed from the DOM to prevent memory + // leaks. + const currentCanvasSet = new Set(canvases); + for (const canvas of this.renderedCanvasElements_) { + if (!currentCanvasSet.has(canvas)) { + this.renderedCanvasElements_.delete(canvas); + } + } + + for (const canvas of canvases) { + if (!this.renderedCanvasElements_.has(canvas)) { + // Draw synchronously using a 2D context to avoid flickering and bitmap + // detachment. + canvas.width = this.currentScreenshot.width; + canvas.height = this.currentScreenshot.height; + const ctx = canvas.getContext('2d'); + if (ctx) { + ctx.drawImage(this.currentScreenshot, 0, 0); + this.renderedCanvasElements_.add(canvas); + } + } + } + } + setCanvasSizeTo(width: number, height: number) { // Resetting the canvas width and height also clears the canvas. this.canvasWidth = width;
diff --git a/chrome/browser/resources/lens/overlay/side_panel/side_panel_app.html b/chrome/browser/resources/lens/overlay/side_panel/side_panel_app.html index 6e383fa7..4bbd978 100644 --- a/chrome/browser/resources/lens/overlay/side_panel/side_panel_app.html +++ b/chrome/browser/resources/lens/overlay/side_panel/side_panel_app.html
@@ -431,6 +431,10 @@ pointer-events: none; } + #composebox::part(context-menu-and-tools) { + min-height: var(--cr-icon-button-size); + } + #composeboxFooter { height: 0px; transition: height var(--emphasized-curve); @@ -452,6 +456,7 @@ #composebox::part(input) { color: var(--color-composebox-font); + min-height: 48px; padding-inline-start: var(--text-input-left-spacing); }
diff --git a/chrome/browser/resources/lens/overlay/side_panel/side_panel_app.ts b/chrome/browser/resources/lens/overlay/side_panel/side_panel_app.ts index c2923d8b..11587955 100644 --- a/chrome/browser/resources/lens/overlay/side_panel/side_panel_app.ts +++ b/chrome/browser/resources/lens/overlay/side_panel/side_panel_app.ts
@@ -617,7 +617,7 @@ // Setup a listener on the suggestions container to adjust the ghost loader // number of suggestions. this.searchboxBoundingClientRectObserver.observe( - this.$.searchbox.getSuggestionsElement()); + this.$.searchbox.getDropdownElement()); } private onSearchboxFocusOut_(event: FocusEvent) { @@ -641,7 +641,7 @@ private onSearchboxBoundsChanged() { this.searchboxSuggestionCount = - this.$.searchbox.getSuggestionsElement().selectableMatchElements.length; + this.$.searchbox.getDropdownElement().selectableMatchElements.length; } private computeShowGhostLoader(): boolean {
diff --git a/chrome/browser/resources/omnibox_popup/aim_app.html.ts b/chrome/browser/resources/omnibox_popup/aim_app.html.ts index 5ba8850..0e4222a 100644 --- a/chrome/browser/resources/omnibox_popup/aim_app.html.ts +++ b/chrome/browser/resources/omnibox_popup/aim_app.html.ts
@@ -14,7 +14,7 @@ searchbox-layout-mode="${this.searchboxLayoutMode_}" ?disable-caret-color-animation="${!this.caretAnimationsEnabled_}" ?disable-composebox-animation="${this.disableComposeboxAnimation_}" - ?disable-voice-search-animation="${true}" + disable-voice-search-animation @context-menu-entrypoint-click="${this.onContextMenuEntrypointClick_}" @close-composebox="${this.onCloseComposebox_}" @composebox-submit="${this.onComposeboxSubmit_}"
diff --git a/chrome/browser/resources/settings/system_page/system_page.html b/chrome/browser/resources/settings/system_page/system_page.html index ba2e1af7..1f752f6cd 100644 --- a/chrome/browser/resources/settings/system_page/system_page.html +++ b/chrome/browser/resources/settings/system_page/system_page.html
@@ -27,6 +27,22 @@ </cr-button> </template> </settings-toggle-button> + <!-- <if expr="is_win"> --> + <template is="dom-if" if="[[showProcessIsolationSetting_]]" restamp> + <settings-toggle-button id="isolationState" + pref="{{prefs.isolation_state.enabled}}" + label="$i18n{isolationStateLabel}" + sub-label="$i18n{isolationStateSubLabel}" + learn-more-url="$i18n{isolationStateLearnMoreUrl}"> + <template is="dom-if" if="[[shouldShowIsolationRestart_( + prefs.isolation_state.enabled.value)]]"> + <cr-button on-click="onRestartClick_" slot="more-actions"> + $i18n{restart} + </cr-button> + </template> + </settings-toggle-button> + </template> + <!-- </if> --> <if expr="_google_chrome"> <!-- On device AI settings --> <template is="dom-if" if="[[showOnDeviceAiSettings_]]" restamp>
diff --git a/chrome/browser/resources/settings/system_page/system_page.ts b/chrome/browser/resources/settings/system_page/system_page.ts index 7158d5da..e8fc73c 100644 --- a/chrome/browser/resources/settings/system_page/system_page.ts +++ b/chrome/browser/resources/settings/system_page/system_page.ts
@@ -105,6 +105,15 @@ }, }, // </if> + // <if expr="is_win"> + showProcessIsolationSetting_: { + readOnly: true, + type: Boolean, + value() { + return loadTimeData.getBoolean('showProcessIsolationSetting'); + }, + }, + // </if> }; } @@ -127,6 +136,10 @@ // <if expr="_google_chrome and is_win"> declare private showFeatureNotificationsSetting_: boolean; // </if> + // <if expr="is_win"> + declare private showProcessIsolationSetting_: boolean; + private processIsolationEnabledAtStartup_: boolean = false; + // </if> // <if expr="_google_chrome"> override ready() { @@ -138,6 +151,14 @@ } // </if> + // <if expr="is_win"> + override connectedCallback() { + super.connectedCallback(); + this.processIsolationEnabledAtStartup_ = + this.getPref('isolation_state.enabled').value; + } + // </if> + private observeProxyPrefChanged_() { const pref = this.getPref('proxy'); // TODO(dbeam): do types of policy other than USER apply on ChromeOS? @@ -241,6 +262,13 @@ return enabled !== proxy.wasHardwareAccelerationEnabledAtStartup(); } + // <if expr="is_win"> + private shouldShowIsolationRestart_(): boolean { + return this.getPref('isolation_state.enabled').value !== + this.processIsolationEnabledAtStartup_; + } + // </if> + // <if expr="_google_chrome and is_win"> private onFeatureNotificationsChange_(e: Event) { const enabled = (e.target as SettingsToggleButtonElement).checked;
diff --git a/chrome/browser/resources/side_panel/bookmarks/power_bookmark_row.html.ts b/chrome/browser/resources/side_panel/bookmarks/power_bookmark_row.html.ts index fe42af3..e3a8d5c9 100644 --- a/chrome/browser/resources/side_panel/bookmarks/power_bookmark_row.html.ts +++ b/chrome/browser/resources/side_panel/bookmarks/power_bookmark_row.html.ts
@@ -57,7 +57,7 @@ .activeFolderPath="${this.activeFolderPath}" .contextMenuBookmark="${this.contextMenuBookmark}" .activeSortIndex="${this.activeSortIndex}" - ?has-folders="${true}"> + has-folders> </power-bookmark-row> `)} `: ''}
diff --git a/chrome/browser/resources/side_panel/read_anything/app/read_anything.d.ts b/chrome/browser/resources/side_panel/read_anything/app/read_anything.d.ts index 12e8ca6e..9933557e 100644 --- a/chrome/browser/resources/side_panel/read_anything/app/read_anything.d.ts +++ b/chrome/browser/resources/side_panel/read_anything/app/read_anything.d.ts
@@ -382,6 +382,9 @@ // Called by the Read Anything app to close the Read Anything UI. function close(): void; + // Called when the speech engine stalls. + function onSpeechEngineStalled(): void; + // Called by the ReadAnything app to toggle the pin state. function togglePinState(): void;
diff --git a/chrome/browser/resources/side_panel/read_anything/content/content_controller.ts b/chrome/browser/resources/side_panel/read_anything/content/content_controller.ts index 98dfc73..2a6025b6 100644 --- a/chrome/browser/resources/side_panel/read_anything/content/content_controller.ts +++ b/chrome/browser/resources/side_panel/read_anything/content/content_controller.ts
@@ -274,11 +274,23 @@ } } - // Set before updateImages to avoid early return. + // Process images from distillation. If images are disabled or there is + // no text content, images shouldn't be considered "content" and the + // empty state page should be shown. If there is a valid selection, then + // the images may be shown. + // TODO: crbug.com/483140075- Right now, selection with Readability does + // not work, so selected images will not be distilled. + const hasImages = this.updateImagesForReadability_(contentContainer); + const hasImagesAsContent = chrome.readingMode.imagesEnabled && + chrome.readingMode.hasValidSelection && hasImages; + + if (!contentContainer.textContent && !hasImagesAsContent) { + this.setEmpty(); + return null; + } + this.setState(ContentType.HAS_CONTENT); - // Process images from distillation. - this.updateImages(contentContainer); contentFragment.appendChild(contentContainer); // Ensure link visibility is updated with user preferences. @@ -309,7 +321,13 @@ const node = this.buildSubtree_(rootId); // If there is no text or images in the tree, do not proceed. The empty // state container will show instead. - if (!node.textContent && !this.nodeStore_.hasImagesToFetch()) { + // We should only consider images as content when determining whether or + // not to show the empty state page if they are enabled and if + // the user specifically selected the content. + const hasImagesAsContent = chrome.readingMode.imagesEnabled && + chrome.readingMode.hasValidSelection && + this.nodeStore_.hasImagesToFetch(); + if (!node.textContent && !hasImagesAsContent) { // Sometimes the controller thinks there will be content and redraws // without showing the empty page, but we end up not actually having any // content and also not showing the empty page sometimes. In this case,
diff --git a/chrome/browser/resources/side_panel/read_anything/content/selection_controller.ts b/chrome/browser/resources/side_panel/read_anything/content/selection_controller.ts index 0f9b94fd..0ab5724 100644 --- a/chrome/browser/resources/side_panel/read_anything/content/selection_controller.ts +++ b/chrome/browser/resources/side_panel/read_anything/content/selection_controller.ts
@@ -39,10 +39,14 @@ } getCurrentSelectionStart(): SelectionEndpoint { - const anchorNodeId = chrome.readingMode.startNodeId; - const anchorOffset = chrome.readingMode.startOffset; - const focusNodeId = chrome.readingMode.endNodeId; - const focusOffset = chrome.readingMode.endOffset; + const selection = this.currentSelection_; + if (!selection || !selection.anchorNode || !selection.focusNode) { + return {nodeId: 0, offset: -1}; + } + const {anchorNodeId, anchorOffset, focusNodeId, focusOffset} = + this.getSelectionIds_( + selection.anchorNode, selection.anchorOffset, selection.focusNode, + selection.focusOffset); // If only one of the ids is present, use that one. let startingNodeId: number|undefined = @@ -50,10 +54,9 @@ let startingOffset = anchorNodeId ? anchorOffset : focusOffset; // If both are present, start with the node that is sooner in the page. if (anchorNodeId && focusNodeId) { - const selection = this.currentSelection_; if (anchorNodeId === focusNodeId) { startingOffset = Math.min(anchorOffset, focusOffset); - } else if (selection && selection.anchorNode && selection.focusNode) { + } else { const pos = selection.anchorNode.compareDocumentPosition(selection.focusNode); const focusIsFirst = pos === Node.DOCUMENT_POSITION_PRECEDING;
diff --git a/chrome/browser/resources/side_panel/read_anything/read_aloud/speech_controller.ts b/chrome/browser/resources/side_panel/read_anything/read_aloud/speech_controller.ts index e8f5c04..66ba3a0b 100644 --- a/chrome/browser/resources/side_panel/read_anything/read_aloud/speech_controller.ts +++ b/chrome/browser/resources/side_panel/read_anything/read_aloud/speech_controller.ts
@@ -1024,9 +1024,12 @@ // <if expr="not is_chromeos"> this.engineTimeoutId_ = setTimeout(() => { if (this.model_.getEngineState() === SpeechEngineState.LOADING) { - // TODO: crbug.com/490113040- When the engine stalls, uninstall and - // reinstall the engine. this.logger_.logSpeechError('timeout-engine-stalled'); + // TODO: crbug.com/465479425- Stop speech to make it a little bit + // easier to resume speech when the new engine is hopefully + // successfully reinstalled. + chrome.readingMode.onSpeechEngineStalled(); + this.voiceLanguageController_.onVoicesChanged(); } }, ENGINE_TIMEOUT_THRESHOLD_MS); // </if>
diff --git a/chrome/browser/resources/signin/BUILD.gn b/chrome/browser/resources/signin/BUILD.gn index cba47f7..c7e9638 100644 --- a/chrome/browser/resources/signin/BUILD.gn +++ b/chrome/browser/resources/signin/BUILD.gn
@@ -39,6 +39,7 @@ if (!is_chromeos) { static_files += [ "managed_user_profile_notice/managed_user_profile_notice.html", + "managed_user_profile_notice/managed_user_profile_notice_refresh.html", "profile_customization/profile_customization.html", "signin_email_confirmation/signin_email_confirmation.html", "signin_error/signin_error.html", @@ -65,11 +66,15 @@ ts_files += [ "managed_user_profile_notice/managed_user_profile_notice_app.html.ts", "managed_user_profile_notice/managed_user_profile_notice_app.ts", + "managed_user_profile_notice/managed_user_profile_notice_app_refresh.html.ts", + "managed_user_profile_notice/managed_user_profile_notice_app_refresh.ts", "managed_user_profile_notice/managed_user_profile_notice_browser_proxy.ts", "managed_user_profile_notice/managed_user_profile_notice_data_handling.html.ts", "managed_user_profile_notice/managed_user_profile_notice_data_handling.ts", "managed_user_profile_notice/managed_user_profile_notice_disclosure.html.ts", "managed_user_profile_notice/managed_user_profile_notice_disclosure.ts", + "managed_user_profile_notice/managed_user_profile_notice_disclosure_refresh.html.ts", + "managed_user_profile_notice/managed_user_profile_notice_disclosure_refresh.ts", "managed_user_profile_notice/managed_user_profile_notice_state.html.ts", "managed_user_profile_notice/managed_user_profile_notice_state.ts", "managed_user_profile_notice/managed_user_profile_notice_value_prop.html.ts", @@ -107,8 +112,10 @@ if (!is_chromeos) { css_files += [ "managed_user_profile_notice/managed_user_profile_notice_app.css", + "managed_user_profile_notice/managed_user_profile_notice_app_refresh.css", "managed_user_profile_notice/managed_user_profile_notice_data_handling.css", "managed_user_profile_notice/managed_user_profile_notice_disclosure.css", + "managed_user_profile_notice/managed_user_profile_notice_disclosure_refresh.css", "managed_user_profile_notice/managed_user_profile_notice_state.css", "managed_user_profile_notice/managed_user_profile_notice_value_prop.css", "profile_customization/profile_customization_app.css",
diff --git a/chrome/browser/resources/signin/managed_user_profile_notice/managed_user_profile_notice_app_refresh.css b/chrome/browser/resources/signin/managed_user_profile_notice/managed_user_profile_notice_app_refresh.css new file mode 100644 index 0000000..b8547d9 --- /dev/null +++ b/chrome/browser/resources/signin/managed_user_profile_notice/managed_user_profile_notice_app_refresh.css
@@ -0,0 +1,86 @@ +/* Copyright 2026 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://resources/cr_elements/cr_shared_vars.css.js + * #import=chrome://resources/cr_elements/cr_spinner_style_lit.css.js + * #import=/signin_shared.css.js + * #import=/signin_vars.css.js + * #scheme=relative + * #include=signin-shared cr-spinner-style-lit + * #css_wrapper_metadata_end */ + +:host { + color: var(--cr-primary-text-color); + display: flex; + flex-direction: column; + gap: 48px; + height: 100vh; + width: 100vw; + justify-content: center; + min-height: 560px; + min-width: 600px; +} + +.main-container { + box-sizing: border-box; + display: flex; + flex-direction: column; + overflow: hidden; + padding-inline: 16px; + width: 100%; +} + +.action-container { + align-items: center; + justify-content: center; + padding: 0; +} + +#cancelButton { + font-weight: normal; +} + +.tangible-button { + min-width: 133px; +} + +.success-icon, +.timeout-icon, +.error-icon { + height: 130px; + width: 180px; +} + +.success-icon { + content: url(images/enrollment_success.svg); +} + +.timeout-icon { + content: url(images/enrollment_timeout.svg); +} + +.error-icon { + content: url(images/enrollment_failure.svg); +} + +@media (prefers-color-scheme: dark) { + .success-icon { + content: url(images/enrollment_success_dark.svg); + } + + .timeout-icon { + content: url(images/enrollment_timeout_dark.svg); + } + + .error-icon { + content: url(images/enrollment_failure_dark.svg); + } +} + +.spinner { + --cr-spinner-size: 60px; + display: inline-block; +}
diff --git a/chrome/browser/resources/signin/managed_user_profile_notice/managed_user_profile_notice_app_refresh.html.ts b/chrome/browser/resources/signin/managed_user_profile_notice/managed_user_profile_notice_app_refresh.html.ts new file mode 100644 index 0000000..d923d4b --- /dev/null +++ b/chrome/browser/resources/signin/managed_user_profile_notice/managed_user_profile_notice_app_refresh.html.ts
@@ -0,0 +1,86 @@ +// Copyright 2026 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 {State} from './managed_user_profile_notice_browser_proxy.js'; +import type {ManagedUserProfileNoticeAppRefreshElement} from './managed_user_profile_notice_app_refresh.js'; + +export function getHtml(this: ManagedUserProfileNoticeAppRefreshElement) { + // clang-format off + return html`<!--_html_template_start_--> +<div class="main-container"> + ${this.isState_(State.VALUE_PROPOSITION) ? html` + <managed-user-profile-notice-value-prop id="value-prop" + title="${this.i18n('valuePropTitle')}" + subtitle="${this.i18n('valuePropSubtitle')}" + picture-url="${this.profileInfo_.pictureUrl}" + email="${this.profileInfo_.email}" + account-name="${this.profileInfo_.accountName}" + ?show-enterprise-badge="${this.profileInfo_.showEnterpriseBadge}"> + </managed-user-profile-notice-value-prop> + ` : ''} + ${this.isState_(State.DISCLOSURE) ? html` + <managed-user-profile-notice-disclosure-refresh id="disclosure" + title="${this.i18n('profileDisclosureTitle')}" + subtitle="${this.i18n('profileDisclosureSubtitle')}" + picture-url="${this.profileInfo_.pictureUrl}" + ?show-enterprise-badge="${this.profileInfo_.showEnterpriseBadge}"> + </managed-user-profile-notice-disclosure-refresh> + ` : ''} + ${this.isState_(State.PROCESSING) ? html` + <managed-user-profile-notice-state id="processing" + subtitle="${this.processingSubtitle_}" icon="cr:domain"> + <div class="spinner"></div> + </managed-user-profile-notice-state> + ` : ''} + ${this.isState_(State.SUCCESS) ? html` + <managed-user-profile-notice-state id="success" icon="cr:domain" + title="$i18n{successTitle}" subtitle="$i18n{successSubtitle}"> + <img class="success-icon" alt=""> + </managed-user-profile-notice-state> + ` : ''} + ${this.isState_(State.TIMEOUT) ? html` + <managed-user-profile-notice-state id="timeout" icon="cr:domain" + title="$i18n{timeoutTitle}" subtitle="$i18n{timeoutSubtitle}"> + <img class="timeout-icon" alt=""> + </managed-user-profile-notice-state> + ` : ''} + ${this.isState_(State.ERROR) ? html` + <managed-user-profile-notice-state id="error" icon="cr:domain" + title="${this.errorTitle_}" subtitle="${this.errorSubtitle_}"> + <img class="error-icon" alt=""> + </managed-user-profile-notice-state> + ` : ''} + ${this.isState_(State.USER_DATA_HANDLING) ? html` + <managed-user-profile-notice-data-handling id="user-data-handling" + title="${this.i18n('separateBrowsingDataTitle')}" + separate-data-choice-title="${this.i18n('separateBrowsingDataChoiceTitle')}" + separate-data-choice-details="${this.i18n('separateBrowsingDataChoiceDetails')}" + merge-data-choice-title="${this.i18n('mergeBrowsingDataChoiceTitle')}" + merge-data-choice-details="${this.i18n('mergeBrowsingDataChoiceDetails')}" + .selectedDataHandling="${this.selectedDataHandling_}" + @selected-data-handling-changed="${this.onSelectedDataHandlingChanged_}"> + </managed-user-profile-notice-data-handling> + ` : ''} +</div> +<div class="action-container"> + <cr-button id="proceedButton" + aria-label="${this.proceedLabel_}" + class="action-button tangible-button" + @click="${this.onProceedButtonClick_}" + ?disabled="${this.shouldDisableProceedButton_()}" + ?hidden="${this.isState_(State.PROCESSING)}"> + ${this.proceedLabel_} + </cr-button> + <cr-button id="cancelButton" + aria-label="${this.getCancelLabel_()}" + class="tangible-button ${this.getCancelButtonClass_()}" + @click="${this.onCancelButtonClick_}" + ?hidden="${!this.allowCancel_()}"> + ${this.getCancelLabel_()} + </cr-button> +</div> +<!--_html_template_end_-->`; + // clang-format on +}
diff --git a/chrome/browser/resources/signin/managed_user_profile_notice/managed_user_profile_notice_app_refresh.ts b/chrome/browser/resources/signin/managed_user_profile_notice/managed_user_profile_notice_app_refresh.ts new file mode 100644 index 0000000..a95dc89 --- /dev/null +++ b/chrome/browser/resources/signin/managed_user_profile_notice/managed_user_profile_notice_app_refresh.ts
@@ -0,0 +1,267 @@ +// Copyright 2026 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 '/icons.html.js'; +import 'chrome://resources/cr_elements/cr_button/cr_button.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; +import './managed_user_profile_notice_disclosure_refresh.js'; +import './managed_user_profile_notice_value_prop.js'; +import './managed_user_profile_notice_state.js'; +import './managed_user_profile_notice_data_handling.js'; + +import type {CrButtonElement} from 'chrome://resources/cr_elements/cr_button/cr_button.js'; +import {I18nMixinLit} from 'chrome://resources/cr_elements/i18n_mixin_lit.js'; +import {WebUiListenerMixinLit} from 'chrome://resources/cr_elements/web_ui_listener_mixin_lit.js'; +import {assertNotReachedCase} from 'chrome://resources/js/assert.js'; +import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; +import {CrLitElement} from 'chrome://resources/lit/v3_0/lit.rollup.js'; +import type {PropertyValues} from 'chrome://resources/lit/v3_0/lit.rollup.js'; + +import {getCss} from './managed_user_profile_notice_app_refresh.css.js'; +import {getHtml} from './managed_user_profile_notice_app_refresh.html.js'; +import type {ManagedUserProfileInfo, ManagedUserProfileNoticeBrowserProxy} from './managed_user_profile_notice_browser_proxy.js'; +import {BrowsingDataHandling, ManagedUserProfileNoticeBrowserProxyImpl, State} from './managed_user_profile_notice_browser_proxy.js'; + +export interface ManagedUserProfileNoticeAppRefreshElement { + $: { + proceedButton: CrButtonElement, + cancelButton: CrButtonElement, + }; +} + +const ManagedUserProfileNoticeAppRefreshElementBase = + WebUiListenerMixinLit(I18nMixinLit(CrLitElement)); + +export class ManagedUserProfileNoticeAppRefreshElement extends + ManagedUserProfileNoticeAppRefreshElementBase { + static get is() { + return 'managed-user-profile-notice-app-refresh'; + } + + static override get styles() { + return getCss(); + } + + override render() { + return getHtml.bind(this)(); + } + + static override get properties() { + return { + profileInfo_: {type: Object}, + + /** + * Whether this page is being shown as a dialog. + * + * Reflected as an attribute to allow configuring variables and styles at + * the element host level. + */ + isModalDialog_: { + type: Boolean, + reflect: true, + }, + + proceedLabel_: {type: String}, + + errorTitle_: {type: String}, + errorSubtitle_: {type: String}, + + disableProceedButton_: {type: Boolean}, + currentState_: {type: Number}, + processingSubtitle_: {type: String}, + selectedDataHandling_: {type: String}, + usePrimaryAndTonalButtons_: {type: Boolean}, + }; + } + + protected accessor profileInfo_: ManagedUserProfileInfo = { + accountName: '', + continueAs: '', + email: '', + pictureUrl: '', + showEnterpriseBadge: false, + title: '', + subtitle: '', + proceedLabel: '', + checkLinkDataCheckboxByDefault: false, + }; + + protected accessor isModalDialog_: boolean = + loadTimeData.getBoolean('isModalDialog'); + protected accessor proceedLabel_: string = ''; + protected accessor errorTitle_: string = ''; + protected accessor errorSubtitle_: string = ''; + protected accessor disableProceedButton_: boolean = false; + protected accessor currentState_: State = State.DISCLOSURE; + protected accessor processingSubtitle_: string = + loadTimeData.getString('processingSubtitle'); + protected accessor selectedDataHandling_: BrowsingDataHandling|null = null; + private accessor usePrimaryAndTonalButtons_: boolean = + loadTimeData.getBoolean('usePrimaryAndTonalButtonsForPromos'); + + private managedUserProfileNoticeBrowserProxy_: + ManagedUserProfileNoticeBrowserProxy = + ManagedUserProfileNoticeBrowserProxyImpl.getInstance(); + + override connectedCallback() { + super.connectedCallback(); + + this.addWebUiListener( + 'on-state-changed', (state: State) => this.updateCurrentState_(state)); + + this.addWebUiListener( + 'on-state-changed-to-error', + (errorTitle: string, errorSubTitle: string) => { + this.updateErrorStrings_(errorTitle, errorSubTitle); + this.updateCurrentState_(State.ERROR); + }); + + this.addWebUiListener( + 'on-profile-info-changed', + (info: ManagedUserProfileInfo) => this.updateProfileInfo_(info)); + + this.addWebUiListener( + 'on-long-processing', () => this.updateProcessingText_()); + + this.managedUserProfileNoticeBrowserProxy_.initialized().then(info => { + this.updateProfileInfo_(info); + this.updateCurrentState_(loadTimeData.getInteger('initialState')); + + // Prefer using |document.body.offsetHeight| instead of + // |document.body.scrollHeight| as it returns the correct height of the + // page even when the page zoom in Chrome is different than 100%. + this.managedUserProfileNoticeBrowserProxy_.initializedWithSize( + document.body.offsetHeight); + }); + } + + override willUpdate(changedProperties: PropertyValues<this>) { + super.willUpdate(changedProperties); + + const changedPrivateProperties = + changedProperties as Map<PropertyKey, unknown>; + + if (changedPrivateProperties.has('currentState_')) { + this.disableProceedButton_ = false; + } + + if (changedPrivateProperties.has('profileInfo_')) { + this.selectedDataHandling_ = + this.profileInfo_.checkLinkDataCheckboxByDefault ? + BrowsingDataHandling.MERGE : + BrowsingDataHandling.SEPARATE; + } + + if (changedPrivateProperties.has('currentState_') || + changedPrivateProperties.has('profileInfo_')) { + this.proceedLabel_ = this.computeProceedLabel_(); + } + } + + /** Called when the proceed button is clicked. */ + protected onProceedButtonClick_() { + this.disableProceedButton_ = true; + const linkData = this.selectedDataHandling_ === BrowsingDataHandling.MERGE; + this.managedUserProfileNoticeBrowserProxy_.proceed( + /*currentState=*/ this.currentState_, linkData); + } + + /** Called when the cancel button is clicked. */ + protected onCancelButtonClick_() { + if (this.allowValuePropStateBackFromDisclosure_()) { + this.updateCurrentState_(State.VALUE_PROPOSITION); + return; + } + this.managedUserProfileNoticeBrowserProxy_.cancel(); + } + + protected allowValuePropStateBackFromDisclosure_() { + return this.currentState_ === State.DISCLOSURE && + loadTimeData.getInteger('initialState') !== State.DISCLOSURE; + } + + private updateProfileInfo_(info: ManagedUserProfileInfo) { + this.profileInfo_ = info; + } + + private updateCurrentState_(state: State) { + this.currentState_ = state; + } + + private updateErrorStrings_(errorTitle: string, errorSubTitle: string) { + this.errorTitle_ = errorTitle; + this.errorSubtitle_ = errorSubTitle; + } + + protected allowCancel_(): boolean { + return this.isState_(State.DISCLOSURE) || + this.isState_(State.VALUE_PROPOSITION) || + this.isState_(State.USER_DATA_HANDLING) || + this.isState_(State.TIMEOUT) || this.isState_(State.PROCESSING); + } + + protected getCancelLabel_(): string { + if (this.isState_(State.VALUE_PROPOSITION) && + !loadTimeData.getBoolean('enforcedByPolicy')) { + return this.i18n('cancelValueProp'); + } + return this.i18n( + this.allowValuePropStateBackFromDisclosure_() ? 'backLabel' : + 'cancelLabel'); + } + + protected shouldDisableProceedButton_(): boolean { + return this.disableProceedButton_ || + (this.isState_(State.USER_DATA_HANDLING) && + !this.selectedDataHandling_); + } + + private computeProceedLabel_(): string { + switch (this.currentState_) { + case State.VALUE_PROPOSITION: + return this.profileInfo_.continueAs; + case State.DISCLOSURE: + case State.PROCESSING: + case State.SUCCESS: + return this.profileInfo_.proceedLabel || this.i18n('continueLabel'); + case State.USER_DATA_HANDLING: + return this.i18n('confirmLabel'); + case State.ERROR: + return this.i18n('closeLabel'); + case State.TIMEOUT: + return this.i18n('retryLabel'); + default: + assertNotReachedCase(this.currentState_); + } + } + + private updateProcessingText_() { + this.processingSubtitle_ = this.i18n('longProcessingSubtitle'); + } + + protected onSelectedDataHandlingChanged_( + e: CustomEvent<{value: BrowsingDataHandling}>) { + this.selectedDataHandling_ = e.detail.value; + } + + protected getCancelButtonClass_(): string { + return this.usePrimaryAndTonalButtons_ ? 'tonal-button' : ''; + } + + protected isState_(state: State): boolean { + return this.currentState_ === state; + } +} + +declare global { + interface HTMLElementTagNameMap { + 'managed-user-profile-notice-app-refresh': + ManagedUserProfileNoticeAppRefreshElement; + } +} + +customElements.define( + ManagedUserProfileNoticeAppRefreshElement.is, + ManagedUserProfileNoticeAppRefreshElement);
diff --git a/chrome/browser/resources/signin/managed_user_profile_notice/managed_user_profile_notice_disclosure_refresh.css b/chrome/browser/resources/signin/managed_user_profile_notice/managed_user_profile_notice_disclosure_refresh.css new file mode 100644 index 0000000..fc30e5a --- /dev/null +++ b/chrome/browser/resources/signin/managed_user_profile_notice/managed_user_profile_notice_disclosure_refresh.css
@@ -0,0 +1,177 @@ +/* Copyright 2026 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=/signin_shared.css.js + * #import=/signin_vars.css.js + * #scheme=relative + * #include=signin-shared + * #css_wrapper_metadata_end */ + +:host { + color: var(--cr-primary-text-color); + --cr-secondary-text-color: var(--google-grey-700); + --disclaimer-cards-gap: 24px; + --disclaimer-card-width: 300px; +} + +:host([is-oidc-dialog]) .title { + font-size: 24px; +} + +main { + display: flex; + flex-direction: column; + margin-inline: auto; +} + +#headerContainer { + padding-bottom: 24px; + position: relative; + width: 100%; +} + +#avatarContainer { + height: 92px; + margin-inline: auto; + position: relative; + width: 92px; + z-index: 1; +} + +#avatar { + border-radius: 50%; + display: block; + height: 100%; + width: 100%; +} + +.work-badge { + align-items: center; + background-color: var(--signin-work-badge-background-color); + border: 1px solid var(--google-grey-300); + border-radius: 50%; + box-sizing: border-box; + display: flex; + height: 36px; + width: 36px; + justify-content: center; + position: absolute; + right: -4px; + bottom: -4px; +} + +.work-badge > cr-icon { + border-radius: 50%; + box-shadow: 0 1px 5px 0 rgba(0, 0, 0, 0.25); + height: 24px; + width: 24px; + padding: 6px; +} + +#textContainer { + text-align: center; + display: flex; + flex-direction: column; + gap: 8px; + margin-block-end: 24px; +} + +.title { + box-sizing: border-box; + font-size: 60px; + margin: 0; + padding-inline: 48px; + width: 100%; +} + +.subtitle { + align-self: center; + font-size: 16px; + font-weight: 500; + max-width: calc(var(--disclaimer-card-width) * 2 + var(--disclaimer-cards-gap)); + margin: 0; +} + +.title:focus { + outline: none; +} + +.disclaimer-container { + align-items: stretch; + display: flex; + flex-direction: row; + gap: var(--disclaimer-cards-gap); + justify-content: center; +} + +.disclaimer { + width: var(--disclaimer-card-width); + align-items: center; + background-color: var(--google-white); + border: 1px solid var(--google-grey-200); + border-radius: 24px; + box-sizing: border-box; + display: flex; + flex-direction: column; + gap: 8px; + padding: 24px; +} + +.disclaimer .icon { + flex-shrink: 0; + height: 36px; + width: 36px; +} + +.disclaimer h2 { + color: var(--cr-primary-text-color); + font-size: 16px; + font-weight: 500; + text-align: center; + margin: 0; +} + +.disclaimer p { + color: var(--cr-secondary-text-color); + line-height: 20px; + text-align: center; + margin: 0; +} + +@media screen and ((max-width: 780px) or (max-height: 600px)) { + #avatarContainer { + height: 64px; + width: 64px; + } + + .title { + font-size: 32px; + } + + .subtitle { + font-size: 15px; + } +} + +@media (prefers-color-scheme: dark) { + :host { + --cr-secondary-text-color: var(--google-grey-500); + } + + .work-badge { + border-color: var(--md-background-color); + } + + .work-badge > cr-icon { + box-shadow: 0 0 2px rgba(var(--google-grey-800-rgb), 0.12), + 0 0 6px rgba(var(--google-grey-800-rgb), 0.15); + } + + .disclaimer { + background-color: var(--cr-fallback-color-surface); + border: none; + } +}
diff --git a/chrome/browser/resources/signin/managed_user_profile_notice/managed_user_profile_notice_disclosure_refresh.html.ts b/chrome/browser/resources/signin/managed_user_profile_notice/managed_user_profile_notice_disclosure_refresh.html.ts new file mode 100644 index 0000000..60f9a39 --- /dev/null +++ b/chrome/browser/resources/signin/managed_user_profile_notice/managed_user_profile_notice_disclosure_refresh.html.ts
@@ -0,0 +1,42 @@ +// Copyright 2026 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 {ManagedUserProfileNoticeDisclosureRefreshElement} from './managed_user_profile_notice_disclosure_refresh.js'; + +export function getHtml(this: ManagedUserProfileNoticeDisclosureRefreshElement) { + return html`<!--_html_template_start_--> +<main> + <div id="headerContainer"> + <div id="avatarContainer"> + <img id="avatar" alt="$i18n{avatarAccessibilityLabel}" + src="${this.pictureUrl}"> + ${this.showEnterpriseBadge ? html` + <div class="work-badge"> + <cr-icon class="icon" icon="cr:domain" + aria-label="$i18n{enterpriseIconAccessibilityLabel}"> + </cr-icon> + </div> + ` : ''} + </div> + </div> + <div id="textContainer"> + <h1 id="title" class="title" tabindex="-1">${this.title}</h1> + <p id="subtitle" class="subtitle">${this.subtitle}</p> + </div> + <div class="disclaimer-container"> + <section class="disclaimer"> + <cr-icon class="icon" icon="signin:person-outline"></cr-icon> + <h2>$i18n{profileInformationTitle}</h2> + <p>$i18n{profileInformationDetails}</p> + </section> + <section class="disclaimer"> + <cr-icon class="icon" icon="cr:phonelink"></cr-icon> + <h2>$i18n{deviceInformationTitle}</h2> + <p>$i18n{deviceInformationDetails}</p> + </section> + </div> +</main> +<!--_html_template_end_-->`; +}
diff --git a/chrome/browser/resources/signin/managed_user_profile_notice/managed_user_profile_notice_disclosure_refresh.ts b/chrome/browser/resources/signin/managed_user_profile_notice/managed_user_profile_notice_disclosure_refresh.ts new file mode 100644 index 0000000..a711381 --- /dev/null +++ b/chrome/browser/resources/signin/managed_user_profile_notice/managed_user_profile_notice_disclosure_refresh.ts
@@ -0,0 +1,72 @@ +// Copyright 2026 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 'chrome://resources/cr_elements/cr_shared_vars.css.js'; +import 'chrome://resources/cr_elements/cr_icon/cr_icon.js'; +import 'chrome://resources/cr_elements/icons.html.js'; + +import {I18nMixinLit} from 'chrome://resources/cr_elements/i18n_mixin_lit.js'; +import {assert} from 'chrome://resources/js/assert.js'; +import {CrLitElement} from 'chrome://resources/lit/v3_0/lit.rollup.js'; + +import {getCss} from './managed_user_profile_notice_disclosure_refresh.css.js'; +import {getHtml} from './managed_user_profile_notice_disclosure_refresh.html.js'; + +export interface ManagedUserProfileNoticeDisclosureRefreshElement { + $: { + avatar: HTMLImageElement, + title: HTMLElement, + subtitle: HTMLElement, + }; +} + +const ManagedUserProfileNoticeDisclosureRefreshElementBase = + I18nMixinLit(CrLitElement); + +export class ManagedUserProfileNoticeDisclosureRefreshElement extends + ManagedUserProfileNoticeDisclosureRefreshElementBase { + static get is() { + return 'managed-user-profile-notice-disclosure-refresh'; + } + + static override get styles() { + return getCss(); + } + + override render() { + return getHtml.bind(this)(); + } + + static override get properties() { + return { + showEnterpriseBadge: {type: Boolean}, + pictureUrl: {type: String}, + title: {type: String}, + subtitle: {type: String}, + }; + } + + accessor showEnterpriseBadge: boolean = false; + accessor pictureUrl: string = ''; + override accessor title: string = ''; + accessor subtitle: string = ''; + + override firstUpdated() { + const titleElement = this.shadowRoot.querySelector<HTMLElement>('.title'); + assert(titleElement); + titleElement.focus(); + } +} + +declare global { + interface HTMLElementTagNameMap { + 'managed-user-profile-notice-disclosure-refresh': + ManagedUserProfileNoticeDisclosureRefreshElement; + } +} + +customElements.define( + ManagedUserProfileNoticeDisclosureRefreshElement.is, + ManagedUserProfileNoticeDisclosureRefreshElement);
diff --git a/chrome/browser/resources/signin/managed_user_profile_notice/managed_user_profile_notice_refresh.html b/chrome/browser/resources/signin/managed_user_profile_notice/managed_user_profile_notice_refresh.html new file mode 100644 index 0000000..a39876b3 --- /dev/null +++ b/chrome/browser/resources/signin/managed_user_profile_notice/managed_user_profile_notice_refresh.html
@@ -0,0 +1,26 @@ +<!doctype html> +<html dir="$i18n{textdirection}" lang="$i18n{language}"> + <head> + <meta charset="utf-8"> + <meta name="color-scheme" content="light dark"> + <link rel="stylesheet" href="chrome://resources/css/md_colors.css"> + <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css"> + <style> + body { + margin: 0; + width: auto; + } + @media (prefers-color-scheme: dark) { + body { + --md-background-color: var(--signin-dark-customized-background-color); + background-color: var(--md-background-color); + } + } + </style> + <title>$i18n{enterpriseProfileWelcomeTitle}</title> + </head> + <body> + <managed-user-profile-notice-app-refresh></managed-user-profile-notice-app-refresh> + <script type="module" src="/managed_user_profile_notice_app_refresh.js"></script> + </body> +</html>
diff --git a/chrome/browser/resources/skills/app.html.ts b/chrome/browser/resources/skills/app.html.ts index 11f39cc7..dd20cfd 100644 --- a/chrome/browser/resources/skills/app.html.ts +++ b/chrome/browser/resources/skills/app.html.ts
@@ -13,7 +13,7 @@ // clang-format off return html`<!--_html_template_start_--> <cr-toolbar id="toolbar" page-name="$i18n{skillsTitle}" - clear-label="$i18n{delete}" ?autofocus="${true}" + clear-label="$i18n{delete}" autofocus search-prompt="$i18n{searchBarPlaceholderText}" @cr-toolbar-menu-click="${this.onCrToolbarMenuClick_}" menu-label="$i18n{mainMenu}" @search-changed="${this.onSearchChanged_}"
diff --git a/chrome/browser/safe_browsing/BUILD.gn b/chrome/browser/safe_browsing/BUILD.gn index d01b05a..2e9968d 100644 --- a/chrome/browser/safe_browsing/BUILD.gn +++ b/chrome/browser/safe_browsing/BUILD.gn
@@ -169,8 +169,6 @@ "cloud_content_scanning/deep_scanning_utils.h", "cloud_content_scanning/file_analysis_request.cc", "cloud_content_scanning/file_analysis_request.h", - "cloud_content_scanning/file_opening_job.cc", - "cloud_content_scanning/file_opening_job.h", "delayed_warning_navigation_throttle.cc", "delayed_warning_navigation_throttle.h", "download_protection/check_client_download_request.cc",
diff --git a/chrome/browser/safe_browsing/download_protection/deep_scanning_request.cc b/chrome/browser/safe_browsing/download_protection/deep_scanning_request.cc index 9b5ccfb..c118e09 100644 --- a/chrome/browser/safe_browsing/download_protection/deep_scanning_request.cc +++ b/chrome/browser/safe_browsing/download_protection/deep_scanning_request.cc
@@ -24,7 +24,6 @@ #include "chrome/browser/policy/dm_token_utils.h" #include "chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.h" #include "chrome/browser/safe_browsing/cloud_content_scanning/file_analysis_request.h" -#include "chrome/browser/safe_browsing/cloud_content_scanning/file_opening_job.h" #include "chrome/browser/safe_browsing/download_protection/download_protection_service.h" #include "chrome/browser/safe_browsing/download_protection/download_protection_util.h" #include "chrome/browser/safe_browsing/download_protection/download_request_maker.h" @@ -35,6 +34,7 @@ #include "components/enterprise/common/proto/connectors.pb.h" #include "components/enterprise/connectors/core/cloud_content_scanning/binary_upload_service.h" #include "components/enterprise/connectors/core/cloud_content_scanning/deep_scanning_utils.h" +#include "components/enterprise/connectors/core/cloud_content_scanning/file_opening_job.h" #include "components/enterprise/connectors/core/common.h" #include "components/enterprise/connectors/core/reporting_constants.h" #include "components/enterprise/connectors/core/reporting_utils.h"
diff --git a/chrome/browser/safe_browsing/download_protection/deep_scanning_request.h b/chrome/browser/safe_browsing/download_protection/deep_scanning_request.h index 32101fc9..bf96251 100644 --- a/chrome/browser/safe_browsing/download_protection/deep_scanning_request.h +++ b/chrome/browser/safe_browsing/download_protection/deep_scanning_request.h
@@ -20,7 +20,6 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.h" #include "chrome/browser/safe_browsing/cloud_content_scanning/file_analysis_request.h" -#include "chrome/browser/safe_browsing/cloud_content_scanning/file_opening_job.h" #include "chrome/browser/safe_browsing/download_protection/deep_scanning_metadata.h" #include "chrome/browser/safe_browsing/download_protection/download_protection_util.h" #include "components/enterprise/common/proto/connectors.pb.h" @@ -37,6 +36,7 @@ class DownloadProtectionService; class DownloadRequestMaker; +class FileOpeningJob; // This class encapsulates the process of uploading a file to Safe Browsing for // deep scanning and reporting the result.
diff --git a/chrome/browser/screenshot_monitor/BUILD.gn b/chrome/browser/screenshot_monitor/BUILD.gn deleted file mode 100644 index 9cf142ab..0000000 --- a/chrome/browser/screenshot_monitor/BUILD.gn +++ /dev/null
@@ -1,26 +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. - -import("//build/config/android/config.gni") -import("//build/config/android/rules.gni") - -android_library("java") { - sources = [ - "java/src/org/chromium/chrome/browser/screenshot_monitor/ScreenshotMonitor.java", - "java/src/org/chromium/chrome/browser/screenshot_monitor/ScreenshotMonitorDelegate.java", - "java/src/org/chromium/chrome/browser/screenshot_monitor/ScreenshotMonitorImpl.java", - "java/src/org/chromium/chrome/browser/screenshot_monitor/ScreenshotTabObserver.java", - ] - - deps = [ - "//base:base_java", - "//chrome/browser/profiles/android:java", - "//chrome/browser/tab:java", - "//components/ukm/android:java", - "//content/public/android:content_java", - "//third_party/androidx:androidx_annotation_annotation_java", - "//third_party/androidx:androidx_core_core_java", - "//ui/android:ui_full_java", - ] -}
diff --git a/chrome/browser/screenshot_monitor/DEPS b/chrome/browser/screenshot_monitor/DEPS deleted file mode 100644 index df9fbc7..0000000 --- a/chrome/browser/screenshot_monitor/DEPS +++ /dev/null
@@ -1,9 +0,0 @@ -include_rules = [ - "+content/public/android/java", -] - -specific_include_rules = { - ".*test.*": [ - "+chrome/browser/ui/views", - ], -}
diff --git a/chrome/browser/screenshot_monitor/OWNERS b/chrome/browser/screenshot_monitor/OWNERS deleted file mode 100644 index 9d1d9e6..0000000 --- a/chrome/browser/screenshot_monitor/OWNERS +++ /dev/null
@@ -1,5 +0,0 @@ -# Primary -dtrainor@chromium.org - -# Backup -file://components/feature_engagement/OWNERS
diff --git a/chrome/browser/screenshot_monitor/java/src/org/chromium/chrome/browser/screenshot_monitor/ScreenshotMonitor.java b/chrome/browser/screenshot_monitor/java/src/org/chromium/chrome/browser/screenshot_monitor/ScreenshotMonitor.java deleted file mode 100644 index 69a0864..0000000 --- a/chrome/browser/screenshot_monitor/java/src/org/chromium/chrome/browser/screenshot_monitor/ScreenshotMonitor.java +++ /dev/null
@@ -1,51 +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. - -package org.chromium.chrome.browser.screenshot_monitor; - -import org.chromium.base.ThreadUtils; -import org.chromium.build.annotations.NullMarked; - -/** Base class for detecting screenshots and notifying the {@code ScreenshotMonitorDelegate}. */ -@NullMarked -public abstract class ScreenshotMonitor { - private final ScreenshotMonitorDelegate mDelegate; - private boolean mIsMonitoring; - - public ScreenshotMonitor(ScreenshotMonitorDelegate delegate) { - mDelegate = delegate; - } - - /** Start observing screenshot actions. */ - public final void startMonitoring() { - ThreadUtils.assertOnUiThread(); - if (mIsMonitoring) return; - mIsMonitoring = true; - setUpMonitoring(true); - } - - /** Stop observing screenshot actions. */ - public final void stopMonitoring() { - ThreadUtils.assertOnUiThread(); - if (!mIsMonitoring) return; - mIsMonitoring = false; - setUpMonitoring(false); - } - - /** - * Implementation class method to do the actual monitoring for screenshots. - * @param monitor Whether or not to monitor for screenshots. - */ - protected abstract void setUpMonitoring(boolean monitor); - - /** - * Helper method meant to be used by subclasses to notify the {@code ScreenshotMonitorDelegate} - * of screenshot actions. - */ - protected final void notifyDelegate() { - ThreadUtils.assertOnUiThread(); - if (!mIsMonitoring) return; - mDelegate.onScreenshotTaken(); - } -}
diff --git a/chrome/browser/screenshot_monitor/java/src/org/chromium/chrome/browser/screenshot_monitor/ScreenshotMonitorDelegate.java b/chrome/browser/screenshot_monitor/java/src/org/chromium/chrome/browser/screenshot_monitor/ScreenshotMonitorDelegate.java deleted file mode 100644 index 94617fdd..0000000 --- a/chrome/browser/screenshot_monitor/java/src/org/chromium/chrome/browser/screenshot_monitor/ScreenshotMonitorDelegate.java +++ /dev/null
@@ -1,13 +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.chrome.browser.screenshot_monitor; - -import org.chromium.build.annotations.NullMarked; - -/** This class serves as a callback from ScreenshotMonitor. */ -@NullMarked -public interface ScreenshotMonitorDelegate { - void onScreenshotTaken(); -}
diff --git a/chrome/browser/screenshot_monitor/java/src/org/chromium/chrome/browser/screenshot_monitor/ScreenshotMonitorImpl.java b/chrome/browser/screenshot_monitor/java/src/org/chromium/chrome/browser/screenshot_monitor/ScreenshotMonitorImpl.java deleted file mode 100644 index c2dbd73..0000000 --- a/chrome/browser/screenshot_monitor/java/src/org/chromium/chrome/browser/screenshot_monitor/ScreenshotMonitorImpl.java +++ /dev/null
@@ -1,220 +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. - -package org.chromium.chrome.browser.screenshot_monitor; - -import android.app.Activity; -import android.content.ContentResolver; -import android.content.pm.PackageManager; -import android.database.ContentObserver; -import android.database.Cursor; -import android.net.Uri; -import android.provider.MediaStore; -import android.provider.MediaStore.Images.Media; -import android.text.TextUtils; - -import androidx.annotation.VisibleForTesting; -import androidx.core.content.ContextCompat; - -import org.chromium.base.ContextUtils; -import org.chromium.base.Log; -import org.chromium.base.ThreadUtils; -import org.chromium.base.metrics.RecordUserAction; -import org.chromium.base.task.PostTask; -import org.chromium.base.task.TaskTraits; -import org.chromium.build.annotations.NullMarked; -import org.chromium.build.annotations.Nullable; -import org.chromium.ui.base.MimeTypeUtils; -import org.chromium.ui.display.DisplayAndroid; - -/** - * This class detects screenshots by monitoring the screenshots directory on internal and external - * storages, and notifies the ScreenshotMonitorDelegate. The caller should use - * @{link ScreenshotMonitor#create(ScreenshotMonitorDelegate)} to create an instance. - */ -@NullMarked -public class ScreenshotMonitorImpl extends ScreenshotMonitor { - private static final String TAG = "ScreenshotMonitor"; - private final ScreenshotMonitorContentObserver mContentObserver; - - private @Nullable ContentResolver mContentResolverForTesting; - private @Nullable DisplayAndroid mDisplayAndroidForTesting; - - /** Observe content changes in the Media database looking for screenshots. */ - private class ScreenshotMonitorContentObserver extends ContentObserver { - private final ScreenshotMonitor mScreenshotMonitor; - - ScreenshotMonitorContentObserver(ScreenshotMonitor screenshotMonitor) { - // null means use the default thread instead of a new thread for the observer. - super(/* Handler */ null); - mScreenshotMonitor = screenshotMonitor; - } - - // ContentObsever implementation. - @Override - public void onChange(boolean selfChange, @Nullable Uri uri) { - checkAndNotify(uri); - } - - private void checkAndNotify(@Nullable Uri uri) { - if (uri == null) return; - - Log.d(TAG, "Detected change to the media database " + uri); - // Validate the uri before processing it. - if (uri == null || !uri.toString().startsWith(Media.EXTERNAL_CONTENT_URI.toString())) { - Log.w(TAG, "uri: %s is not valid. Returning without processing screenshot", uri); - return; - } - - PostTask.postTask( - TaskTraits.UI_DEFAULT, - () -> { - // Unit tests do not have a media database to query, so skip if necessary. - if (!doesChangeLookLikeScreenshot(uri)) return; - mScreenshotMonitor.notifyDelegate(); - }); - } - - // Returns true if the uri appears to correspond to a screenshot. This will look at the - // location of the file in storage by looking for the word "Screenshot", and the width and - // height of the image. We do this to differentiate between screenshots and downloaded - // images. - private boolean doesChangeLookLikeScreenshot(Uri storeUri) { - ThreadUtils.assertOnUiThread(); - - Cursor cursor = null; - String foundPath = ""; - String imageWidthString = ""; - String imageHeightString = ""; - - String[] mediaProjection = - new String[] { - MediaStore.Images.ImageColumns.DATE_TAKEN, - MediaStore.MediaColumns.DATA, - MediaStore.MediaColumns.HEIGHT, - MediaStore.MediaColumns.WIDTH, - MediaStore.MediaColumns._ID - }; - - // Check if the appropriate disk access permission is enabled. - String requiredPermission = - MimeTypeUtils.getPermissionNameForMimeType(MimeTypeUtils.Type.IMAGE); - if (requiredPermission != null - && ContextCompat.checkSelfPermission( - ContextUtils.getApplicationContext(), requiredPermission) - != PackageManager.PERMISSION_GRANTED) { - RecordUserAction.record("Tab.Screenshot.WithoutStoragePermission"); - return false; - } - - try { - ContentResolver contentResolver = mContentResolverForTesting; - if (contentResolver == null) { - contentResolver = ContextUtils.getApplicationContext().getContentResolver(); - } - - cursor = contentResolver.query(storeUri, mediaProjection, null, null, null); - } catch (SecurityException se) { - // This happens on some exotic devices. - Log.e(TAG, "Cannot query media store.", se); - } - - if (cursor == null) { - return false; - } - - try { - while (cursor.moveToNext()) { - foundPath = - cursor.getString( - cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA)); - imageHeightString = - cursor.getString( - cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.HEIGHT)); - imageWidthString = - cursor.getString( - cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.WIDTH)); - break; - } - } finally { - cursor.close(); - } - - if (TextUtils.isEmpty(imageHeightString) || TextUtils.isEmpty(imageWidthString)) { - return false; - } - - // Verify that it is in a screenshot directory. We don't check the file extension - // because we already know that we have an image from the image database. This directory - // name does not get localized. - int index = foundPath.indexOf("Screenshot"); - if (index == -1) { - return false; - } - - // Check width and height. - DisplayAndroid display = mDisplayAndroidForTesting; - if (display == null) { - display = DisplayAndroid.getNonMultiDisplay(ContextUtils.getApplicationContext()); - } - - int screenHeight = display.getDisplayHeight(); - int screenWidth = display.getDisplayWidth(); - int imageHeight = Integer.parseInt(imageHeightString); - int imageWidth = Integer.parseInt(imageWidthString); - - // Note that the height of the system bar and the status bar are not counted in the - // values returned by displayMetrics. If the device is in portrait, the height reported - // by this API will be smaller than the actual screen size. In landscape mode, the - // reported width will be smaller. This means that either the height or width will match - // (the other will be a bit short). So, we return that the image looks like a - // screenshot if either matches. - if (screenHeight == imageHeight || screenWidth == imageWidth) return true; - - // Just in case the device gets rotated after the snapshot and before the event, check - // width against height instead of width. - if (screenHeight == imageWidth || screenWidth == imageHeight) return true; - - // Otherwise assume this is not a screenshot. - return false; - } - } - - public ScreenshotMonitorImpl(ScreenshotMonitorDelegate delegate, Activity activity) { - super(delegate); - mContentObserver = new ScreenshotMonitorContentObserver(this); - } - - @VisibleForTesting - ScreenshotMonitorImpl( - ScreenshotMonitorDelegate delegate, - Activity activity, - ContentResolver contentResolver, - DisplayAndroid displayAndroid) { - this(delegate, activity); - mContentResolverForTesting = contentResolver; - mDisplayAndroidForTesting = displayAndroid; - } - - // ScreenshotMonitor implementation. - @Override - protected void setUpMonitoring(boolean monitor) { - ContentResolver contentResolver = mContentResolverForTesting; - if (contentResolver == null) { - contentResolver = ContextUtils.getApplicationContext().getContentResolver(); - } - if (monitor) { - // Register the content observer for the Media database to watch the media database. - contentResolver.registerContentObserver( - Media.EXTERNAL_CONTENT_URI, true, mContentObserver); - } else { - contentResolver.unregisterContentObserver(mContentObserver); - } - } - - @VisibleForTesting - ContentObserver getContentObserver() { - return mContentObserver; - } -}
diff --git a/chrome/browser/screenshot_monitor/java/src/org/chromium/chrome/browser/screenshot_monitor/ScreenshotTabObserver.java b/chrome/browser/screenshot_monitor/java/src/org/chromium/chrome/browser/screenshot_monitor/ScreenshotTabObserver.java deleted file mode 100644 index b71fd1d..0000000 --- a/chrome/browser/screenshot_monitor/java/src/org/chromium/chrome/browser/screenshot_monitor/ScreenshotTabObserver.java +++ /dev/null
@@ -1,140 +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.chrome.browser.screenshot_monitor; - -import static org.chromium.build.NullUtil.assumeNonNull; - -import org.chromium.base.UserData; -import org.chromium.base.metrics.RecordHistogram; -import org.chromium.base.metrics.RecordUserAction; -import org.chromium.build.annotations.NullMarked; -import org.chromium.build.annotations.Nullable; -import org.chromium.chrome.browser.tab.EmptyTabObserver; -import org.chromium.chrome.browser.tab.Tab; -import org.chromium.components.ukm.UkmRecorder; -import org.chromium.content_public.browser.WebContents; -import org.chromium.ui.base.WindowAndroid; - -/** A {@link TabObserver} that also handles screenshot related events. */ -@NullMarked -public class ScreenshotTabObserver extends EmptyTabObserver implements UserData { - // Enum for logging Screenshot UMA. These match the TabScreenshotAction enum in enums.xml, and - // must not be changed. New ones can be added if we also add them in enums.xml. - public static final int SCREENSHOT_ACTION_NONE = 0; - public static final int SCREENSHOT_ACTION_SHARE = 1; - public static final int SCREENSHOT_ACTION_DOWNLOAD_IPH = 2; - // If new actions are added, count must always be one higher than the last number. - public static final int SCREENSHOT_ACTION_COUNT = 3; - - private static final Class<ScreenshotTabObserver> USER_DATA_KEY = ScreenshotTabObserver.class; - private @Nullable Runnable mOnReportCompleteForTesting; - - /** - * Gets the existing observer if it exists, otherwise creates one. - * @param tab The Tab for which to create the observer. - * @return ScreenshotTabObserver to use, or null if the tab was null. - */ - public static @Nullable ScreenshotTabObserver from(Tab tab) { - if (tab == null || !tab.isInitialized()) return null; - // Get the current observer from the tab using UserData, if any. If not, create a new - // observer and put it into the UserData for the tab. - ScreenshotTabObserver observer = get(tab); - if (observer == null) { - observer = - tab.getUserDataHost() - .setUserData(USER_DATA_KEY, new ScreenshotTabObserver(tab)); - tab.addObserver(observer); - } - return observer; - } - - /** - * Returns {@link ScreenshotTabObserver} object for a given {@link Tab}, or {@code null} - * if there is no object available. - */ - public static @Nullable ScreenshotTabObserver get(Tab tab) { - if (tab == null || !tab.isInitialized()) return null; - return tab.getUserDataHost().getUserData(USER_DATA_KEY); - } - - /** Number of screenshots taken of the tab while on the same page */ - private int mScreenshotsTaken; - - /** Actions performed after a screenshot was taken. */ - private int mScreenshotAction; - - private @Nullable Tab mTab; - - public ScreenshotTabObserver(Tab tab) { - mTab = tab; - mTab.addObserver(this); - mScreenshotAction = SCREENSHOT_ACTION_NONE; - } - - @Override - public void destroy() { - assumeNonNull(mTab); - mTab.removeObserver(this); - mTab = null; - } - - @Override - public void onClosingStateChanged(Tab tab, boolean closing) { - reportScreenshotUMA(tab); - } - - @Override - public void onDestroyed(Tab tab) { - reportScreenshotUMA(tab); - } - - @Override - public void onLoadStarted(Tab tab, boolean toDifferentDocument) { - reportScreenshotUMA(tab); - } - - @Override - public void onActivityAttachmentChanged(Tab tab, @Nullable WindowAndroid window) { - // Intentionally do nothing to prevent automatic observer removal on detachment. - } - - public void onActionPerformedAfterScreenshot(int action) { - if (mScreenshotsTaken > 0) mScreenshotAction = action; - } - - public void onScreenshotTaken() { - RecordUserAction.record("Tab.Screenshot"); - mScreenshotsTaken++; - } - - /** Before leaving a page, report screenshot related UMA and reset screenshot counter. */ - private void reportScreenshotUMA(Tab tab) { - if (mScreenshotsTaken > 0) { - RecordHistogram.recordCount1MHistogram( - "Tab.Screenshot.ScreenshotsPerPage", mScreenshotsTaken); - RecordHistogram.recordEnumeratedHistogram( - "Tab.Screenshot.Action", mScreenshotAction, SCREENSHOT_ACTION_COUNT); - // For UKM, report a boolean metric as to whether a screenshot was - // taken. - WebContents webContents = tab.getWebContents(); - if (webContents != null) { - new UkmRecorder(webContents, "Tab.Screenshot") - .addBooleanMetric("HasOccurred") - .record(); - } - } - - mScreenshotsTaken = 0; - mScreenshotAction = SCREENSHOT_ACTION_NONE; - if (mOnReportCompleteForTesting != null) { - mOnReportCompleteForTesting.run(); - mOnReportCompleteForTesting = null; - } - } - - public void setOnReportCompleteForTesting(Runnable onReportCompleteForTesting) { - mOnReportCompleteForTesting = onReportCompleteForTesting; - } -}
diff --git a/chrome/browser/search_engines/android/java/src/org/chromium/chrome/browser/search_engines/settings/common/ExpandableSiteSearchMediator.java b/chrome/browser/search_engines/android/java/src/org/chromium/chrome/browser/search_engines/settings/common/ExpandableSiteSearchMediator.java index ba8016fe..4004b8eb 100644 --- a/chrome/browser/search_engines/android/java/src/org/chromium/chrome/browser/search_engines/settings/common/ExpandableSiteSearchMediator.java +++ b/chrome/browser/search_engines/android/java/src/org/chromium/chrome/browser/search_engines/settings/common/ExpandableSiteSearchMediator.java
@@ -6,8 +6,11 @@ import android.content.Context; +import androidx.annotation.VisibleForTesting; + import org.chromium.build.annotations.NullMarked; import org.chromium.chrome.browser.profiles.Profile; +import org.chromium.components.search_engines.TemplateUrl; import org.chromium.ui.modelutil.MVCListAdapter.ListItem; import org.chromium.ui.modelutil.MVCListAdapter.ModelList; import org.chromium.ui.modelutil.PropertyModel; @@ -24,15 +27,17 @@ /** The default maximum number of items to show before displaying a "More" button. */ protected static final int DEFAULT_MAX_ROWS = 5; - /** Tracks whether the list is currently expanded to show all hidden items. */ + /** Tracks whether the list is currently expanded to show all items. */ private boolean mIsExpanded; + /** Staged URLs that are lazy-loaded into mExpandableItems when the list is expanded. */ + private final List<TemplateUrl> mStagedUrls = new ArrayList<>(); + /** - * The items to display when the list is expanded. Subclasses are responsible for populating - * this list during {@link #refreshList()} or lazy-loading them via {@link - * #prepareHiddenItemsIfNeeded()}. + * The items to display when the list is expanded. These are controlled by {@link + * #onMoreButtonClicked(PropertyModel)}. */ - private final List<ListItem> mHiddenItems = new ArrayList<>(); + private final List<ListItem> mExpandableItems = new ArrayList<>(); /** * Constructs the expandable mediator. @@ -56,28 +61,30 @@ return mIsExpanded; } - /** Clears all items currently staged in the hidden items list. */ - protected void clearHiddenItems() { - mHiddenItems.clear(); + /** + * Clears all items from the model list, the expandable items list, and the staged urls list. + */ + protected void clearAllItems() { + mModelList.clear(); + mExpandableItems.clear(); + mStagedUrls.clear(); } /** - * Adds a new item to the hidden items list, which will be displayed when the user clicks - * "More". + * Populates the model list with the given TemplateUrls, adding the default maximum number of + * rows directly and staging the remaining URLs for lazy-loading. * - * @param item The {@link ListItem} to append to the hidden list. + * @param urls The list of TemplateUrls to populate the model list with. */ - protected void addHiddenItem(ListItem item) { - mHiddenItems.add(item); - } - - /** - * Checks if there are no items currently staged in the hidden items list. - * - * @return True if the hidden items list is empty, false otherwise. - */ - protected boolean areHiddenItemsEmpty() { - return mHiddenItems.isEmpty(); + protected void populateTemplateUrls(List<TemplateUrl> urls) { + for (int i = 0; i < urls.size(); i++) { + TemplateUrl url = urls.get(i); + if (i < DEFAULT_MAX_ROWS) { + mModelList.add(createListItem(url)); + } else { + mStagedUrls.add(url); + } + } } /** @@ -105,30 +112,50 @@ * * @param moreButtonModel The property model of the clicked button to update its UI state. */ - protected void onMoreButtonClicked(PropertyModel moreButtonModel) { + @VisibleForTesting + void onMoreButtonClicked(PropertyModel moreButtonModel) { // TODO: We're using a single RecyclerView + ModelList to display the list + More button + - // the hidden list items. Consider splitting into one RecyclerView for the list + More - // button and another RecyclerView for the hidden list items. + // the expandable list items. Consider splitting into one RecyclerView for the list + More + // button and another RecyclerView for the expandable list items. mIsExpanded = !mIsExpanded; moreButtonModel.set(SiteSearchProperties.IS_EXPANDED, mIsExpanded); if (mIsExpanded) { - prepareHiddenItemsIfNeeded(); - if (!mHiddenItems.isEmpty()) { - mModelList.addAll(mHiddenItems); - } + prepareExpandableItemsIfNeeded(); + maybeAddExpandableItemsToModelList(); } else { - // Dynamically calculate where the hidden items start by removing them from the tail. - // This safely accounts for any buttons (Add, More) that might precede the hidden items. - int startIndex = mModelList.size() - mHiddenItems.size(); - mModelList.removeRange(startIndex, mHiddenItems.size()); + // Dynamically calculate where the expandable items start by removing them from the + // tail. This safely accounts for any buttons (Add, More) that might precede the + // expandable items. + int startIndex = mModelList.size() - mExpandableItems.size(); + mModelList.removeRange(startIndex, mExpandableItems.size()); } } /** - * A lifecycle hook called right before the hidden items are added to the list. Subclasses can - * override this to lazy-load their hidden ListItems to save memory and processing time during - * the initial layout. + * Lazy-loads the staged URLs into list items when the list is expanded for the first time. + * Clears the staged URLs afterwards to free up memory. */ - protected void prepareHiddenItemsIfNeeded() {} + private void prepareExpandableItemsIfNeeded() { + if (mExpandableItems.isEmpty()) { + for (TemplateUrl url : mStagedUrls) { + mExpandableItems.add(createListItem(url)); + } + mStagedUrls.clear(); + } + } + + private void maybeAddExpandableItemsToModelList() { + if (!mExpandableItems.isEmpty()) { + mModelList.addAll(mExpandableItems); + } + } + + void addExpandableItemForTesting(ListItem item) { + mExpandableItems.add(item); + } + + boolean areExpandableItemsEmptyForTesting() { + return mExpandableItems.isEmpty(); + } }
diff --git a/chrome/browser/search_engines/android/java/src/org/chromium/chrome/browser/search_engines/settings/custom_site_search/CustomSiteSearchMediator.java b/chrome/browser/search_engines/android/java/src/org/chromium/chrome/browser/search_engines/settings/custom_site_search/CustomSiteSearchMediator.java index 879f3ac..009503a 100644 --- a/chrome/browser/search_engines/android/java/src/org/chromium/chrome/browser/search_engines/settings/custom_site_search/CustomSiteSearchMediator.java +++ b/chrome/browser/search_engines/android/java/src/org/chromium/chrome/browser/search_engines/settings/custom_site_search/CustomSiteSearchMediator.java
@@ -50,29 +50,17 @@ @Override protected void refreshList() { - mModelList.clear(); - clearHiddenItems(); + clearAllItems(); List<TemplateUrl> urls = mTemplateUrlService.getTemplateUrlsByCategory( TemplateUrlCategory.ACTIVE_SITE_SEARCH); - setUpSiteSearchList(urls); + populateTemplateUrls(urls); setUpAddButton(); setUpMoreButtonIfNeeded(urls.size()); } - private void setUpSiteSearchList(List<TemplateUrl> urls) { - for (int i = 0; i < urls.size(); i++) { - ListItem item = createListItem(urls.get(i)); - if (i < DEFAULT_MAX_ROWS) { - mModelList.add(item); - } else { - addHiddenItem(item); - } - } - } - private void setUpAddButton() { PropertyModel addButtonModel = new PropertyModel.Builder(SiteSearchProperties.ALL_KEYS)
diff --git a/chrome/browser/search_engines/android/java/src/org/chromium/chrome/browser/search_engines/settings/inactive_shortcut/InactiveShortcutMediator.java b/chrome/browser/search_engines/android/java/src/org/chromium/chrome/browser/search_engines/settings/inactive_shortcut/InactiveShortcutMediator.java index 15f22d0b..9660f44 100644 --- a/chrome/browser/search_engines/android/java/src/org/chromium/chrome/browser/search_engines/settings/inactive_shortcut/InactiveShortcutMediator.java +++ b/chrome/browser/search_engines/android/java/src/org/chromium/chrome/browser/search_engines/settings/inactive_shortcut/InactiveShortcutMediator.java
@@ -21,13 +21,10 @@ import org.chromium.ui.listmenu.ListMenuItemProperties; import org.chromium.ui.modelutil.MVCListAdapter.ModelList; -import java.util.ArrayList; import java.util.List; @NullMarked public class InactiveShortcutMediator extends ExpandableSiteSearchMediator { - // TODO: Move to ExpandableSiteSearchMediator and add logic in CustomSiteSearchMediator. - private final List<TemplateUrl> mHiddenUrls = new ArrayList<>(); public InactiveShortcutMediator(Context context, ModelList modelList, Profile profile) { super(context, modelList, profile); @@ -37,39 +34,16 @@ @Override protected void refreshList() { - mModelList.clear(); - clearHiddenItems(); - mHiddenUrls.clear(); + clearAllItems(); List<TemplateUrl> urls = mTemplateUrlService.getTemplateUrlsByCategory( TemplateUrlCategory.INACTIVE_SITE_SEARCH); - setUpSiteSearchList(urls); + populateTemplateUrls(urls); setUpMoreButtonIfNeeded(urls.size()); } - private void setUpSiteSearchList(List<TemplateUrl> urls) { - for (int i = 0; i < urls.size(); i++) { - TemplateUrl url = urls.get(i); - if (i < DEFAULT_MAX_ROWS) { - mModelList.add(createListItem(url)); - } else { - mHiddenUrls.add(url); - } - } - } - - @Override - protected void prepareHiddenItemsIfNeeded() { - // Lazy load models and fetch favicons on the first expansion. - if (!mHiddenUrls.isEmpty() && areHiddenItemsEmpty()) { - for (TemplateUrl url : mHiddenUrls) { - addHiddenItem(createListItem(url)); - } - } - } - @Override protected ListMenuDelegate createMenuDelegate(TemplateUrl url) { return () -> {
diff --git a/chrome/browser/search_engines/android/junit/src/org/chromium/chrome/browser/search_engines/settings/common/ExpandableSiteSearchMediatorUnitTest.java b/chrome/browser/search_engines/android/junit/src/org/chromium/chrome/browser/search_engines/settings/common/ExpandableSiteSearchMediatorUnitTest.java index d52155f..729c96f 100644 --- a/chrome/browser/search_engines/android/junit/src/org/chromium/chrome/browser/search_engines/settings/common/ExpandableSiteSearchMediatorUnitTest.java +++ b/chrome/browser/search_engines/android/junit/src/org/chromium/chrome/browser/search_engines/settings/common/ExpandableSiteSearchMediatorUnitTest.java
@@ -82,19 +82,19 @@ @Test public void testHiddenItemsManagement() { - assertTrue(mMediator.areHiddenItemsEmpty()); + assertTrue(mMediator.areExpandableItemsEmptyForTesting()); ListItem item1 = new ListItem(0, null); ListItem item2 = new ListItem(0, null); - mMediator.addHiddenItem(item1); - mMediator.addHiddenItem(item2); + mMediator.addExpandableItemForTesting(item1); + mMediator.addExpandableItemForTesting(item2); - assertFalse(mMediator.areHiddenItemsEmpty()); + assertFalse(mMediator.areExpandableItemsEmptyForTesting()); - mMediator.clearHiddenItems(); + mMediator.clearAllItems(); - assertTrue(mMediator.areHiddenItemsEmpty()); + assertTrue(mMediator.areExpandableItemsEmptyForTesting()); } @Test @@ -122,8 +122,8 @@ ListItem hiddenItem1 = new ListItem(0, null); ListItem hiddenItem2 = new ListItem(0, null); - mMediator.addHiddenItem(hiddenItem1); - mMediator.addHiddenItem(hiddenItem2); + mMediator.addExpandableItemForTesting(hiddenItem1); + mMediator.addExpandableItemForTesting(hiddenItem2); PropertyModel moreButtonModel = new PropertyModel.Builder(SiteSearchProperties.ALL_KEYS) @@ -139,7 +139,6 @@ assertTrue(mMediator.isExpandedForTesting()); assertTrue(moreButtonModel.get(SiteSearchProperties.IS_EXPANDED)); - verify(mMediator).prepareHiddenItemsIfNeeded(); // ModelList should now have 4 items: baseItem, moreButton, hiddenItem1, hiddenItem2 assertEquals(4, mModelList.size());
diff --git a/chrome/browser/tab_contents/BUILD.gn b/chrome/browser/tab_contents/BUILD.gn new file mode 100644 index 0000000..3d534f1 --- /dev/null +++ b/chrome/browser/tab_contents/BUILD.gn
@@ -0,0 +1,105 @@ +# Copyright 2026 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//extensions/buildflags/buildflags.gni") +source_set("tab_contents") { + public = [ + "form_interaction_tab_helper.h", + "navigation_metrics_recorder.h", + "tab_util.h", + "web_contents_collection.h", + ] + + public_deps = [ + "//base", + "//components/content_settings/core/browser:cookie_settings", + "//content/public/browser", + "//url", + ] +} + +source_set("impl") { + sources = [ + "form_interaction_tab_helper.cc", + "navigation_metrics_recorder.cc", + "tab_util.cc", + "web_contents_collection.cc", + ] + + deps = [ + ":tab_contents", + "//chrome/browser:browser_process", + "//chrome/browser/content_settings:content_settings_factory", + "//chrome/browser/profiles:profile", + "//chrome/browser/ui", + "//components/navigation_metrics", + "//components/performance_manager", + "//components/profile_metrics", + "//components/site_engagement/content", + "//extensions/buildflags", + ] + + if (enable_extensions) { + deps += [ "//extensions/browser" ] + } +} + +source_set("unit_tests") { + testonly = true + + sources = [ "form_interaction_tab_helper_unittest.cc" ] + + deps = [ + ":impl", + ":tab_contents", + "//base", + "//base/test:test_support", + "//chrome/test:test_support", + "//components/performance_manager", + "//components/performance_manager/test_support", + "//components/performance_manager/test_support:test_support_common", + "//content/public/browser", + "//content/test:test_support", + "//testing/gtest", + "//third_party/blink/public/common:headers", + ] +} + +if (!is_android) { + source_set("browser_tests") { + testonly = true + + sources = [ + "navigation_metrics_recorder_browsertest.cc", + "view_source_browsertest.cc", + ] + + defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ] + + deps = [ + ":impl", + ":tab_contents", + "//base", + "//base/test:test_support", + "//chrome/app:command_ids", + "//chrome/browser/profiles:profile", + "//chrome/browser/ui", + "//chrome/browser/ui/tabs:tab_strip", + "//chrome/common:chrome_features", + "//chrome/test:test_support_ui", + "//components/content_settings/core/common:features", + "//components/navigation_metrics", + "//components/site_engagement/content", + "//content/public/browser", + "//content/public/common", + "//content/test:test_support", + "//net:net_features", + "//net:test_support", + "//services/network/public/cpp:cpp_base", + "//testing/gmock", + "//testing/gtest", + "//url", + ] + } +}
diff --git a/chrome/browser/tab_contents/view_source_browsertest.cc b/chrome/browser/tab_contents/view_source_browsertest.cc index 1bc3b55..3ec0620 100644 --- a/chrome/browser/tab_contents/view_source_browsertest.cc +++ b/chrome/browser/tab_contents/view_source_browsertest.cc
@@ -15,7 +15,6 @@ #include "chrome/browser/ui/browser_commands.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/common/chrome_features.h" -#include "chrome/common/url_constants.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" #include "content/public/browser/back_forward_cache.h" @@ -25,6 +24,7 @@ #include "content/public/browser/web_contents.h" #include "content/public/common/content_switches.h" #include "content/public/common/isolated_world_ids.h" +#include "content/public/common/url_constants.h" #include "content/public/test/browser_test.h" #include "content/public/test/browser_test_utils.h" #include "content/public/test/prerender_test_util.h"
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index 2c29380..dbcf5ec 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -243,6 +243,7 @@ "//chrome/browser/media/webrtc", "//chrome/browser/memory", "//chrome/browser/search", + "//chrome/browser/tab_contents", "//chrome/browser/task_manager", "//chrome/browser/ui/dialogs", "//chrome/browser/ui/tabs:tab_enums", @@ -296,6 +297,7 @@ "//chrome/browser/content_settings:content_settings_factory_impl", "//chrome/browser/content_settings:content_settings_util", "//chrome/browser/content_settings:content_settings_util_impl", + "//chrome/browser/contextual_tasks:ui", "//chrome/browser/crash_upload_list", "//chrome/browser/data_sharing", "//chrome/browser/devtools", @@ -1790,7 +1792,7 @@ "//chrome/browser/ui/read_anything", "//chrome/browser/ui/tabs:tab_enums", "//chrome/browser/ui/views/side_panel", - "//chrome/browser/ui/waap", + "//chrome/browser/ui/waap:manager", "//chrome/browser/ui/webui/feedback/report_unsafe_site", "//chrome/browser/ui/webui/on_device_internals", "//components/page_image_service/mojom:mojo_bindings", @@ -2136,7 +2138,7 @@ "//ash/quick_pair/proto:fastpair_proto", "//ash/quick_pair/repository", "//ash/quick_pair/ui", - "//ash/strings:strings_grit", + "//ash/strings", "//ash/style", "//ash/webui/annotator", "//ash/webui/annotator/public/mojom:annotator_mojo_bindings", @@ -2966,7 +2968,6 @@ "views/profiles/signin_view_controller_delegate_views.h", ] deps += [ - "//chrome/browser/contextual_tasks:ui", "//chrome/browser/lifetime:termination_notification", "//chrome/browser/search/background", "//chrome/browser/themes", @@ -4158,6 +4159,8 @@ "views/omnibox/remove_suggestion_bubble.h", "views/omnibox/rounded_omnibox_results_frame.cc", "views/omnibox/rounded_omnibox_results_frame.h", + "views/omnibox/webui_readonly_omnibox.cc", + "views/omnibox/webui_readonly_omnibox.h", "views/optimization_guide/optimization_guide_icon_view.cc", "views/optimization_guide/optimization_guide_icon_view.h", "views/overlay/back_to_tab_button.cc",
diff --git a/chrome/browser/ui/android/actions/BUILD.gn b/chrome/browser/ui/android/actions/BUILD.gn index 207bf23..77fc295 100644 --- a/chrome/browser/ui/android/actions/BUILD.gn +++ b/chrome/browser/ui/android/actions/BUILD.gn
@@ -6,6 +6,7 @@ android_library("java") { sources = [ + "java/src/org/chromium/chrome/browser/ui/actions/ActionButtonData.java", "java/src/org/chromium/chrome/browser/ui/actions/ActionId.java", "java/src/org/chromium/chrome/browser/ui/actions/ActionRegistry.java", "java/src/org/chromium/chrome/browser/ui/actions/DelegateButtonData.java",
diff --git a/chrome/browser/ui/android/actions/java/src/org/chromium/chrome/browser/ui/actions/ActionButtonData.java b/chrome/browser/ui/android/actions/java/src/org/chromium/chrome/browser/ui/actions/ActionButtonData.java new file mode 100644 index 0000000..48044493 --- /dev/null +++ b/chrome/browser/ui/android/actions/java/src/org/chromium/chrome/browser/ui/actions/ActionButtonData.java
@@ -0,0 +1,28 @@ +// Copyright 2026 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.ui.actions; + +import org.chromium.build.annotations.NullMarked; + +/** Specialized version of {@link FullButtonData} that includes toggle and transparent states. */ +@NullMarked +public interface ActionButtonData extends FullButtonData { + /** + * Returns true if the button should be transparent (alpha 0) instead of View.INVISIBLE. This + * allows the button to remain clickable even when it is not visually seen. Useful for the new + * background tab animation where two tab switcher buttons are present but only one is seen. + */ + default boolean isTransparent() { + return false; + } + + /** + * Returns true if the button is in a toggled state. This is needed for the bottom bar, which + * signals the user which actions are active. + */ + default boolean isToggled() { + return false; + } +}
diff --git a/chrome/browser/ui/android/actions/java/src/org/chromium/chrome/browser/ui/actions/DelegateButtonData.java b/chrome/browser/ui/android/actions/java/src/org/chromium/chrome/browser/ui/actions/DelegateButtonData.java index 7f6b487..bf9912f 100644 --- a/chrome/browser/ui/android/actions/java/src/org/chromium/chrome/browser/ui/actions/DelegateButtonData.java +++ b/chrome/browser/ui/android/actions/java/src/org/chromium/chrome/browser/ui/actions/DelegateButtonData.java
@@ -15,10 +15,12 @@ * DisplayButtonData}. */ @NullMarked -public class DelegateButtonData implements FullButtonData { +public class DelegateButtonData implements ActionButtonData { private final DisplayButtonData mDelegateButtonData; private final @Nullable Runnable mOnPress; private final @Nullable Runnable mOnLongPress; + private boolean mIsTransparent; + private boolean mIsToggled; /** * Stores parameters until resolution time. Never invokes {@link Runnable} itself. @@ -48,6 +50,34 @@ mOnLongPress = onLongPress; } + /** + * Sets whether the button should be transparent. + * + * @param isTransparent true if the button should be transparent, false otherwise. + */ + public void setIsTransparent(boolean isTransparent) { + mIsTransparent = isTransparent; + } + + /** + * Sets whether the button should be in a toggled state. + * + * @param isToggled true if the button should be toggled, false otherwise. + */ + public void setIsToggled(boolean isToggled) { + mIsToggled = isToggled; + } + + @Override + public boolean isTransparent() { + return mIsTransparent; + } + + @Override + public boolean isToggled() { + return mIsToggled; + } + @Override public String resolveText(Context context) { return mDelegateButtonData.resolveText(context); @@ -79,7 +109,9 @@ return true; } if (o instanceof DelegateButtonData that) { - return mDelegateButtonData.equals(that.mDelegateButtonData); + return mDelegateButtonData.equals(that.mDelegateButtonData) + && mIsToggled == that.mIsToggled + && mIsTransparent == that.mIsTransparent; } return false; }
diff --git a/chrome/browser/ui/android/actions/junit/src/org/chromium/chrome/browser/ui/actions/DelegateButtonDataUnitTest.java b/chrome/browser/ui/android/actions/junit/src/org/chromium/chrome/browser/ui/actions/DelegateButtonDataUnitTest.java index 32f54e5..a24ceb8d 100644 --- a/chrome/browser/ui/android/actions/junit/src/org/chromium/chrome/browser/ui/actions/DelegateButtonDataUnitTest.java +++ b/chrome/browser/ui/android/actions/junit/src/org/chromium/chrome/browser/ui/actions/DelegateButtonDataUnitTest.java
@@ -120,6 +120,18 @@ new DelegateButtonData( differentDisplayButtonData, runnable1, longRunnable1))); + // Test inequality with different transparent state + DelegateButtonData transparentButtonData = + new DelegateButtonData(displayButtonData2, runnable2, longRunnable2); + transparentButtonData.setIsTransparent(true); + assertFalse(buttonData.buttonDataEquals(transparentButtonData)); + + // Test inequality with different toggled state + DelegateButtonData toggledButtonData = + new DelegateButtonData(displayButtonData2, runnable2, longRunnable2); + toggledButtonData.setIsToggled(true); + assertFalse(buttonData.buttonDataEquals(toggledButtonData)); + // Test inequality with null assertFalse(buttonData.buttonDataEquals(null)); @@ -130,6 +142,40 @@ assertTrue(buttonData.buttonDataEquals(buttonData)); } + @Test + @SmallTest + public void testTransparency() { + DelegateButtonData buttonData = new DelegateButtonData(mDisplayButtonData, mRunnable); + + // Default state. + assertFalse(buttonData.isTransparent()); + + // Make it transparent. + buttonData.setIsTransparent(true); + assertTrue(buttonData.isTransparent()); + + // Make it opaque again. + buttonData.setIsTransparent(false); + assertFalse(buttonData.isTransparent()); + } + + @Test + @SmallTest + public void testToggledState() { + DelegateButtonData buttonData = new DelegateButtonData(mDisplayButtonData, mRunnable); + + // Default state. + assertFalse(buttonData.isToggled()); + + // Toggle the button. + buttonData.setIsToggled(true); + assertTrue(buttonData.isToggled()); + + // Untoggle the button. + buttonData.setIsToggled(false); + assertFalse(buttonData.isToggled()); + } + private Drawable createBitmapDrawable() { Bitmap image = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); Resources resources = ApplicationProvider.getApplicationContext().getResources();
diff --git a/chrome/browser/ui/android/bottombar/java/src/org/chromium/chrome/browser/ui/bottombar/BottomBarHostManager.java b/chrome/browser/ui/android/bottombar/java/src/org/chromium/chrome/browser/ui/bottombar/BottomBarHostManager.java index 43bf237..582734d 100644 --- a/chrome/browser/ui/android/bottombar/java/src/org/chromium/chrome/browser/ui/bottombar/BottomBarHostManager.java +++ b/chrome/browser/ui/android/bottombar/java/src/org/chromium/chrome/browser/ui/bottombar/BottomBarHostManager.java
@@ -34,15 +34,25 @@ } private @Nullable BottomBar mBottomBar; + private @Nullable Callback<View> mDefaultAttachCallback; /** * Registers the bottom bar. This method should only ever be called once. * * @param bottomBar The bottom bar to register. + * @param defaultAttachCallback A callback to attach the bottom bar view to the default host. */ - public void registerBottomBar(BottomBar bottomBar) { + public void registerBottomBar(BottomBar bottomBar, Callback<View> defaultAttachCallback) { assert mBottomBar == null : "registerBottomBar should only be called once"; mBottomBar = bottomBar; + mDefaultAttachCallback = defaultAttachCallback; + resetOwnership(); + } + + /** Resets ownership of the bottom bar view to the default owner (TABBED mode). */ + public void resetOwnership() { + assert mDefaultAttachCallback != null : "Default attach callback not set"; + takeOwnership(Host.TABBED, mDefaultAttachCallback); } /**
diff --git a/chrome/browser/ui/android/bottombar/java/src/org/chromium/chrome/browser/ui/bottombar/BottomBarHostManagerUnitTest.java b/chrome/browser/ui/android/bottombar/java/src/org/chromium/chrome/browser/ui/bottombar/BottomBarHostManagerUnitTest.java index 5804e1ac..09f250b 100644 --- a/chrome/browser/ui/android/bottombar/java/src/org/chromium/chrome/browser/ui/bottombar/BottomBarHostManagerUnitTest.java +++ b/chrome/browser/ui/android/bottombar/java/src/org/chromium/chrome/browser/ui/bottombar/BottomBarHostManagerUnitTest.java
@@ -4,6 +4,7 @@ package org.chromium.chrome.browser.ui.bottombar; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -31,6 +32,7 @@ @Mock private View mView; @Mock private ViewGroup mParentView; @Mock private Callback<View> mCallback; + @Mock private Callback<View> mDefaultAttachCallback; private BottomBarHostManager mHostManager; @@ -41,8 +43,17 @@ } @Test + public void testRegisterBottomBar() { + mHostManager.registerBottomBar(mBottomBar, mDefaultAttachCallback); + verify(mBottomBar).setParent(Host.TABBED); + } + + @Test public void testTakeOwnership() { - mHostManager.registerBottomBar(mBottomBar); + mHostManager.registerBottomBar(mBottomBar, mDefaultAttachCallback); + + verify(mDefaultAttachCallback).onResult(mView); + verify(mBottomBar).setParent(Host.TABBED); mHostManager.takeOwnership(Host.HUB, mCallback); @@ -51,22 +62,33 @@ } @Test - public void testTakeOwnership_WithParent() { - when(mView.getParent()).thenReturn(mParentView); - mHostManager.registerBottomBar(mBottomBar); + public void testResetOwnership() { + mHostManager.registerBottomBar(mBottomBar, mDefaultAttachCallback); - mHostManager.takeOwnership(Host.TABBED, mCallback); + mHostManager.resetOwnership(); + + verify(mDefaultAttachCallback, times(2)).onResult(mView); + verify(mBottomBar, times(2)).setParent(Host.TABBED); + } + + @Test + public void testTakeOwnership_WithParent() { + mHostManager.registerBottomBar(mBottomBar, mDefaultAttachCallback); + + when(mView.getParent()).thenReturn(mParentView); + + mHostManager.takeOwnership(Host.HUB, mCallback); verify(mCallback).onResult(mView); verify(mParentView).removeView(mView); - verify(mBottomBar).setParent(Host.TABBED); + verify(mBottomBar).setParent(Host.HUB); } @Test(expected = AssertionError.class) public void testRegisterBottomBarTwice() { - mHostManager.registerBottomBar(mBottomBar); + mHostManager.registerBottomBar(mBottomBar, mDefaultAttachCallback); // This should trigger the assertion - mHostManager.registerBottomBar(mBottomBar); + mHostManager.registerBottomBar(mBottomBar, mDefaultAttachCallback); } @Test(expected = AssertionError.class) @@ -74,4 +96,10 @@ // This should trigger the assertion because mBottomBar is null mHostManager.takeOwnership(Host.HUB, mCallback); } + + @Test(expected = AssertionError.class) + public void testResetOwnership_WithoutRegistration() { + // This should trigger the assertion because defaultAttachCallback is null + mHostManager.resetOwnership(); + } }
diff --git a/chrome/browser/ui/android/extensions/extension_action_delegate_android.cc b/chrome/browser/ui/android/extensions/extension_action_delegate_android.cc index 3ef8d2a..a4e5a991 100644 --- a/chrome/browser/ui/android/extensions/extension_action_delegate_android.cc +++ b/chrome/browser/ui/android/extensions/extension_action_delegate_android.cc
@@ -79,7 +79,14 @@ } void ExtensionActionDelegateAndroid::ShowContextMenuAsFallback() { - // TODO(crbug.com/461981075) + if (!toolbar_android_) { + // TODO(crbug.com/461981075): Remove this check once + // `ExtensionsMenuDelegateAndroid` passes a correct `toolbar_android_` + // instead of `nullptr`. + return; + } + + toolbar_android_->ShowContextMenu(action_id_); } bool ExtensionActionDelegateAndroid::CloseOverflowMenuIfOpen() {
diff --git a/chrome/browser/ui/android/extensions/extensions_toolbar_android.cc b/chrome/browser/ui/android/extensions/extensions_toolbar_android.cc index ba78834..3ccc286b 100644 --- a/chrome/browser/ui/android/extensions/extensions_toolbar_android.cc +++ b/chrome/browser/ui/android/extensions/extensions_toolbar_android.cc
@@ -61,6 +61,12 @@ reinterpret_cast<int64_t>(host.release())); } +void ExtensionsToolbarAndroid::ShowContextMenu( + const ToolbarActionsModel::ActionId& action_id) { + Java_ExtensionsToolbarBridge_showContextMenu(AttachCurrentThread(), + java_object_, action_id); +} + std::unique_ptr<ExtensionActionViewModel> ExtensionsToolbarAndroid::CreateActionViewModel( const ToolbarActionsModel::ActionId& action_id, @@ -88,8 +94,8 @@ } void ExtensionsToolbarAndroid::HideActivePopup() { - // TODO(crbug.com/461981075) - NOTIMPLEMENTED(); + return Java_ExtensionsToolbarBridge_hideActivePopup(AttachCurrentThread(), + java_object_); } bool ExtensionsToolbarAndroid::CloseOverflowMenuIfOpen() { @@ -100,9 +106,8 @@ bool ExtensionsToolbarAndroid::CanShowToolbarActionPopupForAPICall( const std::string& action_id) { - // TODO(crbug.com/461981075) - NOTIMPLEMENTED(); - return false; + return Java_ExtensionsToolbarBridge_hasPoppedOutAction(AttachCurrentThread(), + java_object_); } void ExtensionsToolbarAndroid::ToggleExtensionsMenu() { @@ -144,9 +149,10 @@ } void ExtensionsToolbarAndroid::OnActiveWebContentsChanged( - bool /*is_same_document*/) { - Java_ExtensionsToolbarBridge_onActiveWebContentsChanged(AttachCurrentThread(), - java_object_); + bool /*is_same_document*/, + content::WebContents* web_contents) { + Java_ExtensionsToolbarBridge_onActiveWebContentsChanged( + AttachCurrentThread(), java_object_, web_contents->GetJavaWebContents()); } void ExtensionsToolbarAndroid::OnToolbarControlStateUpdated() {
diff --git a/chrome/browser/ui/android/extensions/extensions_toolbar_android.h b/chrome/browser/ui/android/extensions/extensions_toolbar_android.h index 330f8a3..9b7cb6ce1 100644 --- a/chrome/browser/ui/android/extensions/extensions_toolbar_android.h +++ b/chrome/browser/ui/android/extensions/extensions_toolbar_android.h
@@ -31,6 +31,9 @@ void TriggerPopup(const ToolbarActionsModel::ActionId& action_id, std::unique_ptr<ExtensionViewHost> host); + // Shows the context menu for the given action ID. + void ShowContextMenu(const ToolbarActionsModel::ActionId& action_id); + // ExtensionsToolbarViewModel::Delegate: std::unique_ptr<ExtensionActionViewModel> CreateActionViewModel( const ToolbarActionsModel::ActionId& action_id, @@ -47,7 +50,8 @@ void OnActionRemoved(const ToolbarActionsModel::ActionId& action_id) override; void OnActionUpdated(const ToolbarActionsModel::ActionId& action_id) override; void OnPinnedActionsChanged() override; - void OnActiveWebContentsChanged(bool is_same_document) override; + void OnActiveWebContentsChanged(bool is_same_document, + content::WebContents* web_contents) override; void OnToolbarControlStateUpdated() override; void OnRequestAccessButtonParamsChanged( content::WebContents* web_contents) override;
diff --git a/chrome/browser/ui/android/extensions/java/src/org/chromium/chrome/browser/ui/extensions/ExtensionsToolbarBridge.java b/chrome/browser/ui/android/extensions/java/src/org/chromium/chrome/browser/ui/extensions/ExtensionsToolbarBridge.java index b8ae1a4..6b65088 100644 --- a/chrome/browser/ui/android/extensions/java/src/org/chromium/chrome/browser/ui/extensions/ExtensionsToolbarBridge.java +++ b/chrome/browser/ui/android/extensions/java/src/org/chromium/chrome/browser/ui/extensions/ExtensionsToolbarBridge.java
@@ -181,6 +181,14 @@ } @CalledByNative + void showContextMenu(@JniType("std::string") String actionId) { + // {@link mDelegate} should be set in {@code ExtensionActionListMediator}'s constructor. + assert mDelegate != null; + + mDelegate.showContextMenu(actionId); + } + + @CalledByNative public void onRequestAccessButtonParamsChanged() { for (Observer observer : mObservers) { observer.onRequestAccessButtonParamsChanged(); @@ -195,6 +203,22 @@ } @CalledByNative + public boolean hasPoppedOutAction() { + // {@link mDelegate} should be set in {@code ExtensionActionListMediator}'s constructor. + assert mDelegate != null; + + return mDelegate.hasPoppedOutAction(); + } + + @CalledByNative + public void hideActivePopup() { + // {@link mDelegate} should be set in {@code ExtensionActionListMediator}'s constructor. + assert mDelegate != null; + + mDelegate.hideActivePopup(); + } + + @CalledByNative public void onActionsInitialized() { for (Observer observer : mObservers) { observer.onActionsInitialized(); @@ -230,9 +254,9 @@ } @CalledByNative - public void onActiveWebContentsChanged() { + public void onActiveWebContentsChanged(WebContents webContents) { for (Observer observer : mObservers) { - observer.onActiveWebContentsChanged(); + observer.onActiveWebContentsChanged(webContents); } } @@ -253,7 +277,7 @@ default void onPinnedActionsChanged() {} // Called when the active web contents changes due to e.g. navigation or tab change. - default void onActiveWebContentsChanged() {} + default void onActiveWebContentsChanged(WebContents webContents) {} // Called when the request access button parameters have changed. default void onRequestAccessButtonParamsChanged() {} @@ -265,6 +289,15 @@ public interface Delegate { // Called when the popup should be shown. void triggerPopup(String actionId, long nativeHostPtr); + + // Called when the context menu should be shown. + void showContextMenu(String actionId); + + // Returns whether there is a popped out action. + boolean hasPoppedOutAction(); + + // Called when active popup should be hidden. + void hideActivePopup(); } @NativeMethods
diff --git a/chrome/browser/ui/android/extensions/windowing/test/test_extension_setup.sh b/chrome/browser/ui/android/extensions/windowing/test/test_extension_setup.sh new file mode 100755 index 0000000..8bddd37 --- /dev/null +++ b/chrome/browser/ui/android/extensions/windowing/test/test_extension_setup.sh
@@ -0,0 +1,122 @@ +#!/bin/bash +# Copyright 2026 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +print_usage() { + cat << 'EOF' +============================================================================== +Usage: +./test_extension_setup.sh [-h] [-C <build_dir>] [-d <remote_extension_dir>] + +This script configures the environment and connected Android device for +Desktop Android testing. It automates the following steps: + 1. Validates the Chromium build config (requires is_desktop_android = true). + 2. Verifies an active ADB device connection. + 3. Builds and installs the Chrome APK, and sets it as the default browser. + 4. Builds and installs the CustomTabsClientExample APK. + 5. Pushes the local 'test_extension' folder to the device. + +Options: + -h, --help + Show this help message and exit. + + -C <build_dir> + Path to the Chromium build directory. + Default: out/Default + + -d <remote_extension_dir> + Path on the Android device where the test extension should be pushed. + Provide this if your device uses a specific user profile path + (e.g., /mnt/user/10/emulated/10/test_extension). + Default: /sdcard/Download/test_extension +============================================================================== +EOF +} + +setup() { + local build_dir="out/Default" + local remote_ext_dir="/sdcard/Download/test_extension" + local OPTIND opt + + # Parse the flags. + if [[ "$1" == "--help" ]]; then + print_usage + return 0 + fi + + while getopts "hC:d:" opt; do + case "$opt" in + C) build_dir=$OPTARG ;; + d) remote_ext_dir=$OPTARG ;; + h) print_usage; return 0 ;; + *) echo "Usage: test_extension_setup.sh [-C <build_dir>] " \ + "[-d <remote_extension_dir>]"; return 1 ;; + esac + done + shift $((OPTIND - 1)) + + # Check existence of build directory. + if [[ -d "$build_dir" ]]; then + build_dir=$(realpath "$build_dir") + else + echo "Error: Directory '$build_dir' does not exist." + return 1 + fi + + if [[ ! -f "$build_dir/args.gn" ]]; then + echo "Warning: $build_dir does not look like a Chromium " \ + "build output directory (missing args.gn)." + fi + echo "Validating build configuration in $build_dir..." + + # Check that is_desktop_android is set to true. + RAW_GN_ARGS=$(gn args "$build_dir" --list=is_desktop_android \ + --short 2>/dev/null) + IS_DESKTOP=$(echo "$RAW_GN_ARGS" | cut -d'=' -f2 | xargs) + + if [[ "$IS_DESKTOP" != "true" ]]; then + echo "Error: This build is not configured for Desktop Android." + echo "Please ensure 'is_desktop_android = true' is in your args.gn" + return 1 + fi + echo "Build configuration verified: is_desktop_android = true" + + # Check that a device is connected. + if ! adb get-state &>/dev/null; then + echo "Error: No device connected or authorized." + return 1 + fi + echo "Device connection verified." + + # Build and install Chrome. + autoninja -C "$build_dir" chrome_apk || return 1 + adb install -r "$build_dir/apks/Chrome.apk" + # Set default browser. + PACKAGE_NAME="com.google.android.apps.chrome" + adb shell cmd role add-role-holder android.app.role.BROWSER $PACKAGE_NAME + # Build and install CCT app. + autoninja -C "$build_dir" custom_tabs_client_example_apk || return 1 + adb install -r "$build_dir/apks/CustomTabsClientExample.apk" + + # Copy extension code to device. + LOCAL_EXT_DIR="$(dirname "${BASH_SOURCE[0]}")/test_extension" + # Confirm if the local extension directory actually exists + if [[ -d "$LOCAL_EXT_DIR" ]]; then + echo "Pushing test extension to device..." + + # Make sure the extension directory exists and is empty. + adb shell rm -rf "$remote_ext_dir" + adb shell mkdir -p "$remote_ext_dir" + + # Push the extension to the device. + adb push "$LOCAL_EXT_DIR/." "$remote_ext_dir/" + + echo "Test Extension files synced to $remote_ext_dir" + else + echo "Warning: '$LOCAL_EXT_DIR' not found. Skipping extension sync." \ + "Was this script moved?" + fi +} + +setup "$@"
diff --git a/chrome/browser/ui/android/multiwindow/BUILD.gn b/chrome/browser/ui/android/multiwindow/BUILD.gn index 9b5d7f31..87102f7 100644 --- a/chrome/browser/ui/android/multiwindow/BUILD.gn +++ b/chrome/browser/ui/android/multiwindow/BUILD.gn
@@ -3,6 +3,7 @@ # found in the LICENSE file. import("//build/config/android/rules.gni") +import("//third_party/protobuf/proto_library.gni") android_library("java") { sources = [ @@ -26,6 +27,7 @@ ] deps = [ ":java_resources", + ":multi_instance_data_proto_java", "//base:base_java", "//chrome/browser/feature_engagement:java", "//chrome/browser/flags:java", @@ -47,6 +49,7 @@ "//components/messages/android:java", "//content/public/android:content_java", "//third_party/android_deps:material_design_java", + "//third_party/android_deps:protobuf_lite_runtime_java", "//third_party/androidx:androidx_annotation_annotation_java", "//third_party/androidx:androidx_appcompat_appcompat_resources_java", "//third_party/androidx:androidx_constraintlayout_constraintlayout_java", @@ -60,6 +63,11 @@ resources_package = "org.chromium.chrome.browser.multiwindow" } +proto_java_library("multi_instance_data_proto_java") { + proto_path = "proto" + sources = [ "proto/multi_instance_data.proto" ] +} + android_resources("java_resources") { sources = [ "java/res/color/instance_switcher_item_foreground_color_list.xml",
diff --git a/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/MultiInstancePersistentStore.java b/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/MultiInstancePersistentStore.java index 8511ca7d..c064c48 100644 --- a/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/MultiInstancePersistentStore.java +++ b/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/MultiInstancePersistentStore.java
@@ -4,12 +4,26 @@ package org.chromium.chrome.browser.multiwindow; +import android.content.Context; +import android.util.AtomicFile; + +import org.chromium.base.ContextUtils; +import org.chromium.base.Log; +import org.chromium.base.StreamUtil; import org.chromium.base.shared_preferences.SharedPreferencesManager; import org.chromium.build.annotations.NullMarked; import org.chromium.build.annotations.Nullable; +import org.chromium.chrome.browser.flags.ChromeFeatureList; +import org.chromium.chrome.browser.multiwindow.MultiInstanceDataProto.MultiInstanceData; +import org.chromium.chrome.browser.multiwindow.MultiInstanceDataProto.WindowModeData; import org.chromium.chrome.browser.preferences.MultiInstancePreferenceKeys; import org.chromium.chrome.browser.preferences.MultiInstanceSharedPreferences; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.HashSet; import java.util.Set; /** @@ -18,6 +32,17 @@ */ @NullMarked public class MultiInstancePersistentStore { + private static final String TAG = "MultiInstanceStore"; + private static final String FILE_NAME = "multi_instance_data.pb"; + private static final String DIR = "multi_instance"; + + protected static @Nullable MultiInstanceData sData; + private static @Nullable AtomicFile sAtomicFile; + private static boolean sInitialized; + + static { + ensureInitialized(); + } protected MultiInstancePersistentStore() {} @@ -25,15 +50,102 @@ return MultiInstanceSharedPreferences.getInstance(); } + protected static synchronized void ensureInitialized() { + if (sInitialized) return; + + boolean isProtoEnabled = ChromeFeatureList.sMultiInstanceSharedPrefsMigration.isEnabled(); + // TODO: Implement migration and downgrade path. + if (isProtoEnabled) { + sData = loadProtoFromFile(); + } + sInitialized = true; + } + + protected static void initializeFromMigration(MultiInstanceData data) { + sData = data; + saveProto(); + } + + private static AtomicFile getAtomicFile() { + if (sAtomicFile == null) { + File dir = ContextUtils.getApplicationContext().getDir(DIR, Context.MODE_PRIVATE); + File file = new File(dir, FILE_NAME); + sAtomicFile = new AtomicFile(file); + } + return sAtomicFile; + } + + protected static @Nullable MultiInstanceData loadProtoFromFile() { + AtomicFile atomicFile = getAtomicFile(); + if (!atomicFile.getBaseFile().exists()) return MultiInstanceData.getDefaultInstance(); + + FileInputStream stream = null; + try { + stream = atomicFile.openRead(); + return MultiInstanceData.parseFrom(stream); + } catch (IOException e) { + Log.e(TAG, "Failed to load multi-instance proto", e); + return MultiInstanceData.getDefaultInstance(); + } finally { + StreamUtil.closeQuietly(stream); + } + } + + protected static void saveProto() { + if (sData == null) return; + AtomicFile atomicFile = getAtomicFile(); + FileOutputStream stream = null; + try { + stream = atomicFile.startWrite(); + sData.writeTo(stream); + atomicFile.finishWrite(stream); + } catch (IOException e) { + if (stream != null) atomicFile.failWrite(stream); + Log.e(TAG, "Failed to save multi-instance proto", e); + } + } + + protected static void deleteProtoFile() { + getAtomicFile().delete(); + sData = null; + } + + public static boolean containsMultiWindowModeCycleStartTime() { + if (sData != null) { + return sData.hasMultiWindowModeCycleStartTime(); + } + return getManager() + .contains(MultiInstancePreferenceKeys.MULTI_WINDOW_MODE_CYCLE_START_TIME); + } + + public static boolean containsMultiWindowModeStartTime(int modeIndex) { + if (sData != null) { + WindowModeData windowModeData = sData.getWindowModesMap().get(modeIndex); + return windowModeData != null && windowModeData.hasStartTime(); + } else { + String key = + MultiInstancePreferenceKeys.MULTI_WINDOW_MODE_START_TIME.createKey( + String.valueOf(modeIndex)); + return getManager().contains(key); + } + } + static long readMultiWindowStartTime() { + if (sData != null) return sData.getMultiWindowStartTime(); return getManager().readLong(MultiInstancePreferenceKeys.MULTI_WINDOW_START_TIME, 0); } static void writeMultiWindowStartTime(long startTime) { - getManager().writeLong(MultiInstancePreferenceKeys.MULTI_WINDOW_START_TIME, startTime); + if (sData != null) { + sData = sData.toBuilder().setMultiWindowStartTime(startTime).build(); + saveProto(); + } else { + getManager().writeLong(MultiInstancePreferenceKeys.MULTI_WINDOW_START_TIME, startTime); + } } static boolean readCloseWindowSkipConfirm() { + if (sData != null) return sData.getMultiInstanceCloseWindowSkipConfirm(); return getManager() .readBoolean( MultiInstancePreferenceKeys.MULTI_INSTANCE_CLOSE_WINDOW_SKIP_CONFIRM, @@ -41,25 +153,44 @@ } static void writeCloseWindowSkipConfirm(boolean skipConfirm) { - getManager() - .writeBoolean( - MultiInstancePreferenceKeys.MULTI_INSTANCE_CLOSE_WINDOW_SKIP_CONFIRM, - skipConfirm); + if (sData != null) { + sData = sData.toBuilder().setMultiInstanceCloseWindowSkipConfirm(skipConfirm).build(); + saveProto(); + } else { + getManager() + .writeBoolean( + MultiInstancePreferenceKeys.MULTI_INSTANCE_CLOSE_WINDOW_SKIP_CONFIRM, + skipConfirm); + } } static int readMaxInstanceLimit(int maxInstance) { + if (sData != null) { + return sData.hasMultiInstanceMaxInstanceLimit() + ? sData.getMultiInstanceMaxInstanceLimit() + : maxInstance; + } return getManager() .readInt( MultiInstancePreferenceKeys.MULTI_INSTANCE_MAX_INSTANCE_LIMIT, maxInstance); } static void writeMaxInstanceLimit(int maxInstance) { - getManager() - .writeInt( - MultiInstancePreferenceKeys.MULTI_INSTANCE_MAX_INSTANCE_LIMIT, maxInstance); + if (sData != null) { + sData = sData.toBuilder().setMultiInstanceMaxInstanceLimit(maxInstance).build(); + saveProto(); + } else { + getManager() + .writeInt( + MultiInstancePreferenceKeys.MULTI_INSTANCE_MAX_INSTANCE_LIMIT, + maxInstance); + } } static boolean readInstanceLimitDowngradeTriggered() { + if (sData != null) { + return sData.getMultiInstanceInstanceLimitDowngradeTriggered(); + } return getManager() .readBoolean( MultiInstancePreferenceKeys @@ -68,135 +199,270 @@ } static void writeInstanceLimitDowngradeTriggered(boolean triggered) { - getManager() - .writeBoolean( - MultiInstancePreferenceKeys - .MULTI_INSTANCE_INSTANCE_LIMIT_DOWNGRADE_TRIGGERED, - triggered); + if (sData != null) { + sData = + sData.toBuilder() + .setMultiInstanceInstanceLimitDowngradeTriggered(triggered) + .build(); + saveProto(); + } else { + getManager() + .writeBoolean( + MultiInstancePreferenceKeys + .MULTI_INSTANCE_INSTANCE_LIMIT_DOWNGRADE_TRIGGERED, + triggered); + } } static boolean readRestorationMessageShown() { + if (sData != null) { + return sData.getMultiInstanceRestorationMessageShown(); + } return getManager() .readBoolean( MultiInstancePreferenceKeys.MULTI_INSTANCE_RESTORATION_MESSAGE_SHOWN, false); } - static void writeRestorationMessageShown(boolean triggered) { - getManager() - .writeBoolean( - MultiInstancePreferenceKeys.MULTI_INSTANCE_RESTORATION_MESSAGE_SHOWN, - triggered); + static void writeRestorationMessageShown(boolean shown) { + if (sData != null) { + sData = sData.toBuilder().setMultiInstanceRestorationMessageShown(shown).build(); + saveProto(); + } else { + getManager() + .writeBoolean( + MultiInstancePreferenceKeys.MULTI_INSTANCE_RESTORATION_MESSAGE_SHOWN, + shown); + } } static long readMaxCountHistogramStartTime() { + if (sData != null) { + return sData.getMultiInstanceMaxCountTime(); + } return getManager().readLong(MultiInstancePreferenceKeys.MULTI_INSTANCE_MAX_COUNT_TIME, 0); } static void writeMaxCountHistogramStartTime(long maxCountTime) { - getManager() - .writeLong(MultiInstancePreferenceKeys.MULTI_INSTANCE_MAX_COUNT_TIME, maxCountTime); + if (sData != null) { + sData = sData.toBuilder().setMultiInstanceMaxCountTime(maxCountTime).build(); + saveProto(); + } else { + getManager() + .writeLong( + MultiInstancePreferenceKeys.MULTI_INSTANCE_MAX_COUNT_TIME, + maxCountTime); + } } static int readDailyMaxActiveInstanceCount() { + if (sData != null) { + return sData.getMultiInstanceMaxActiveInstanceCount(); + } return getManager() .readInt(MultiInstancePreferenceKeys.MULTI_INSTANCE_MAX_ACTIVE_INSTANCE_COUNT, 0); } static void writeDailyMaxActiveInstanceCount(int count) { - getManager() - .writeInt( - MultiInstancePreferenceKeys.MULTI_INSTANCE_MAX_ACTIVE_INSTANCE_COUNT, - count); + if (sData != null) { + sData = sData.toBuilder().setMultiInstanceMaxActiveInstanceCount(count).build(); + saveProto(); + } else { + getManager() + .writeInt( + MultiInstancePreferenceKeys.MULTI_INSTANCE_MAX_ACTIVE_INSTANCE_COUNT, + count); + } } static int readDailyMaxInstanceCount() { + if (sData != null) { + return sData.getMultiInstanceMaxInstanceCount(); + } return getManager() .readInt(MultiInstancePreferenceKeys.MULTI_INSTANCE_MAX_INSTANCE_COUNT, 0); } static void writeDailyMaxInstanceCount(int count) { - getManager().writeInt(MultiInstancePreferenceKeys.MULTI_INSTANCE_MAX_INSTANCE_COUNT, count); + if (sData != null) { + sData = sData.toBuilder().setMultiInstanceMaxInstanceCount(count).build(); + saveProto(); + } else { + getManager() + .writeInt(MultiInstancePreferenceKeys.MULTI_INSTANCE_MAX_INSTANCE_COUNT, count); + } } static int readDailyMaxIncognitoInstanceCount() { + if (sData != null) return sData.getMultiInstanceMaxInstanceCountIncognito(); return getManager() .readInt( MultiInstancePreferenceKeys.MULTI_INSTANCE_MAX_INSTANCE_COUNT_INCOGNITO, 0); } static void writeDailyMaxIncognitoInstanceCount(int count) { - getManager() - .writeInt( - MultiInstancePreferenceKeys.MULTI_INSTANCE_MAX_INSTANCE_COUNT_INCOGNITO, - count); + if (sData != null) { + sData = sData.toBuilder().setMultiInstanceMaxInstanceCountIncognito(count).build(); + saveProto(); + } else { + getManager() + .writeInt( + MultiInstancePreferenceKeys.MULTI_INSTANCE_MAX_INSTANCE_COUNT_INCOGNITO, + count); + } } static long readMultiInstanceStartTime() { + if (sData != null) return sData.getMultiInstanceStartTime(); return getManager().readLong(MultiInstancePreferenceKeys.MULTI_INSTANCE_START_TIME, 0); } static void writeMultiInstanceStartTime(long startTime) { - getManager().writeLong(MultiInstancePreferenceKeys.MULTI_INSTANCE_START_TIME, startTime); + if (sData != null) { + sData = sData.toBuilder().setMultiInstanceStartTime(startTime).build(); + saveProto(); + } else { + getManager() + .writeLong(MultiInstancePreferenceKeys.MULTI_INSTANCE_START_TIME, startTime); + } } static long readMultiWindowModeCycleStartTime() { + if (sData != null) { + return sData.getMultiWindowModeCycleStartTime(); + } return getManager() .readLong(MultiInstancePreferenceKeys.MULTI_WINDOW_MODE_CYCLE_START_TIME, 0); } static void writeMultiWindowModeCycleStartTime(long startTime) { - getManager() - .writeLong( - MultiInstancePreferenceKeys.MULTI_WINDOW_MODE_CYCLE_START_TIME, startTime); + if (sData != null) { + sData = sData.toBuilder().setMultiWindowModeCycleStartTime(startTime).build(); + saveProto(); + } else { + getManager() + .writeLong( + MultiInstancePreferenceKeys.MULTI_WINDOW_MODE_CYCLE_START_TIME, + startTime); + } } static long readMultiWindowModeStartTime(int modeIndex, long currentTime) { + if (sData != null) { + WindowModeData wm = sData.getWindowModesMap().get(modeIndex); + return (wm != null && wm.hasStartTime()) ? wm.getStartTime() : currentTime; + } String startTimeKey = MultiInstancePreferenceKeys.MULTI_WINDOW_MODE_START_TIME.createKey(modeIndex); return getManager().readLong(startTimeKey, currentTime); } static void writeMultiWindowModeStartTime(int modeIndex, long startTime) { - String startTimeKey = - MultiInstancePreferenceKeys.MULTI_WINDOW_MODE_START_TIME.createKey(modeIndex); - getManager().writeLong(startTimeKey, startTime); + if (sData != null) { + WindowModeData wm = + sData + .getWindowModesOrDefault(modeIndex, WindowModeData.getDefaultInstance()) + .toBuilder() + .setStartTime(startTime) + .build(); + sData = sData.toBuilder().putWindowModes(modeIndex, wm).build(); + saveProto(); + } else { + String startTimeKey = + MultiInstancePreferenceKeys.MULTI_WINDOW_MODE_START_TIME.createKey(modeIndex); + getManager().writeLong(startTimeKey, startTime); + } } static long readMultiWindowModeDurationMs(int modeIndex) { + if (sData != null) { + WindowModeData windowModeData = sData.getWindowModesMap().get(modeIndex); + return windowModeData != null ? windowModeData.getDurationMs() : 0; + } String durationKey = MultiInstancePreferenceKeys.MULTI_WINDOW_MODE_DURATION_MS.createKey(modeIndex); return getManager().readLong(durationKey, 0); } - static void writeMultiWindowModeDurationMs(int modeIndex, long startTime) { - String durationKey = - MultiInstancePreferenceKeys.MULTI_WINDOW_MODE_DURATION_MS.createKey(modeIndex); - getManager().writeLong(durationKey, startTime); + static void writeMultiWindowModeDurationMs(int modeIndex, long duration) { + if (sData != null) { + WindowModeData windowModeData = + sData + .getWindowModesOrDefault(modeIndex, WindowModeData.getDefaultInstance()) + .toBuilder() + .setDurationMs(duration) + .build(); + sData = sData.toBuilder().putWindowModes(modeIndex, windowModeData).build(); + saveProto(); + } else { + String durationKey = + MultiInstancePreferenceKeys.MULTI_WINDOW_MODE_DURATION_MS.createKey(modeIndex); + getManager().writeLong(durationKey, duration); + } } static @Nullable Set<String> readMultiWindowModeActivities(int modeIndex) { + if (sData != null) { + WindowModeData windowModeData = sData.getWindowModesMap().get(modeIndex); + return (windowModeData != null && windowModeData.getActivitiesCount() > 0) + ? new HashSet<>(windowModeData.getActivitiesList()) + : null; + } String activitiesKey = MultiInstancePreferenceKeys.MULTI_WINDOW_MODE_ACTIVITIES.createKey(modeIndex); return getManager().readStringSet(activitiesKey, null); } - static void writeMultiWindowModeActivities(int modeIndex, Set<String> startTime) { - String startTimeKey = - MultiInstancePreferenceKeys.MULTI_WINDOW_MODE_ACTIVITIES.createKey(modeIndex); - getManager().writeStringSet(startTimeKey, startTime); + static void writeMultiWindowModeActivities(int modeIndex, Set<String> activities) { + if (sData != null) { + WindowModeData windowModeData = + sData + .getWindowModesOrDefault(modeIndex, WindowModeData.getDefaultInstance()) + .toBuilder() + .clearActivities() + .addAllActivities(activities) + .build(); + sData = sData.toBuilder().putWindowModes(modeIndex, windowModeData).build(); + saveProto(); + } else { + String activitiesKey = + MultiInstancePreferenceKeys.MULTI_WINDOW_MODE_ACTIVITIES.createKey(modeIndex); + getManager().writeStringSet(activitiesKey, activities); + } } static void removeMultiWindowModeStartTime(int modeIndex) { - String startTimeKey = - MultiInstancePreferenceKeys.MULTI_WINDOW_MODE_START_TIME.createKey(modeIndex); - getManager().removeKey(startTimeKey); + if (sData != null) { + WindowModeData wm = sData.getWindowModesMap().get(modeIndex); + if (wm != null) { + sData = + sData.toBuilder() + .putWindowModes(modeIndex, wm.toBuilder().clearStartTime().build()) + .build(); + saveProto(); + } + } else { + String startTimeKey = + MultiInstancePreferenceKeys.MULTI_WINDOW_MODE_START_TIME.createKey(modeIndex); + getManager().removeKey(startTimeKey); + } } static void removeMultiWindowModeDurationMs(int modeIndex) { - String durationKey = - MultiInstancePreferenceKeys.MULTI_WINDOW_MODE_DURATION_MS.createKey(modeIndex); - getManager().removeKey(durationKey); + if (sData != null) { + WindowModeData wm = sData.getWindowModesMap().get(modeIndex); + if (wm != null) { + sData = + sData.toBuilder() + .putWindowModes(modeIndex, wm.toBuilder().clearDurationMs().build()) + .build(); + saveProto(); + } + } else { + String durationKey = + MultiInstancePreferenceKeys.MULTI_WINDOW_MODE_DURATION_MS.createKey(modeIndex); + getManager().removeKey(durationKey); + } } static boolean contains(String key) {
diff --git a/chrome/browser/ui/android/multiwindow/proto/multi_instance_data.proto b/chrome/browser/ui/android/multiwindow/proto/multi_instance_data.proto new file mode 100644 index 0000000..2fd5e26 --- /dev/null +++ b/chrome/browser/ui/android/multiwindow/proto/multi_instance_data.proto
@@ -0,0 +1,98 @@ +// Copyright 2026 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +syntax = "proto3"; + +package org.chromium.chrome.browser.multiwindow; + +option java_package = "org.chromium.chrome.browser.multiwindow"; +option java_outer_classname = "MultiInstanceDataProto"; + +// Data representing the state of all Chrome instances for multi-instance +// support. +message MultiInstanceData { + + optional int64 multi_window_start_time = 1; + + // Start timestamp of 1-day period for measuring the max count of instances + // used simultaneously. + optional int64 multi_instance_max_count_time = 2; + + optional int64 multi_instance_start_time = 3; + + // Start timestamp of 1-day period for measuring the duration of disjoint time + // spent in various windowing modes. + optional int64 multi_window_mode_cycle_start_time = 4; + + optional int32 multi_instance_max_instance_limit = 5; + + // Max count of active Chrome instances used in a day. + optional int32 multi_instance_max_active_instance_count = 6; + + // Max count of Chrome instances used in a day. + optional int32 multi_instance_max_instance_count = 7; + + // Max count of Chrome Incognito instances used in a day. + optional int32 multi_instance_max_instance_count_incognito = 8; + + optional bool multi_instance_close_window_skip_confirm = 9; + + optional bool multi_instance_instance_limit_downgrade_triggered = 10; + + optional bool multi_instance_restoration_message_shown = 11; + + // Per-instance data, keyed by instance ID. + map<int32, InstanceData> instances = 12; + + // Per-windowing mode data, keyed by mode index. + map<int32, WindowModeData> window_modes = 13; +} + +// Data representing the state of a single Chrome instance. +message InstanceData { + optional int64 last_accessed_time = 1; + + optional int64 closure_time = 2; + + // {Instance:Task} ID mapping for multi-instance support. + optional int32 task_id = 3; + + // Information on each instance. Normal tab count + optional int32 normal_tab_count = 4; + + optional int32 incognito_tab_count = 5; + + // The total tab count at the time Chrome is shut down for use during + // relaunch. This value may not be accurate if Chrome remains active in the + // foreground or background without being terminated. + optional int32 tab_count_for_relaunch = 6; + + optional int32 profile_type = 7; + + optional int32 latest_persistent_state_id = 8; + + optional string url = 9; + + // The default window title, equivalent to the active tab title. + optional string active_tab_title = 10; + + // A custom window title set by the user. + optional string custom_title = 11; + + optional bool incognito_selected = 12; + + optional bool marked_for_deletion = 13; +} + +// Data representing the state of a specific windowing mode. +message WindowModeData { + // Start timestamp of the current windowing mode. + optional int64 start_time = 1; + + // Aggregated duration of time spent in a given windowing mode. + optional int64 duration_ms = 2; + + // Tracks window IDs of activities in a given windowing mode. + repeated string activities = 3; +}
diff --git a/chrome/browser/ui/android/omnibox/java/res/layout/fusebox_context_popup.xml b/chrome/browser/ui/android/omnibox/java/res/layout/fusebox_context_popup.xml index 570aba4..ef1dc42 100644 --- a/chrome/browser/ui/android/omnibox/java/res/layout/fusebox_context_popup.xml +++ b/chrome/browser/ui/android/omnibox/java/res/layout/fusebox_context_popup.xml
@@ -71,14 +71,9 @@ android:id="@+id/fusebox_tools_divider"/> <TextView + style="@style/Fusebox.PopupMenu.Header" android:id="@+id/fusebox_tools_header" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/fusebox_tools_header" - android:textAlignment="viewStart" - android:textAppearance="@style/TextAppearance.TextSmall.Secondary" - android:paddingHorizontal="8dp" - android:importantForAccessibility="no"/> + android:text="@string/fusebox_tools_header"/> <org.chromium.ui.widget.ButtonCompat style="@style/Fusebox.PopupMenu.Item" @@ -111,14 +106,9 @@ android:id="@+id/fusebox_models_divider"/> <TextView + style="@style/Fusebox.PopupMenu.Header" android:id="@+id/fusebox_models_header" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/fusebox_models_header" - android:textAlignment="viewStart" - android:textAppearance="@style/TextAppearance.TextSmall.Secondary" - android:paddingHorizontal="8dp" - android:importantForAccessibility="no"/> + android:text="@string/fusebox_models_header"/> </LinearLayout>
diff --git a/chrome/browser/ui/android/omnibox/java/res/values/styles.xml b/chrome/browser/ui/android/omnibox/java/res/values/styles.xml index da04c1c..7f9cb31 100644 --- a/chrome/browser/ui/android/omnibox/java/res/values/styles.xml +++ b/chrome/browser/ui/android/omnibox/java/res/values/styles.xml
@@ -46,6 +46,18 @@ <item name="android:background">?android:attr/listDivider</item> </style> + <style name="Fusebox.PopupMenu.Header"> + <item name="android:layout_width">wrap_content</item> + <item name="android:layout_height">wrap_content</item> + <item name="android:textAlignment">viewStart</item> + <item name="android:textAppearance"> + @style/TextAppearance.TextSmall.Secondary + </item> + <item name="android:paddingHorizontal">8dp</item> + <item name="android:importantForAccessibility">no</item> + <item name="android:layout_marginTop">4dp</item> + </style> + <style name="OmniboxIcon" parent="LocationBarButton"> <item name="android:layout_width"> @dimen/location_bar_status_icon_width
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/fusebox/FuseboxMediator.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/fusebox/FuseboxMediator.java index c9dfb2b7..3b1ea245 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/fusebox/FuseboxMediator.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/fusebox/FuseboxMediator.java
@@ -205,11 +205,13 @@ mModel.set( FuseboxProperties.POPUP_ATTACH_FILE_VISIBLE, mComposeboxQueryControllerBridge.isPdfUploadEligible()); - mModel.set( - FuseboxProperties.POPUP_TOOL_CREATE_IMAGE_VISIBLE, - mComposeboxQueryControllerBridge.isCreateImagesEligible() - && (OmniboxFeatures.sShowImageGenerationButtonInIncognito.getValue() - || !mProfile.isIncognitoBranded())); + if (!OmniboxFeatures.sShowModelPicker.getValue()) { + mModel.set( + FuseboxProperties.POPUP_TOOL_CREATE_IMAGE_VISIBLE, + mComposeboxQueryControllerBridge.isCreateImagesEligible() + && (OmniboxFeatures.sShowImageGenerationButtonInIncognito.getValue() + || !mProfile.isIncognitoBranded())); + } } private void setModelList(@Nullable FuseboxAttachmentModelList modelList) { @@ -320,6 +322,14 @@ if (trySetRequestType(AutocompleteRequestType.SEARCH)) { assert mModelList != null; mModelList.clear(); + if (OmniboxFeatures.sShowModelPicker.getValue() + && mComposeboxQueryControllerBridge != null) { + InputState inputState = + mComposeboxQueryControllerBridge.getInputStateSupplier().get(); + if (inputState != null) { + mComposeboxQueryControllerBridge.setActiveModel(inputState.defaultModel); + } + } } } @@ -474,10 +484,13 @@ private void onAttachmentsChanged() { if (!isInInputSession()) return; mModel.set(FuseboxProperties.ATTACHMENTS_VISIBLE, !mModelList.isEmpty()); - mModel.set( - FuseboxProperties.POPUP_TOOL_CREATE_IMAGE_ENABLED, - areAttachmentsCompatibleWithCreateImage()); - updatePopupButtonEnabledStates(); + + if (!OmniboxFeatures.sShowModelPicker.getValue()) { + mModel.set( + FuseboxProperties.POPUP_TOOL_CREATE_IMAGE_ENABLED, + areAttachmentsCompatibleWithCreateImage()); + updatePopupButtonEnabledStates(); + } } private boolean areAttachmentsCompatibleWithCreateImage() { @@ -610,18 +623,21 @@ type == AutocompleteRequestType.SEARCH && OmniboxFeatures.sCompactFusebox.getValue()); mModel.set(FuseboxProperties.AUTOCOMPLETE_REQUEST_TYPE, type); - updatePopupButtonEnabledStates(); - if (OmniboxFeatures.sShowModelPicker.getValue() && isInInputSession()) { + + if (OmniboxFeatures.sShowModelPicker.getValue()) { + if (!isInInputSession()) return; InputState inputState = mComposeboxQueryControllerBridge.getInputStateSupplier().get(); if (inputState != null) { onInputStateChange(inputState); } + } else { + updatePopupButtonEnabledStates(); } } private void updatePopupButtonEnabledStates() { + assert !OmniboxFeatures.sShowModelPicker.getValue(); if (!isInInputSession()) return; - if (OmniboxFeatures.sShowModelPicker.getValue()) return; // Disable Camera and Gallery Selection popup buttons if no remaining attachments are left. boolean allowByCapacity = mModelList.getRemainingAttachments() > 0; @@ -874,6 +890,15 @@ boolean deepSearchVisible = inputState.isToolVisible(ToolMode.TOOL_MODE_DEEP_SEARCH_VALUE); boolean canvasVisible = inputState.isToolVisible(ToolMode.TOOL_MODE_CANVAS_VALUE); + mModel.set( + FuseboxProperties.POPUP_TOOL_CREATE_IMAGE_VISIBLE, + inputState.isImageGenToolVisible() + && (OmniboxFeatures.sShowImageGenerationButtonInIncognito.getValue() + || !mProfile.isIncognitoBranded())); + mModel.set( + FuseboxProperties.POPUP_TOOL_CREATE_IMAGE_ENABLED, + inputState.isImageGenToolEnabled()); + mModel.set(FuseboxProperties.POPUP_TOOL_DEEP_SEARCH_VISIBLE, deepSearchVisible); mModel.set( FuseboxProperties.POPUP_TOOL_DEEP_SEARCH_ENABLED, @@ -909,11 +934,12 @@ selected)); } } - mModel.set(FuseboxProperties.POPUP_MODEL_BUTTON_DATA_LIST, modelButtonDataList); - - boolean anyModels = !modelButtonDataList.isEmpty(); - mModel.set(FuseboxProperties.POPUP_MODEL_DIVIDER_VISIBLE, anyModels); - mModel.set(FuseboxProperties.POPUP_MODEL_HEADER_VISIBLE, anyModels); + boolean showModelPicker = modelButtonDataList.size() >= 2; + mModel.set(FuseboxProperties.POPUP_MODEL_DIVIDER_VISIBLE, showModelPicker); + mModel.set(FuseboxProperties.POPUP_MODEL_HEADER_VISIBLE, showModelPicker); + mModel.set( + FuseboxProperties.POPUP_MODEL_BUTTON_DATA_LIST, + showModelPicker ? modelButtonDataList : List.of()); } private boolean trySetRequestType(@AutocompleteRequestType int requestType) {
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/fusebox/FuseboxMediatorUnitTest.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/fusebox/FuseboxMediatorUnitTest.java index f83b0004..70fba08 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/fusebox/FuseboxMediatorUnitTest.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/fusebox/FuseboxMediatorUnitTest.java
@@ -707,21 +707,29 @@ reset(mPopup); mInput.setRequestType(AutocompleteRequestType.SEARCH); - ModelConfig config = + ModelConfig config1 = ModelConfig.newBuilder() .setModelValue(ModelMode.MODEL_MODE_GEMINI_PRO_AUTOROUTE_VALUE) .setMenuLabel("Auto") .build(); + ModelConfig config2 = + ModelConfig.newBuilder() + .setModelValue(ModelMode.MODEL_MODE_GEMINI_PRO_VALUE) + .setMenuLabel("Flash") + .build(); InputState state = new InputState.Builder() .withActiveModel(ModelMode.MODEL_MODE_GEMINI_PRO_AUTOROUTE_VALUE) - .withAllowedModels(ModelMode.MODEL_MODE_GEMINI_PRO_AUTOROUTE_VALUE) - .withModelConfigs(new byte[][] {config.toByteArray()}) + .withAllowedModels( + ModelMode.MODEL_MODE_GEMINI_PRO_AUTOROUTE_VALUE, + ModelMode.MODEL_MODE_GEMINI_PRO_VALUE) + .withModelConfigs( + new byte[][] {config1.toByteArray(), config2.toByteArray()}) .build(); mInputStateSupplier.set(state); List<PopupButtonData> models = mModel.get(FuseboxProperties.POPUP_MODEL_BUTTON_DATA_LIST); - assertEquals(1, models.size()); + assertEquals(2, models.size()); models.get(0).onClicked.run(); verify(mPopup).dismiss(); @@ -732,6 +740,51 @@ } @Test + public void testModelPickerVisibility_hidesIfFewerThanTwoModels() { + OmniboxFeatures.sShowModelPicker.setForTesting(true); + recreateMediator(); + + InputState state0 = new InputState.Builder().build(); + mInputStateSupplier.set(state0); + assertEquals(0, mModel.get(FuseboxProperties.POPUP_MODEL_BUTTON_DATA_LIST).size()); + assertFalse(mModel.get(FuseboxProperties.POPUP_MODEL_DIVIDER_VISIBLE)); + assertFalse(mModel.get(FuseboxProperties.POPUP_MODEL_HEADER_VISIBLE)); + + ModelConfig config1 = + ModelConfig.newBuilder() + .setModelValue(ModelMode.MODEL_MODE_GEMINI_PRO_AUTOROUTE_VALUE) + .setMenuLabel("Auto") + .build(); + InputState state1 = + new InputState.Builder() + .withAllowedModels(ModelMode.MODEL_MODE_GEMINI_PRO_AUTOROUTE_VALUE) + .withModelConfigs(new byte[][] {config1.toByteArray()}) + .build(); + mInputStateSupplier.set(state1); + assertEquals(0, mModel.get(FuseboxProperties.POPUP_MODEL_BUTTON_DATA_LIST).size()); + assertFalse(mModel.get(FuseboxProperties.POPUP_MODEL_DIVIDER_VISIBLE)); + assertFalse(mModel.get(FuseboxProperties.POPUP_MODEL_HEADER_VISIBLE)); + + ModelConfig config2 = + ModelConfig.newBuilder() + .setModelValue(ModelMode.MODEL_MODE_GEMINI_PRO_VALUE) + .setMenuLabel("Pro") + .build(); + InputState state2 = + new InputState.Builder() + .withAllowedModels( + ModelMode.MODEL_MODE_GEMINI_PRO_AUTOROUTE_VALUE, + ModelMode.MODEL_MODE_GEMINI_PRO_VALUE) + .withModelConfigs( + new byte[][] {config1.toByteArray(), config2.toByteArray()}) + .build(); + mInputStateSupplier.set(state2); + assertEquals(2, mModel.get(FuseboxProperties.POPUP_MODEL_BUTTON_DATA_LIST).size()); + assertTrue(mModel.get(FuseboxProperties.POPUP_MODEL_DIVIDER_VISIBLE)); + assertTrue(mModel.get(FuseboxProperties.POPUP_MODEL_HEADER_VISIBLE)); + } + + @Test public void onRequestTypeButtonClicked_fromDeepSearch_activatesSearchMode() { mInput.setRequestType(AutocompleteRequestType.DEEP_SEARCH); mModel.get(FuseboxProperties.AUTOCOMPLETE_REQUEST_TYPE_CLICKED).run(); @@ -1211,6 +1264,11 @@ .setModelValue(ModelMode.MODEL_MODE_GEMINI_PRO_VALUE) .setMenuLabel("Pro") .build(); + ModelConfig configAuto = + ModelConfig.newBuilder() + .setModelValue(ModelMode.MODEL_MODE_GEMINI_PRO_AUTOROUTE_VALUE) + .setMenuLabel("Auto") + .build(); InputState state = new InputState.Builder() @@ -1218,15 +1276,18 @@ .withAllowedTools(ToolMode.TOOL_MODE_CANVAS_VALUE) .withDisabledTools(ToolMode.TOOL_MODE_CANVAS_VALUE) .withActiveModel(ModelMode.MODEL_MODE_GEMINI_PRO_VALUE) - .withAllowedModels(ModelMode.MODEL_MODE_GEMINI_PRO_VALUE) + .withAllowedModels( + ModelMode.MODEL_MODE_GEMINI_PRO_VALUE, + ModelMode.MODEL_MODE_GEMINI_PRO_AUTOROUTE_VALUE) .withDisabledModels(ModelMode.MODEL_MODE_GEMINI_PRO_VALUE) - .withModelConfigs(new byte[][] {configPro.toByteArray()}) + .withModelConfigs( + new byte[][] {configPro.toByteArray(), configAuto.toByteArray()}) .build(); mInputStateSupplier.set(state); assertTrue(mModel.get(FuseboxProperties.POPUP_TOOL_CANVAS_ENABLED)); List<PopupButtonData> models = mModel.get(FuseboxProperties.POPUP_MODEL_BUTTON_DATA_LIST); - assertEquals(1, models.size()); + assertEquals(2, models.size()); assertTrue(models.get(0).enabled); } @@ -1240,19 +1301,29 @@ .setModelValue(ModelMode.MODEL_MODE_GEMINI_PRO_VALUE) .setMenuLabel("Pro") .build(); + ModelConfig configAuto = + ModelConfig.newBuilder() + .setModelValue(ModelMode.MODEL_MODE_GEMINI_PRO_AUTOROUTE_VALUE) + .setMenuLabel("Auto") + .build(); + InputState state = new InputState.Builder() .withActiveTool(ToolMode.TOOL_MODE_CANVAS_VALUE) .withAllowedTools(ToolMode.TOOL_MODE_DEEP_SEARCH_VALUE) .withActiveModel(ModelMode.MODEL_MODE_GEMINI_PRO_VALUE) - .withAllowedModels(ModelMode.MODEL_MODE_GEMINI_PRO_AUTOROUTE_VALUE) - .withModelConfigs(new byte[][] {configPro.toByteArray()}) + .withAllowedModels( + ModelMode.MODEL_MODE_GEMINI_PRO_AUTOROUTE_VALUE, + ModelMode.MODEL_MODE_GEMINI_PRO_VALUE) + .withModelConfigs( + new byte[][] {configPro.toByteArray(), configAuto.toByteArray()}) .build(); mInputStateSupplier.set(state); assertTrue(mModel.get(FuseboxProperties.POPUP_TOOL_CANVAS_ENABLED)); List<PopupButtonData> modelButtons = mModel.get(FuseboxProperties.POPUP_MODEL_BUTTON_DATA_LIST); + assertEquals(2, modelButtons.size()); assertEquals("Pro", modelButtons.get(0).text); } @@ -1266,16 +1337,26 @@ .setModelValue(ModelMode.MODEL_MODE_GEMINI_PRO_VALUE) .setMenuLabel("Pro") .build(); + ModelConfig configAuto = + ModelConfig.newBuilder() + .setModelValue(ModelMode.MODEL_MODE_GEMINI_PRO_AUTOROUTE_VALUE) + .setMenuLabel("Auto") + .build(); + InputState inputState = new InputState.Builder() .withActiveModel(ModelMode.MODEL_MODE_GEMINI_PRO_VALUE) - .withAllowedModels(ModelMode.MODEL_MODE_GEMINI_PRO_VALUE) - .withModelConfigs(new byte[][] {configPro.toByteArray()}) + .withAllowedModels( + ModelMode.MODEL_MODE_GEMINI_PRO_VALUE, + ModelMode.MODEL_MODE_GEMINI_PRO_AUTOROUTE_VALUE) + .withModelConfigs( + new byte[][] {configPro.toByteArray(), configAuto.toByteArray()}) .build(); mInput.setRequestType(AutocompleteRequestType.SEARCH); mInputStateSupplier.set(inputState); List<PopupButtonData> modelButtons = mModel.get(FuseboxProperties.POPUP_MODEL_BUTTON_DATA_LIST); + assertEquals(2, modelButtons.size()); assertFalse(modelButtons.get(0).selected); mInput.setRequestType(AutocompleteRequestType.AI_MODE); @@ -1308,4 +1389,95 @@ assertTrue(mModel.get(FuseboxProperties.POPUP_ATTACH_GALLERY_ENABLED)); assertFalse(mModel.get(FuseboxProperties.POPUP_ATTACH_FILE_ENABLED)); } + + @Test + public void onInputStateChanged_setsCreateImageVisibilityAndEnablement() { + OmniboxFeatures.sShowModelPicker.setForTesting(true); + recreateMediator(); + + InputState bothHidden = new InputState.Builder().build(); + mInputStateSupplier.set(bothHidden); + assertFalse(mModel.get(FuseboxProperties.POPUP_TOOL_CREATE_IMAGE_VISIBLE)); + assertFalse(mModel.get(FuseboxProperties.POPUP_TOOL_CREATE_IMAGE_ENABLED)); + + InputState imageGenVisibleDisabled = + new InputState.Builder() + .withAllowedTools(ToolMode.TOOL_MODE_IMAGE_GEN_VALUE) + .withDisabledTools(ToolMode.TOOL_MODE_IMAGE_GEN_VALUE) + .build(); + mInputStateSupplier.set(imageGenVisibleDisabled); + assertTrue(mModel.get(FuseboxProperties.POPUP_TOOL_CREATE_IMAGE_VISIBLE)); + assertFalse(mModel.get(FuseboxProperties.POPUP_TOOL_CREATE_IMAGE_ENABLED)); + + InputState imageGenUploadVisibleDisabled = + new InputState.Builder() + .withAllowedTools(ToolMode.TOOL_MODE_IMAGE_GEN_UPLOAD_VALUE) + .withDisabledTools(ToolMode.TOOL_MODE_IMAGE_GEN_UPLOAD_VALUE) + .build(); + mInputStateSupplier.set(imageGenUploadVisibleDisabled); + assertTrue(mModel.get(FuseboxProperties.POPUP_TOOL_CREATE_IMAGE_VISIBLE)); + assertFalse(mModel.get(FuseboxProperties.POPUP_TOOL_CREATE_IMAGE_ENABLED)); + + InputState imageGenEnabled = + new InputState.Builder() + .withAllowedTools(ToolMode.TOOL_MODE_IMAGE_GEN_VALUE) + .build(); + mInputStateSupplier.set(imageGenEnabled); + assertTrue(mModel.get(FuseboxProperties.POPUP_TOOL_CREATE_IMAGE_VISIBLE)); + assertTrue(mModel.get(FuseboxProperties.POPUP_TOOL_CREATE_IMAGE_ENABLED)); + + InputState imageGenUploadEnabled = + new InputState.Builder() + .withAllowedTools(ToolMode.TOOL_MODE_IMAGE_GEN_UPLOAD_VALUE) + .build(); + mInputStateSupplier.set(imageGenUploadEnabled); + assertTrue(mModel.get(FuseboxProperties.POPUP_TOOL_CREATE_IMAGE_VISIBLE)); + assertTrue(mModel.get(FuseboxProperties.POPUP_TOOL_CREATE_IMAGE_ENABLED)); + } + + @Test + public void onAutocompleteRequestTypeChanged_resetsActiveModel() { + OmniboxFeatures.sShowModelPicker.setForTesting(true); + recreateMediator(); + + ModelConfig proConfig = + ModelConfig.newBuilder() + .setModelValue(ModelMode.MODEL_MODE_GEMINI_PRO_VALUE) + .setMenuLabel("Pro") + .build(); + ModelConfig autoConfig = + ModelConfig.newBuilder() + .setModelValue(ModelMode.MODEL_MODE_GEMINI_PRO_AUTOROUTE_VALUE) + .setMenuLabel("Auto") + .build(); + InputState state = + new InputState.Builder() + .withActiveModel(ModelMode.MODEL_MODE_GEMINI_PRO_VALUE) + .withDefaultModel(ModelMode.MODEL_MODE_GEMINI_PRO_VALUE) + .withAllowedModels( + ModelMode.MODEL_MODE_GEMINI_PRO_VALUE, + ModelMode.MODEL_MODE_GEMINI_PRO_AUTOROUTE_VALUE) + .withModelConfigs( + new byte[][] {proConfig.toByteArray(), autoConfig.toByteArray()}) + .build(); + mInputStateSupplier.set(state); + + List<FuseboxProperties.PopupButtonData> models = + mModel.get(FuseboxProperties.POPUP_MODEL_BUTTON_DATA_LIST); + assertEquals(2, models.size()); + assertEquals("Pro", models.get(0).text); + assertEquals("Auto", models.get(1).text); + models.get(1).onClicked.run(); + + verify(mComposeboxQueryControllerBridge) + .setActiveModel(ModelMode.MODEL_MODE_GEMINI_PRO_AUTOROUTE_VALUE); + assertEquals(AutocompleteRequestType.AI_MODE, mInput.getRequestType()); + clearInvocations(mComposeboxQueryControllerBridge); + + // The active model should be reset to the default (Pro). + mModel.get(FuseboxProperties.AUTOCOMPLETE_REQUEST_TYPE_CLICKED).run(); + verify(mComposeboxQueryControllerBridge) + .setActiveModel(ModelMode.MODEL_MODE_GEMINI_PRO_VALUE); + assertEquals(AutocompleteRequestType.SEARCH, mInput.getRequestType()); + } }
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/fusebox/FuseboxViewBinder.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/fusebox/FuseboxViewBinder.java index 45a948e6..956f92e4 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/fusebox/FuseboxViewBinder.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/fusebox/FuseboxViewBinder.java
@@ -391,6 +391,8 @@ return R.drawable.autorenew_24dp; } else if (iconId == IconResourceIds.TIMER_VALUE) { return R.drawable.ic_timer; + } else if (iconId == IconResourceIds.BOLT_VALUE) { + return R.drawable.bolt_24dp; } return Resources.ID_NULL; }
diff --git a/chrome/browser/ui/android/signin/BUILD.gn b/chrome/browser/ui/android/signin/BUILD.gn index b7b33509..fd4736b 100644 --- a/chrome/browser/ui/android/signin/BUILD.gn +++ b/chrome/browser/ui/android/signin/BUILD.gn
@@ -229,6 +229,7 @@ "//chrome/browser/signin/services/android:java", "//chrome/browser/sync/android:java", "//chrome/browser/tab:java", + "//chrome/browser/tabmodel:java", "//chrome/browser/ui/messages/android:java", "//chrome/test/android:chrome_java_unit_test_support", "//components/browser_ui/bottomsheet/android:java",
diff --git a/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/BottomSheetSigninAndHistorySyncCoordinator.java b/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/BottomSheetSigninAndHistorySyncCoordinator.java index 58db6ce..9653ec5f 100644 --- a/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/BottomSheetSigninAndHistorySyncCoordinator.java +++ b/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/BottomSheetSigninAndHistorySyncCoordinator.java
@@ -19,6 +19,8 @@ import org.chromium.base.Callback; import org.chromium.base.supplier.OneshotSupplier; import org.chromium.base.supplier.SupplierUtils; +import org.chromium.base.task.PostTask; +import org.chromium.base.task.TaskTraits; import org.chromium.build.annotations.Initializer; import org.chromium.build.annotations.NullMarked; import org.chromium.build.annotations.Nullable; @@ -74,6 +76,7 @@ ActivityResultTracker.ResultListener { private static final String ADD_ACCOUNT_ACTIVITY_KEY = "ADD_ACCOUNT_ACTIVITY_KEY"; + private static final int HISTORY_SYNC_ENTER_ANIMATION_DELAY_MS = 100; private final WindowAndroid mWindowAndroid; private final Activity mActivity; private final ActivityResultTracker mActivityResultTracker; @@ -492,7 +495,10 @@ mSigninBottomSheetCoordinator.destroy(); mSigninBottomSheetCoordinator = null; - maybeShowHistoryOptInDialog(); + PostTask.postDelayedTask( + TaskTraits.UI_DEFAULT, + this::maybeShowHistoryOptInDialog, + HISTORY_SYNC_ENTER_ANIMATION_DELAY_MS); } /** Implements {@link SigninBottomSheetCoordinator.Delegate}. */ @@ -662,19 +668,20 @@ } mSigninBottomSheetCoordinator = - new SigninBottomSheetCoordinator( - mWindowAndroid, - mActivity, - this, - mBottomSheetController.get(), - mDeviceLockActivityLauncher, - signinManager, - mConfig.bottomSheetStrings, - accountPickerMode, - mConfig.withAccountSigninMode == WithAccountSigninMode.SEAMLESS_SIGNIN, - mSigninAccessPoint, - mConfig.selectedCoreAccountId, - mDelegate.getSigninFlowVariant()); + new SigninBottomSheetCoordinator(this, mDelegate.getSigninFlowVariant()); + // show() is separate to ensure this instance is assigned before any synchronous callbacks + // run. + mSigninBottomSheetCoordinator.show( + mWindowAndroid, + mActivity, + mBottomSheetController.get(), + mDeviceLockActivityLauncher, + signinManager, + mConfig.bottomSheetStrings, + accountPickerMode, + mConfig.withAccountSigninMode == WithAccountSigninMode.SEAMLESS_SIGNIN, + mSigninAccessPoint, + mConfig.selectedCoreAccountId); mDidShowSigninStep = true; }
diff --git a/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/SigninBottomSheetCoordinator.java b/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/SigninBottomSheetCoordinator.java index 1c08cf9..755755b 100644 --- a/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/SigninBottomSheetCoordinator.java +++ b/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/SigninBottomSheetCoordinator.java
@@ -11,8 +11,6 @@ import androidx.annotation.ColorInt; import org.chromium.base.Callback; -import org.chromium.base.task.PostTask; -import org.chromium.base.task.TaskTraits; import org.chromium.build.annotations.NullMarked; import org.chromium.build.annotations.Nullable; import org.chromium.chrome.browser.signin.services.SigninFlowTimestampsLogger.FlowVariant; @@ -34,16 +32,8 @@ /** Responsible of showing the sign-in bottom sheet. */ @NullMarked public class SigninBottomSheetCoordinator implements AccountPickerDelegate { - private static final int HISTORY_SYNC_ENTER_ANIMATION_DELAY_MS = 100; - - private final WindowAndroid mWindowAndroid; - private final Activity mActivity; private final Delegate mDelegate; - private final DeviceLockActivityLauncher mDeviceLockActivityLauncher; - private final SigninManager mSigninManager; - private final @SigninAccessPoint int mSigninAccessPoint; - private final @Nullable CoreAccountId mSelectedCoreAccountId; private final @FlowVariant String mSigninFlowVariant; private @Nullable SigninBottomSheetUiCoordinator mSigninUiCoordinator; @@ -83,12 +73,25 @@ } /** - * Creates an instance of {@link SigninBottomSheetCoordinator} and show the sign-in bottom - * sheet. + * Creates an instance of {@link SigninBottomSheetCoordinator} + * + * @param delegate The delegate for this coordinator. + * @param signinFlowVariant The flow variant for logging purposes. + */ + public SigninBottomSheetCoordinator(Delegate delegate, @FlowVariant String signinFlowVariant) { + mDelegate = delegate; + mSigninFlowVariant = signinFlowVariant; + } + + /** + * Initializes the signin coordinator and possibly shows the bottomsheet. + * + * <p>Separate from constructor to avoid synchronous sign-in callbacks (e.g. seamless sign-in) + * from running before the embedder has finished its own initialization and assigned this + * coordinator instance to a member variable. * * @param windowAndroid The window that hosts the sign-in flow. * @param activity The {@link Activity} that hosts the sign-in flow. - * @param delegate The delegate for this coordinator. * @param bottomSheetController The controller of the sign-in bottomsheet. * @param deviceLockActivityLauncher The launcher to start up the device lock page. * @param signinManager The sign-in manager to start the sign-in. @@ -100,10 +103,9 @@ * @param selectedAccountId the account id to use as default, if present. Account id must be * nonnull for seamless signin. */ - public SigninBottomSheetCoordinator( + public void show( WindowAndroid windowAndroid, Activity activity, - Delegate delegate, BottomSheetController bottomSheetController, DeviceLockActivityLauncher deviceLockActivityLauncher, SigninManager signinManager, @@ -111,48 +113,38 @@ @AccountPickerLaunchMode int accountPickerLaunchMode, boolean isSeamlessSigninFlow, @SigninAccessPoint int signinAccessPoint, - @Nullable CoreAccountId selectedAccountId, - @FlowVariant String signinFlowVariant) { - mWindowAndroid = windowAndroid; - mActivity = activity; - mDelegate = delegate; - mDeviceLockActivityLauncher = deviceLockActivityLauncher; - mSigninManager = signinManager; - mSigninAccessPoint = signinAccessPoint; - mSelectedCoreAccountId = selectedAccountId; - mSigninFlowVariant = signinFlowVariant; - + @Nullable CoreAccountId selectedAccountId) { if (isSeamlessSigninFlow) { - assert mSelectedCoreAccountId != null + assert selectedAccountId != null : "Must provide a nonnullable {@link CoreAccountId} for seamless sign-in flow"; SeamlessSigninCoordinator seamlessSigninCoordinator = new SeamlessSigninCoordinator( - mWindowAndroid, - mActivity, - mSigninManager.getIdentityManager(), - mSigninManager, + windowAndroid, + activity, + signinManager.getIdentityManager(), + signinManager, bottomSheetController, this, bottomSheetStrings, - mDeviceLockActivityLauncher, - mSigninAccessPoint, - assertNonNull(mSelectedCoreAccountId)); + deviceLockActivityLauncher, + signinAccessPoint, + assertNonNull(selectedAccountId)); mSigninUiCoordinator = seamlessSigninCoordinator; seamlessSigninCoordinator.launchSigninFlow(); } else { mSigninUiCoordinator = new AccountPickerBottomSheetCoordinator( - mWindowAndroid, - mSigninManager.getIdentityManager(), - mSigninManager, + windowAndroid, + signinManager.getIdentityManager(), + signinManager, bottomSheetController, this, bottomSheetStrings, - mDeviceLockActivityLauncher, + deviceLockActivityLauncher, accountPickerLaunchMode, - mSigninAccessPoint == SigninAccessPoint.WEB_SIGNIN, - mSigninAccessPoint, - mSelectedCoreAccountId); + signinAccessPoint == SigninAccessPoint.WEB_SIGNIN, + signinAccessPoint, + selectedAccountId); } } @@ -195,17 +187,16 @@ CoreAccountInfo accountInfo, AccountPickerDelegate.SigninStateController controller) { controller.onSigninComplete(); destroy(); - PostTask.postDelayedTask( - TaskTraits.UI_DEFAULT, - () -> mDelegate.onSignInComplete(), - HISTORY_SYNC_ENTER_ANIMATION_DELAY_MS); + mDelegate.onSignInComplete(); } + /** Implements {@link AccountPickerDelegate}. */ @Override public void onSignInCancel() { mDelegate.onSignInCancel(); } + /** Implements {@link AccountPickerDelegate}. */ @Override public @FlowVariant String getSigninFlowVariant() { return mSigninFlowVariant;
diff --git a/chrome/browser/ui/android/signin/junit/src/org/chromium/chrome/browser/ui/signin/account_picker/WebSigninAccountPickerDelegateTest.java b/chrome/browser/ui/android/signin/junit/src/org/chromium/chrome/browser/ui/signin/account_picker/WebSigninAccountPickerDelegateTest.java index d225712..c4330c13 100644 --- a/chrome/browser/ui/android/signin/junit/src/org/chromium/chrome/browser/ui/signin/account_picker/WebSigninAccountPickerDelegateTest.java +++ b/chrome/browser/ui/android/signin/junit/src/org/chromium/chrome/browser/ui/signin/account_picker/WebSigninAccountPickerDelegateTest.java
@@ -25,11 +25,14 @@ import org.chromium.base.Callback; import org.chromium.base.test.BaseRobolectricTestRunner; +import org.chromium.build.annotations.Nullable; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.signin.services.SigninMetricsUtils; import org.chromium.chrome.browser.signin.services.SigninMetricsUtilsJni; import org.chromium.chrome.browser.signin.services.WebSigninBridge; import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.browser.tabmodel.TabModelSelector; +import org.chromium.chrome.browser.ui.signin.DelegateContext; import org.chromium.chrome.test.util.browser.signin.AccountManagerTestRule; import org.chromium.components.signin.browser.WebSigninTrackerResult; import org.chromium.components.signin.metrics.AccountConsistencyPromoAction; @@ -43,6 +46,9 @@ @RunWith(BaseRobolectricTestRunner.class) public class WebSigninAccountPickerDelegateTest { private static final GURL CONTINUE_URL = new GURL("https://test-continue-url.com"); + private static final int TAB_ID = 123; + private static final DelegateContext DELEGATE_CONTEXT = + new WebSigninDelegateContext(TAB_ID, CONTINUE_URL); private final FakeAccountManagerFacade mFakeAccountManagerFacade = spy(new FakeAccountManagerFacade()); @@ -62,88 +68,149 @@ @Mock private Tab mTabMock; + @Mock private TabModelSelector mTabModelSelectorMock; + @Mock private AccountPickerDelegate.SigninStateController mSigninStateControllerMock; @Mock private SigninMetricsUtils.Natives mSigninMetricsUtilsJniMock; + @Mock private Callback<@PostSigninOperationResult Integer> mPostSigninCallbackMock; + @Captor private ArgumentCaptor<LoadUrlParams> mLoadUrlParamsCaptor; @Captor private ArgumentCaptor<Callback<@WebSigninTrackerResult Integer>> mWebSigninCallbackCaptor; - private WebSigninAccountPickerDelegate mDelegate; + private @Nullable WebSigninAccountPickerDelegate mDelegate; @Before public void setUp() { mAccountManagerTestRule.addAccount(TestAccounts.ACCOUNT1); - when(mTabMock.getProfile()).thenReturn(mProfileMock); SigninMetricsUtilsJni.setInstanceForTesting(mSigninMetricsUtilsJniMock); - mDelegate = - new WebSigninAccountPickerDelegate( - mTabMock, mWebSigninBridgeFactoryMock, CONTINUE_URL); when(mWebSigninBridgeFactoryMock.createWithCoreAccountId(eq(mProfileMock), any(), any())) .thenReturn(mWebSigninBridgeMock); } @After public void tearDown() { - mDelegate.onAccountPickerDestroy(); + if (mDelegate != null) { + mDelegate.onAccountPickerDestroy(); + } } @Test public void testSignInSucceeded() { + when(mTabModelSelectorMock.getTabById(TAB_ID)).thenReturn(mTabMock); + mDelegate = + new WebSigninAccountPickerDelegate( + mProfileMock, mTabModelSelectorMock, mWebSigninBridgeFactoryMock); + + mDelegate.runPostSigninAction( + TestAccounts.ACCOUNT1, DELEGATE_CONTEXT, mPostSigninCallbackMock); + + verifyWebSigninBridgeAndTriggerCallback(WebSigninTrackerResult.SUCCESS); + + verify(mPostSigninCallbackMock).onResult(PostSigninOperationResult.SUCCESS); + } + + // TODO(crbug.com/469772349): Remove all legacy tests (using deprecated constructor) after + // activityless-signin migration. + + @Test + public void testSignInSucceeded_legacy() { + when(mTabMock.getProfile()).thenReturn(mProfileMock); + mDelegate = + new WebSigninAccountPickerDelegate( + mTabMock, mWebSigninBridgeFactoryMock, CONTINUE_URL); mDelegate.onSignInComplete(TestAccounts.ACCOUNT1, mSigninStateControllerMock); - verify(mWebSigninBridgeFactoryMock) - .createWithCoreAccountId( - eq(mProfileMock), - eq(TestAccounts.ACCOUNT1.getId()), - mWebSigninCallbackCaptor.capture()); - - mWebSigninCallbackCaptor.getValue().onResult(WebSigninTrackerResult.SUCCESS); + verifyWebSigninBridgeAndTriggerCallback(WebSigninTrackerResult.SUCCESS); verify(mSigninStateControllerMock).onSigninComplete(); - verify(mTabMock).loadUrl(mLoadUrlParamsCaptor.capture()); - LoadUrlParams loadUrlParams = mLoadUrlParamsCaptor.getValue(); - Assert.assertEquals( - "Continue url does not match!", CONTINUE_URL.getSpec(), loadUrlParams.getUrl()); } @Test public void testSignInFailedWithConnectionError() { + mDelegate = + new WebSigninAccountPickerDelegate( + mProfileMock, mTabModelSelectorMock, mWebSigninBridgeFactoryMock); + + mDelegate.runPostSigninAction( + TestAccounts.ACCOUNT1, DELEGATE_CONTEXT, mPostSigninCallbackMock); + + verifyWebSigninBridgeAndTriggerCallback(WebSigninTrackerResult.OTHER_ERROR); + + verify(mPostSigninCallbackMock).onResult(PostSigninOperationResult.OTHER_ERROR); + } + + @Test + public void testSignInFailedWithConnectionError_legacy() { + when(mTabMock.getProfile()).thenReturn(mProfileMock); + mDelegate = + new WebSigninAccountPickerDelegate( + mTabMock, mWebSigninBridgeFactoryMock, CONTINUE_URL); + mDelegate.onSignInComplete(TestAccounts.ACCOUNT1, mSigninStateControllerMock); - verify(mWebSigninBridgeFactoryMock) - .createWithCoreAccountId( - eq(mProfileMock), - eq(TestAccounts.ACCOUNT1.getId()), - mWebSigninCallbackCaptor.capture()); - - mWebSigninCallbackCaptor.getValue().onResult(WebSigninTrackerResult.OTHER_ERROR); + verifyWebSigninBridgeAndTriggerCallback(WebSigninTrackerResult.OTHER_ERROR); verify(mSigninStateControllerMock).showGenericError(); - verify(mSigninMetricsUtilsJniMock) - .logAccountConsistencyPromoAction( - AccountConsistencyPromoAction.GENERIC_ERROR_SHOWN, - SigninAccessPoint.WEB_SIGNIN); } @Test public void testSignInFailedWithGaiaError() { + mDelegate = + new WebSigninAccountPickerDelegate( + mProfileMock, mTabModelSelectorMock, mWebSigninBridgeFactoryMock); + + mDelegate.runPostSigninAction( + TestAccounts.ACCOUNT1, DELEGATE_CONTEXT, mPostSigninCallbackMock); + + verifyWebSigninBridgeAndTriggerCallback(WebSigninTrackerResult.AUTH_ERROR); + + verify(mPostSigninCallbackMock).onResult(PostSigninOperationResult.AUTH_ERROR); + } + + @Test + public void testSignInFailedWithGaiaError_legacy() { + when(mTabMock.getProfile()).thenReturn(mProfileMock); + mDelegate = + new WebSigninAccountPickerDelegate( + mTabMock, mWebSigninBridgeFactoryMock, CONTINUE_URL); + mDelegate.onSignInComplete(TestAccounts.ACCOUNT1, mSigninStateControllerMock); + verifyWebSigninBridgeAndTriggerCallback(WebSigninTrackerResult.AUTH_ERROR); + verify(mSigninStateControllerMock).showAuthError(); + } + + private void verifyWebSigninBridgeAndTriggerCallback(@WebSigninTrackerResult int result) { verify(mWebSigninBridgeFactoryMock) .createWithCoreAccountId( eq(mProfileMock), eq(TestAccounts.ACCOUNT1.getId()), mWebSigninCallbackCaptor.capture()); - mWebSigninCallbackCaptor.getValue().onResult(WebSigninTrackerResult.AUTH_ERROR); - verify(mSigninStateControllerMock).showAuthError(); - verify(mSigninMetricsUtilsJniMock) - .logAccountConsistencyPromoAction( - AccountConsistencyPromoAction.AUTH_ERROR_SHOWN, - SigninAccessPoint.WEB_SIGNIN); + mWebSigninCallbackCaptor.getValue().onResult(result); + + if (result == WebSigninTrackerResult.SUCCESS) { + verify(mTabMock).loadUrl(mLoadUrlParamsCaptor.capture()); + LoadUrlParams loadUrlParams = mLoadUrlParamsCaptor.getValue(); + Assert.assertEquals( + "Continue url does not match!", CONTINUE_URL.getSpec(), loadUrlParams.getUrl()); + } else if (result == WebSigninTrackerResult.OTHER_ERROR) { + verify(mSigninMetricsUtilsJniMock) + .logAccountConsistencyPromoAction( + AccountConsistencyPromoAction.GENERIC_ERROR_SHOWN, + SigninAccessPoint.WEB_SIGNIN); + } else if (result == WebSigninTrackerResult.AUTH_ERROR) { + verify(mSigninMetricsUtilsJniMock) + .logAccountConsistencyPromoAction( + AccountConsistencyPromoAction.AUTH_ERROR_SHOWN, + SigninAccessPoint.WEB_SIGNIN); + } else { + throw new IllegalStateException("Unexpected result: " + result); + } } }
diff --git a/chrome/browser/ui/android/tab_model/BUILD.gn b/chrome/browser/ui/android/tab_model/BUILD.gn index 4f244f0..61c86273 100644 --- a/chrome/browser/ui/android/tab_model/BUILD.gn +++ b/chrome/browser/ui/android/tab_model/BUILD.gn
@@ -61,6 +61,7 @@ "//chrome/browser/sessions", "//chrome/browser/sync", "//chrome/browser/tab", + "//chrome/browser/tab_contents", "//chrome/browser/ui:browser_navigator_params_headers", "//chrome/browser/ui/browser_window", "//chrome/browser/ui/browser_window/internal",
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionAccessControlButtonMediator.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionAccessControlButtonMediator.java index 7f68d49..3648edfb 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionAccessControlButtonMediator.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionAccessControlButtonMediator.java
@@ -52,6 +52,10 @@ return; } + refreshRequestAccessButtonWithWebContents(webContents); + } + + private void refreshRequestAccessButtonWithWebContents(WebContents webContents) { RequestAccessButtonParams params = mExtensionsToolbarBridge.getRequestAccessButtonParams(webContents); if (params.getExtensionIds().length > 0) { @@ -70,8 +74,8 @@ private class ToolbarObserver implements ExtensionsToolbarBridge.Observer { @Override - public void onActiveWebContentsChanged() { - refreshRequestAccessButton(); + public void onActiveWebContentsChanged(WebContents webContents) { + refreshRequestAccessButtonWithWebContents(webContents); } @Override
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListCoordinator.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListCoordinator.java index fc8cedd6..bbd6d10 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListCoordinator.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListCoordinator.java
@@ -28,6 +28,7 @@ import org.chromium.components.browser_ui.widget.dragreorder.DragTouchHandler.DraggabilityProvider; import org.chromium.components.embedder_support.contextmenu.ContextMenuPopulatorFactory; import org.chromium.content_public.browser.selection.SelectionDropdownMenuDelegate; +import org.chromium.ui.base.ViewUtils; import org.chromium.ui.base.WindowAndroid; import org.chromium.ui.listmenu.ListMenuButton; import org.chromium.ui.modelutil.MVCListAdapter.ModelList; @@ -39,10 +40,6 @@ */ @NullMarked public class ExtensionActionListCoordinator implements Destroyable { - /** Provider for extension action button views. */ - public interface ActionAnchorViewProvider { - @Nullable View getButtonViewForId(String actionId); - } private final Context mContext; private final ExtensionActionListRecyclerView mContainer; @@ -50,6 +47,7 @@ private final ExtensionActionListMediator mMediator; private final DragReorderableRecyclerViewAdapter mAdapter; @Nullable private final LifetimeAssert mLifetimeAssert = LifetimeAssert.create(this); + private final RecyclerViewDelegate mRecyclerViewDelegate = new RecyclerViewDelegate(); private boolean mIsDragging; @@ -76,7 +74,7 @@ task, profile, currentTabSupplier, - this::getButtonViewForId, + mRecyclerViewDelegate, extensionsToolbarBridge, contextMenuPopulatorFactory, selectionDropdownMenuDelegate); @@ -137,10 +135,20 @@ /** Performs a click on the button for the given action. */ public void click(String actionId) { - View view = getButtonViewForId(actionId); - if (view != null) { - view.performClick(); - } + mMediator.requestActionVisibility( + actionId, + () -> { + View view = getButtonViewForId(actionId); + + // We expect the view to exist at this point, but we shouldn't rely on {@link + // RecyclerView}. + if (view == null) { + mMediator.undoPopout(); + return; + } + + view.performClick(); + }); } @Nullable @@ -150,8 +158,6 @@ if (actionId.equals(model.get(ExtensionActionButtonProperties.ID))) { RecyclerView.ViewHolder holder = mContainer.findViewHolderForAdapterPosition(i); if (holder == null) { - // TODO(crbug.com/478113313): If the action is unpinned, pop it out to show - // action popup. return null; } return holder.itemView; @@ -160,6 +166,20 @@ return null; } + /** Returns whether there is a popped out action. */ + public boolean hasPoppedOutAction() { + return mMediator.hasPoppedOutAction(); + } + + /** + * Remembers whether we can show the popped out action, but does not update the UI just yet, to + * avoid refreshing the UI twice. We actually update the UI via {@link fitActionsWithinWidth()}, + * which will be called due to the rest of the action list having a lower priority. + */ + public int setCanShowPoppedOutAction(int availableWidth) { + return mMediator.setCanShowPoppedOutAction(availableWidth); + } + /** * Updates the list of displayed actions to fit within the provided width constraint. * @@ -190,4 +210,37 @@ model.set(ExtensionActionButtonProperties.DRAG_HELPER, dragHelper); model.set(ExtensionActionButtonProperties.TOUCH_LISTENER, dragHelper::onTouch); } + + public class RecyclerViewDelegate { + /** + * Retrieves the view representing the button for a specific extension action. + * + * @param actionId The ID of the action. + * @return The {@link View} of the given action ID, or {@code null} if no such view exists + * in the current layout. + */ + public @Nullable View getButtonViewForId(String actionId) { + return ExtensionActionListCoordinator.this.getButtonViewForId(actionId); + } + + /** + * Adds a {@link Runnable} to the RecyclerView container that will be executed after a + * layout phase or animation cycle completes. + * + * <p>Specifically, the runnable will execute on the next layout pass if there are no + * animations currently running. If an animation is in progress, the runnable will be + * deferred and executed as soon as the animation ends. + * + * @param runnable The {@link Runnable} to execute once layouts/animations are settled. + */ + public void addOnAnimationsFinishedRunnable(Runnable runnable) { + mContainer.addOnAnimationsFinishedRunnable(runnable); + } + + /** Requests a layout pass on the underlying RecyclerView container. */ + public void requestLayoutWithViewUtils() { + ViewUtils.requestLayout( + mContainer, "RecyclerViewDelegate.requestLayoutWithViewUtils()"); + } + } }
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListMediator.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListMediator.java index cfaaf249..56cb103 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListMediator.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListMediator.java
@@ -90,9 +90,9 @@ private final ChromeAndroidTask mTask; private final Profile mProfile; private final NullableObservableSupplier<Tab> mCurrentTabSupplier; - private final ExtensionActionListCoordinator.ActionAnchorViewProvider mActionAnchorViewProvider; private final @Nullable ContextMenuPopulatorFactory mContextMenuPopulatorFactory; private final @Nullable SelectionDropdownMenuDelegate mSelectionDropdownMenuDelegate; + private final ExtensionActionListCoordinator.RecyclerViewDelegate mRecyclerViewDelegate; private final ExtensionsToolbarBridge mExtensionsToolbarBridge; private final ToolbarDelegate mToolbarDelegate = new ToolbarDelegate(); @@ -102,9 +102,18 @@ @Nullable private final LifetimeAssert mLifetimeAssert = LifetimeAssert.create(this); - // The maximum width that the icons can take up. It is set when the toolbar requests us to be a - // certain size. Until then, we assume we have infinite space. - private @Nullable Integer mAvailableWidth; + // The ID of the action that should be "popped out", since it needs to be visible to show a + // popup anchored to the action view (e.g extension popup or context menu). During animation, it + // should reflect the end state. + @Nullable private String mPoppedOutActionId; + + // Whether the toolbar has allocated us with enough width to show the popped out action. Until + // then, we assume we have infinite space. + private boolean mCanShowPoppedOutAction = true; + + // The maximum width that the icons (other than popped out action) can take up. It is set when + // the toolbar requests us to be a certain size. Until then, we assume we have infinite space. + private @Nullable Integer mAvailableWidthForPinnedActions; public ExtensionActionListMediator( Context context, @@ -113,7 +122,7 @@ ChromeAndroidTask task, Profile profile, NullableObservableSupplier<Tab> currentTabSupplier, - ExtensionActionListCoordinator.ActionAnchorViewProvider actionAnchorViewProvider, + ExtensionActionListCoordinator.RecyclerViewDelegate recyclerViewDelegate, ExtensionsToolbarBridge extensionsToolbarBridge, @Nullable ContextMenuPopulatorFactory contextMenuPopulatorFactory, @Nullable SelectionDropdownMenuDelegate selectionDropdownMenuDelegate) { @@ -123,7 +132,7 @@ mTask = task; mProfile = profile; mCurrentTabSupplier = currentTabSupplier; - mActionAnchorViewProvider = actionAnchorViewProvider; + mRecyclerViewDelegate = recyclerViewDelegate; mExtensionsToolbarBridge = extensionsToolbarBridge; mContextMenuPopulatorFactory = contextMenuPopulatorFactory; mSelectionDropdownMenuDelegate = selectionDropdownMenuDelegate; @@ -145,13 +154,38 @@ LifetimeAssert.setSafeToGc(mLifetimeAssert, true); } + /** Returns whether there is an action that is popped out. */ + public boolean hasPoppedOutAction() { + return mPoppedOutActionId != null; + } + + /** + * Remembers whether we can show the popped out action, but does not update the UI just yet, to + * avoid refreshing the UI twice. We actually update the UI via {@link fitActionsWithinWidth()}, + * which will be called due to the rest of the action list having a lower priority for the + * toolbar to display, as determined in {@code ToolbarUtils}. + * + * @param availableWidth The maximum width that toolbar allows us to use up. + * @return The actual width that we will use up for the popped out action. + */ + public int setCanShowPoppedOutAction(int availableWidth) { + int itemWidth = mContext.getResources().getDimensionPixelSize(R.dimen.toolbar_button_width); + if (hasPoppedOutAction() && itemWidth <= availableWidth) { + mCanShowPoppedOutAction = true; + return itemWidth; + } else { + mCanShowPoppedOutAction = false; + return 0; + } + } + /** * Reconciles the current list of models with the list of IDs from the bridge. This handles * additions, removals, and reordering without rebuilding the whole list. */ @VisibleForTesting void reconcileActionItems() { - String[] actionIds = mExtensionsToolbarBridge.getPinnedActionIds(); + String[] pinnedActionIds = mExtensionsToolbarBridge.getPinnedActionIds(); Tab currentTab = mCurrentTabSupplier.get(); WebContents webContents = currentTab != null ? currentTab.getWebContents() : null; @@ -163,54 +197,54 @@ // Optimization: Remove items that are no longer present in the new list. // This prevents unnecessary moves if the first item is removed. - Set<String> actionIdsSet = new HashSet<>(Arrays.asList(actionIds)); + Set<String> pinnedActionIdsSet = new HashSet<>(Arrays.asList(pinnedActionIds)); for (int i = mModels.size() - 1; i >= 0; i--) { String id = getActionIdForIndex(i); - if (!actionIdsSet.contains(id)) { - if (id.equals(currentPopupActionId)) { - closePopup(); - } - mModels.removeAt(i); + + boolean isPoppedOutAction = mPoppedOutActionId != null && mPoppedOutActionId.equals(id); + if (pinnedActionIdsSet.contains(id) || isPoppedOutAction) { + // We shouldn't remove the model if the icon is pinned or popped out. + continue; } + + if (id.equals(currentPopupActionId)) { + closePopup(); + } + mModels.removeAt(i); } + int itemWidth = mContext.getResources().getDimensionPixelSize(R.dimen.toolbar_button_width); + int maxNumberOfItems = Integer.MAX_VALUE; - if (mAvailableWidth != null) { - int itemWidth = - mContext.getResources().getDimensionPixelSize(R.dimen.toolbar_button_width); + if (mAvailableWidthForPinnedActions != null) { assert itemWidth > 0; - maxNumberOfItems = mAvailableWidth / itemWidth; + maxNumberOfItems = mAvailableWidthForPinnedActions / itemWidth; } // O(N) for removals/no-ops; O(N^2) for reordering/insertions. int currentModelIndex = 0; - for (String actionId : actionIds) { + + // Go through non-popped-out actions. + for (String actionId : pinnedActionIds) { + if (mPoppedOutActionId != null && mPoppedOutActionId.equals(actionId)) { + continue; + } + if (currentModelIndex >= maxNumberOfItems) { + // We ran out of space. break; } - ExtensionAction action = mExtensionsToolbarBridge.getAction(actionId, webContents); - if (action == null) { - continue; - } - - if (currentModelIndex < mModels.size() - && getActionIdForIndex(currentModelIndex).equals(actionId)) { - currentModelIndex++; - continue; - } - - int indexInModels = findIndexForId(actionId, currentModelIndex + 1); - - if (indexInModels != -1) { - mModels.move(indexInModels, currentModelIndex); - } else { - mModels.add(currentModelIndex, createListItem(action, webContents)); - } - - currentModelIndex++; + currentModelIndex = reconcileItem(actionId, currentModelIndex, webContents); } + // Deal with the popped out action last, as it should appear on the [right|left] end of the + // list for [LTR|RTL]. + if (mPoppedOutActionId != null && mCanShowPoppedOutAction) { + currentModelIndex = reconcileItem(mPoppedOutActionId, currentModelIndex, webContents); + } + + // Remove rest of the items. while (mModels.size() > currentModelIndex) { if (getActionIdForIndex(currentModelIndex).equals(currentPopupActionId)) { closePopup(); @@ -219,6 +253,34 @@ } } + /** + * Helper to calculate whether we should show an action item, and if so to reorder {@link + * mModels} so that {@code actionId} comes at {@code currentIndex}. + * + * @return The next index of {@link mModels} that needs to be evaluated. + */ + private int reconcileItem( + String actionId, int currentIndex, @Nullable WebContents webContents) { + ExtensionAction action = mExtensionsToolbarBridge.getAction(actionId, webContents); + if (action == null) { + return currentIndex; + } + + if (currentIndex < mModels.size() && getActionIdForIndex(currentIndex).equals(actionId)) { + // We already have {@link actionId} in the correct place. We can just move onto the next + // one. + return currentIndex + 1; + } + + int indexInModels = findIndexForId(actionId, currentIndex + 1); + if (indexInModels == -1) { + mModels.add(currentIndex, createListItem(action, webContents)); + } else { + mModels.move(indexInModels, currentIndex); + } + return currentIndex + 1; + } + private ListItem createListItem(ExtensionAction action, @Nullable WebContents webContents) { String actionId = action.getId(); @@ -254,12 +316,15 @@ return icon; } - // Updates model properties while keeping it in place. @VisibleForTesting void updateActionProperties(String actionId) { Tab currentTab = mCurrentTabSupplier.get(); WebContents webContents = currentTab != null ? currentTab.getWebContents() : null; + updateActionPropertiesWithWebContents(actionId, webContents); + } + // Updates model properties while keeping it in place. + void updateActionPropertiesWithWebContents(String actionId, @Nullable WebContents webContents) { int index = findIndexForId(actionId); if (index == -1) { return; @@ -284,10 +349,7 @@ mModels.get(index).model.set(ExtensionActionButtonProperties.TOOLTIP, action.getTooltip()); } - private void updateActionPropertiesForAll() { - Tab currentTab = mCurrentTabSupplier.get(); - WebContents webContents = currentTab != null ? currentTab.getWebContents() : null; - + private void updateActionPropertiesForAll(WebContents webContents) { for (int i = 0; i < mModels.size(); i++) { updateActionPropertiesForIndex(i, getActionIdForIndex(i), webContents); } @@ -331,25 +393,58 @@ mExtensionsToolbarBridge.executeUserAction(actionId, InvocationSource.TOOLBAR_BUTTON); } + /** + * Run {@code onVisible} after making sure that the action exists by popping out. + * + * @param actionId The ID of the action that needs visibility. + * @param runnable The runnable to run after all animations end and the {@link RecyclerView} + * reaches a stable state. This does not guarantee that when this runnable is called the + * action is visible - for example, another animation might have taken over and unpopped the + * action. + */ + public void requestActionVisibility(String actionId, Runnable runnable) { + if (mPoppedOutActionId != null && !actionId.equals(mPoppedOutActionId)) { + // Undo pop out for any other action. + undoPopout(); + } + + mRecyclerViewDelegate.addOnAnimationsFinishedRunnable(runnable); + + if (findIndexForId(actionId) == -1) { + mPoppedOutActionId = actionId; + } + + // Force the toolbar to recalculate the toolbar ranking and provide us with a new {@code + // availableWidth}, given that the amount we'll use has changed. + // Also, when no animation is necessary (e.g. the action is already pinned), this will + // trigger {@link ExtensionActionListRecyclerView}'s {@code onLayoutChangedListener} to + // fire, calling the runnable that we just added. + mRecyclerViewDelegate.requestLayoutWithViewUtils(); + } + + @VisibleForTesting + void undoPopout() { + if (mPoppedOutActionId != null) { + mPoppedOutActionId = null; + + // Request layout to update available width and trigger updates. + mRecyclerViewDelegate.requestLayoutWithViewUtils(); + } + } + private void requestShowPopup(String actionId, long nativeHostPtr) { closePopup(); closeContextMenu(); ExtensionActionPopupContents contents = ExtensionActionPopupContents.create(nativeHostPtr); - - if (findIndexForId(actionId) == -1) { - // TODO(crbug.com/483194547): Implement popping out actions. - contents.destroy(); - return; - } else { - showPopupOnReadyAnchor(actionId, contents); - } + requestActionVisibility(actionId, () -> showPopupOnAnchor(actionId, contents)); } - private void showPopupOnReadyAnchor(String actionId, ExtensionActionPopupContents contents) { - View buttonView = mActionAnchorViewProvider.getButtonViewForId(actionId); + private void showPopupOnAnchor(String actionId, ExtensionActionPopupContents contents) { + View buttonView = mRecyclerViewDelegate.getButtonViewForId(actionId); if (buttonView == null) { contents.destroy(); + undoPopout(); return; } @@ -385,6 +480,7 @@ mActionState = new ActionState.Idle(); popup.destroy(); + undoPopout(); } @VisibleForTesting @@ -392,28 +488,26 @@ closePopup(); closeContextMenu(); - if (findIndexForId(actionId) == -1) { - // TODO(crbug.com/483194547): Implement popping out actions. - return; - } else { - showContextMenuOnReadyAnchor(actionId); - } + requestActionVisibility(actionId, () -> showContextMenuOnAnchor(actionId)); } - private void showContextMenuOnReadyAnchor(String actionId) { + private void showContextMenuOnAnchor(String actionId) { ListMenuButton buttonView = - (ListMenuButton) mActionAnchorViewProvider.getButtonViewForId(actionId); + (ListMenuButton) mRecyclerViewDelegate.getButtonViewForId(actionId); if (buttonView == null) { + undoPopout(); return; } Tab currentTab = mCurrentTabSupplier.get(); if (currentTab == null) { + undoPopout(); return; } WebContents webContents = currentTab.getWebContents(); if (webContents == null) { + undoPopout(); return; } @@ -437,7 +531,7 @@ ListMenuButton buttonView = (ListMenuButton) - mActionAnchorViewProvider.getButtonViewForId( + mRecyclerViewDelegate.getButtonViewForId( ((ActionState.ContextMenuActive) mActionState).getActionId()); if (buttonView != null) { // We expect the View to exist if {@code mCurrentContextMenuActionId} is non-null, but @@ -448,11 +542,12 @@ } mActionState = new ActionState.Idle(); + undoPopout(); } /** Updates the list of displayed actions to fit within the provided width constraint. */ public void fitActionsWithinWidth(int availableWidth) { - mAvailableWidth = availableWidth; + mAvailableWidthForPinnedActions = availableWidth; // If this is called during an animation (e.g. the user resizes window during pinning / // unpinning animation), we abandon the animation and update to the new state instantly. @@ -497,15 +592,30 @@ } @Override - public void onActiveWebContentsChanged() { - updateActionPropertiesForAll(); + public void onActiveWebContentsChanged(WebContents webContents) { + updateActionPropertiesForAll(webContents); } } private class ToolbarDelegate implements ExtensionsToolbarBridge.Delegate { @Override public void triggerPopup(String actionId, long nativeHostPtr) { - ExtensionActionListMediator.this.requestShowPopup(actionId, nativeHostPtr); + requestShowPopup(actionId, nativeHostPtr); + } + + @Override + public void showContextMenu(String actionId) { + requestShowContextMenu(actionId); + } + + @Override + public boolean hasPoppedOutAction() { + return ExtensionActionListMediator.this.hasPoppedOutAction(); + } + + @Override + public void hideActivePopup() { + ExtensionActionListMediator.this.closePopup(); } } }
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListMediatorTest.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListMediatorTest.java index 4881f3b..56e4dd5f 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListMediatorTest.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListMediatorTest.java
@@ -47,6 +47,8 @@ import org.chromium.chrome.browser.ui.extensions.ExtensionAction; import org.chromium.chrome.browser.ui.extensions.ExtensionActionContextMenuBridge; import org.chromium.chrome.browser.ui.extensions.ExtensionActionContextMenuBridgeJni; +import org.chromium.chrome.browser.ui.extensions.ExtensionActionPopupContents; +import org.chromium.chrome.browser.ui.extensions.ExtensionActionPopupContentsJni; import org.chromium.chrome.browser.ui.extensions.ExtensionsToolbarBridge; import org.chromium.content_public.browser.WebContents; import org.chromium.ui.base.WindowAndroid; @@ -112,10 +114,16 @@ @Mock private Profile mProfile; @Mock private WindowAndroid mWindowAndroid; @Mock private WebContents mWebContents; - @Mock private ExtensionActionContextMenuBridge.Native mActionContextMenuBridgeJniMock; + @Mock private ExtensionsToolbarBridge mExtensionsToolbarBridge; + + @Mock private ExtensionActionPopupContents mPopupContentsMock; + @Mock private ExtensionActionPopupContents.Natives mPopupContentsJniMock; + @Mock private MenuModelBridge mMenuModelBridge; - @Mock private ExtensionActionListCoordinator.ActionAnchorViewProvider mActionAnchorViewProvider; + @Mock private ExtensionActionContextMenuBridge.Native mActionContextMenuBridgeJniMock; + + @Mock private ExtensionActionListCoordinator.RecyclerViewDelegate mRecyclerViewDelegate; @Captor private ArgumentCaptor<ListMenuHost.PopupMenuShownListener> mPopupListenerCaptor; @@ -128,6 +136,10 @@ // Mock AndroidChromeTask. when(mTask.getOrCreateNativeBrowserWindowPtr(mProfile)).thenReturn(BROWSER_WINDOW_POINTER); + // Add the JNI mock for ExtensionActionPopupContents: + ExtensionActionPopupContentsJni.setInstanceForTesting(mPopupContentsJniMock); + when(mPopupContentsJniMock.create(anyLong())).thenReturn(mPopupContentsMock); + // Mock JNI for Context Menu Bridge. ExtensionActionContextMenuBridgeJni.setInstanceForTesting(mActionContextMenuBridgeJniMock); when(mActionContextMenuBridgeJniMock.init(anyLong(), any(), any(), anyInt())) @@ -175,7 +187,7 @@ mTask, mProfile, mCurrentTabSupplier, - mActionAnchorViewProvider, + mRecyclerViewDelegate, mExtensionsToolbarBridge, /* contextMenuPopulatorFactory= */ null, /* selectionDropdownMenuDelegate= */ null) { @@ -339,7 +351,7 @@ assertEquals(2, mModels.size()); // Test width for more than 1 item but less than 2 items. - mMediator.fitActionsWithinWidth(itemWidth + (int) (itemWidth / 2)); + mMediator.fitActionsWithinWidth(itemWidth + itemWidth / 2); assertEquals(1, mModels.size()); // Test width for exactly 1 item. @@ -353,6 +365,107 @@ assertEquals(0, mModels.size()); } + @Test + public void testPopOutAction_Unpinned_Popup() { + // Action 3 is initially not in the model (unpinned). + assertEquals(2, mModels.size()); + + // Trigger a popup for Action 3 via the bridge delegate. + mBridgeDelegateCaptor.getValue().triggerPopup(ACTION3_ID, 123L); + mMediator.reconcileActionItems(); + + // Action 3 should now be present in the models (popped out). + assertEquals("Action 3 should be added to the list", 3, mModels.size()); + assertItemAt(2, ACTION3_ID, "title of action 3", ICON_GREEN); + } + + @Test + public void testPopOutAction_Unpinned_ContextMenu() { + // Action 3 is initially not in the model. + assertEquals(2, mModels.size()); + + // Trigger a context menu for Action 3. + mMediator.requestShowContextMenu(ACTION3_ID); + mMediator.reconcileActionItems(); + + // Action 3 should be popped out (added to the list). + assertEquals("Action 3 should be temporarily added", 3, mModels.size()); + assertItemAt(2, ACTION3_ID, "title of action 3", ICON_GREEN); + } + + @Test + public void testPopOutAction_HiddenPinned_Popup() { + // Get the button width. + int buttonWidth = + ApplicationProvider.getApplicationContext() + .getResources() + .getDimensionPixelSize( + org.chromium.chrome.browser.toolbar.R.dimen.toolbar_button_width); + + // Constrain width so only 1 action fits (we have 2 pinned actions). + mMediator.fitActionsWithinWidth(buttonWidth); + + // Verify initial state: Only Action 1 is visible. Action 2 is hidden. + assertEquals(1, mModels.size()); + assertItemAt(0, ACTION1_ID, "title of action 1", ICON_RED); + + // Execute: Trigger a popup for Action 2 (pinned but hidden). + mBridgeDelegateCaptor.getValue().triggerPopup(ACTION2_ID, 123L); + mMediator.reconcileActionItems(); + + // Verify: Action 2 is temporarily added to the list (popped out). + assertEquals("Action 2 should be added to the list", 2, mModels.size()); + assertItemAt(0, ACTION1_ID, "title of action 1", ICON_RED); + assertItemAt(1, ACTION2_ID, "title of action 2", ICON_BLUE); + } + + @Test + public void testUndoPopout() { + // Action 3 is unpinned and not in the list. + assertEquals(2, mModels.size()); + + // Trigger popup for Action 3 via the bridge delegate. + mBridgeDelegateCaptor.getValue().triggerPopup(ACTION3_ID, 123L); + mMediator.reconcileActionItems(); + + // The action is popped out (added to the list). + assertEquals("Action 3 should be added to the list", 3, mModels.size()); + assertItemAt(2, ACTION3_ID, "title of action 3", ICON_GREEN); + + // Manually call {@code undoPopout()}. + mMediator.undoPopout(); + mMediator.reconcileActionItems(); + + // The action is removed from the list. + assertEquals("Action 3 should be removed", 2, mModels.size()); + assertItemAt(0, ACTION1_ID, "title of action 1", ICON_RED); + assertItemAt(1, ACTION2_ID, "title of action 2", ICON_BLUE); + } + + @Test + public void testPopOutAction_WidthReservation() { + int buttonWidth = + ApplicationProvider.getApplicationContext() + .getResources() + .getDimensionPixelSize( + org.chromium.chrome.browser.toolbar.R.dimen.toolbar_button_width); + + // Initially, no width is reserved because nothing is popped out. + int reservedWidth = mMediator.setCanShowPoppedOutAction(1000); + assertEquals("Should return 0 when no action is popped out", 0, reservedWidth); + + // Trigger a popup for an unpinned action (Action 3). + mBridgeDelegateCaptor.getValue().triggerPopup(ACTION3_ID, 123L); + mMediator.reconcileActionItems(); + + // Now it should reserve the width of one button. + reservedWidth = mMediator.setCanShowPoppedOutAction(1000); + assertEquals( + "Should return button width when an action is popped out", + buttonWidth, + reservedWidth); + } + private static Bitmap createSimpleIcon(int color) { Bitmap bitmap = Bitmap.createBitmap(12, 12, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap);
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListRecyclerView.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListRecyclerView.java index d6167d42..fe26b4f 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListRecyclerView.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListRecyclerView.java
@@ -21,6 +21,9 @@ import org.chromium.build.annotations.Nullable; import org.chromium.chrome.browser.toolbar.R; +import java.util.ArrayList; +import java.util.List; + /** * A {@link RecyclerView} for extension action buttons. This container will automatically hide any * buttons that don't fit into the allowed width. @@ -35,6 +38,11 @@ /** Custom animator that triggers our layout loop when it accepts an animation task. */ private final DefaultItemAnimator mItemAnimator = new ActionListItemAnimator(); + /** Runnables to run after all animations end. */ + private final List<Runnable> mOnAnimationsFinishedRunnables = new ArrayList<>(); + + private @Nullable Transition mLastTransition; + private View.@Nullable OnLayoutChangeListener mLayoutChangeListener; private final AccelerateDecelerateInterpolator mAccelerateDecelerateInterpolator = new AccelerateDecelerateInterpolator(); @@ -83,9 +91,12 @@ (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> { post( () -> { - if (!mItemAnimator.isRunning()) { - updateRecyclerViewWidth(); + if (mItemAnimator.isRunning()) { + return; } + + updateRecyclerViewWidth(); + runAllOnAnimationsFinishedRunnables(); }); }; addOnLayoutChangeListener(mLayoutChangeListener); @@ -95,6 +106,36 @@ mTransitionRoot = transitionRoot; } + /** + * Adds a callback to run after the UI becomes stable. Specifically, either after the animation + * ends, or during the next layout if there is no pending animation. + */ + public void addOnAnimationsFinishedRunnable(Runnable runnable) { + mOnAnimationsFinishedRunnables.add(runnable); + } + + private void runAllOnAnimationsFinishedRunnables() { + if (mOnAnimationsFinishedRunnables.isEmpty()) { + return; + } + + List<Runnable> runnables = new ArrayList<>(mOnAnimationsFinishedRunnables); + mOnAnimationsFinishedRunnables.clear(); + + for (Runnable runnable : runnables) { + runnable.run(); + } + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + if (mLayoutChangeListener != null) { + removeOnLayoutChangeListener(mLayoutChangeListener); + addOnLayoutChangeListener(mLayoutChangeListener); + } + } + @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); @@ -151,6 +192,34 @@ matchRecyclerView.setStartDelay(startDelay); matchRecyclerView.setInterpolator(mAccelerateDecelerateInterpolator); + matchRecyclerView.addListener( + new Transition.TransitionListener() { + @Override + public void onTransitionEnd(Transition transition) { + transition.removeListener(this); + if (transition == mLastTransition) { + runAllOnAnimationsFinishedRunnables(); + mLastTransition = null; + } + } + + @Override + public void onTransitionCancel(Transition transition) {} + + @Override + public void onTransitionStart(Transition transition) { + // Track the last transition, because we only want to run {@code + // mOnAllAnimationEnded} after all transitions end. + mLastTransition = transition; + } + + @Override + public void onTransitionPause(Transition transition) {} + + @Override + public void onTransitionResume(Transition transition) {} + }); + TransitionManager.beginDelayedTransition(mTransitionRoot, matchRecyclerView); updateRecyclerViewWidth(); }
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionToolbarCoordinator.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionToolbarCoordinator.java index 1dbf76a7..74ea6566 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionToolbarCoordinator.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionToolbarCoordinator.java
@@ -117,6 +117,9 @@ /** Shows the extensions menu programmatically. */ void showExtensionsMenu(); + /** Returns the {@link ToolbarWidthConsumer} for the popped out action. */ + ToolbarWidthConsumer getPoppedOutActionWidthConsumer(); + /** Returns the {@link ToolbarWidthConsumer} for the extensions menu icon. */ ToolbarWidthConsumer getMenuButtonWidthConsumer();
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionToolbarCoordinatorImpl.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionToolbarCoordinatorImpl.java index 311d2b9..d33e25b9e 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionToolbarCoordinatorImpl.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionToolbarCoordinatorImpl.java
@@ -50,6 +50,8 @@ private final MenuButtonWidthConsumer mMenuButtonWidthConsumer = new MenuButtonWidthConsumer(); private final ActionListWidthConsumer mActionListWidthConsumer = new ActionListWidthConsumer(); + private final PoppedOutActionWidthConsumer mPoppedOutActionWidthConsumer = + new PoppedOutActionWidthConsumer(); @Override public void initializeWithNative( @@ -139,6 +141,11 @@ } @Override + public PoppedOutActionWidthConsumer getPoppedOutActionWidthConsumer() { + return mPoppedOutActionWidthConsumer; + } + + @Override public ToolbarWidthConsumer getMenuButtonWidthConsumer() { return mMenuButtonWidthConsumer; } @@ -148,6 +155,27 @@ return mActionListWidthConsumer; } + private class PoppedOutActionWidthConsumer implements ToolbarWidthConsumer { + @Override + public boolean isVisible() { + return mExtensionActionListCoordinator.hasPoppedOutAction(); + } + + @Override + public int updateVisibility(int availableWidth) { + // Do not update the UI here just yet. We will leave that to {@link + // ActionListWidthConsumer}, which will be called but later because it has lower + // priority. + return mExtensionActionListCoordinator.setCanShowPoppedOutAction(availableWidth); + } + + @Override + public int updateVisibilityWithAnimation( + int availableWidth, Collection<Animator> animators) { + return updateVisibility(availableWidth); + } + } + private class MenuButtonWidthConsumer implements ToolbarWidthConsumer { @Override public boolean isVisible() {
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuCoordinator.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuCoordinator.java index 9136101e..6eb9cea 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuCoordinator.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuCoordinator.java
@@ -30,6 +30,7 @@ import org.chromium.chrome.browser.ui.theme.BrandedColorScheme; import org.chromium.components.embedder_support.util.UrlConstants; import org.chromium.content_public.browser.LoadUrlParams; +import org.chromium.content_public.browser.WebContents; import org.chromium.ui.base.PageTransition; import org.chromium.ui.listmenu.ListMenu; import org.chromium.ui.listmenu.ListMenuButton; @@ -299,7 +300,7 @@ } @Override - public void onActiveWebContentsChanged() { + public void onActiveWebContentsChanged(WebContents webContents) { updateButtonState(); }
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarTablet.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarTablet.java index a800ebc..bfb01cad 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarTablet.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarTablet.java
@@ -445,6 +445,8 @@ public void setExtensionToolbarCoordinator( ExtensionToolbarCoordinator extensionToolbarCoordinator) { mExtensionToolbarCoordinator = extensionToolbarCoordinator; + mToolbarWidthConsumers[ToolbarComponentId.POPPED_EXTENSION_ACTION] = + mExtensionToolbarCoordinator.getPoppedOutActionWidthConsumer(); mToolbarWidthConsumers[ToolbarComponentId.EXTENSIONS_MENU_BUTTON] = mExtensionToolbarCoordinator.getMenuButtonWidthConsumer(); mToolbarWidthConsumers[ToolbarComponentId.EXTENSION_ACTION_LIST] =
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarUtils.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarUtils.java index 4f354ef9..156ad8d4 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarUtils.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarUtils.java
@@ -36,6 +36,7 @@ ToolbarComponentId.MENU, ToolbarComponentId.TAB_SWITCHER, ToolbarComponentId.LOCATION_BAR_MINIMUM, + ToolbarComponentId.POPPED_EXTENSION_ACTION, ToolbarComponentId.BACK, ToolbarComponentId.INCOGNITO_INDICATOR, ToolbarComponentId.ADAPTIVE_BUTTON, @@ -78,6 +79,7 @@ ToolbarComponentId.OMNIBOX_LENS, ToolbarComponentId.ADAPTIVE_BUTTON, ToolbarComponentId.INCOGNITO_INDICATOR, + ToolbarComponentId.POPPED_EXTENSION_ACTION, ToolbarComponentId.EXTENSIONS_MENU_BUTTON, ToolbarComponentId.EXTENSION_ACTION_LIST, ToolbarComponentId.TAB_SWITCHER, @@ -102,13 +104,14 @@ int OMNIBOX_LENS = 11; int ADAPTIVE_BUTTON = 12; int INCOGNITO_INDICATOR = 13; - int EXTENSIONS_MENU_BUTTON = 14; - int EXTENSION_ACTION_LIST = 15; - int TAB_SWITCHER = 16; - int MENU = 17; - int PADDING = 18; - int SIGNIN_BUTTON = 19; - int COUNT = 20; + int POPPED_EXTENSION_ACTION = 14; + int EXTENSIONS_MENU_BUTTON = 15; + int EXTENSION_ACTION_LIST = 16; + int TAB_SWITCHER = 17; + int MENU = 18; + int PADDING = 19; + int SIGNIN_BUTTON = 20; + int COUNT = 21; } // LINT.ThenChange(//chrome/browser/ui/android/toolbar/java/res/layout/toolbar_tablet.xml:toolbar_tablet_components|//chrome/browser/ui/android/omnibox/java/res/layout/url_action_container.xml:toolbar_tablet_components)
diff --git a/chrome/browser/ui/ash/arc/arc_app_dialog_view/BUILD.gn b/chrome/browser/ui/ash/arc/arc_app_dialog_view/BUILD.gn index 5f0c200..068efc3 100644 --- a/chrome/browser/ui/ash/arc/arc_app_dialog_view/BUILD.gn +++ b/chrome/browser/ui/ash/arc/arc_app_dialog_view/BUILD.gn
@@ -10,7 +10,7 @@ public_deps = [ "//chrome/browser:browser_public_dependencies" ] deps = [ - "//chrome/app:generated_resources", + "//ash/strings", "//chrome/browser/ash/app_list", "//chrome/browser/ash/app_list/app_service", "//chrome/browser/ash/app_list/arc",
diff --git a/chrome/browser/ui/ash/arc/arc_app_dialog_view/DEPS b/chrome/browser/ui/ash/arc/arc_app_dialog_view/DEPS index a7f06e1..4ebf24c0 100644 --- a/chrome/browser/ui/ash/arc/arc_app_dialog_view/DEPS +++ b/chrome/browser/ui/ash/arc/arc_app_dialog_view/DEPS
@@ -6,7 +6,6 @@ # Existing dependencies within //chrome. There is an active effort to # refactor ash codes in //chrome to break these dependencies; see b/332804822. # Whenever possible, avoid adding new //chrome dependencies to this list. - "+chrome/grit", "+chrome/browser/apps/app_service", "+chrome/browser/ash/app_list", "+chrome/browser/ash/app_list/app_service",
diff --git a/chrome/browser/ui/ash/arc/arc_app_dialog_view/arc_app_dialog_view.cc b/chrome/browser/ui/ash/arc/arc_app_dialog_view/arc_app_dialog_view.cc index 5b2ef18..7a43216 100644 --- a/chrome/browser/ui/ash/arc/arc_app_dialog_view/arc_app_dialog_view.cc +++ b/chrome/browser/ui/ash/arc/arc_app_dialog_view/arc_app_dialog_view.cc
@@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "ash/strings/grit/ash_strings.h" #include "base/functional/bind.h" #include "base/memory/raw_ptr.h" #include "base/strings/utf_string_conversions.h" @@ -12,7 +13,6 @@ #include "chrome/browser/ash/app_list/arc/arc_app_utils.h" #include "chrome/browser/ash/app_list/arc/arc_usb_host_permission_manager.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/grit/generated_resources.h" #include "components/constrained_window/constrained_window_views.h" #include "components/strings/grit/components_strings.h" #include "ui/base/l10n/l10n_util.h"
diff --git a/chrome/browser/ui/ash/arc/arc_data_removal_dialog_view/BUILD.gn b/chrome/browser/ui/ash/arc/arc_data_removal_dialog_view/BUILD.gn index 0b7273c..e7b8b06 100644 --- a/chrome/browser/ui/ash/arc/arc_data_removal_dialog_view/BUILD.gn +++ b/chrome/browser/ui/ash/arc/arc_data_removal_dialog_view/BUILD.gn
@@ -10,6 +10,7 @@ public_deps = [ "//chrome/browser:browser_public_dependencies" ] deps = [ + "//ash/strings", "//chrome/browser/ash/app_list/app_service", "//chrome/browser/ash/app_list/arc", "//chrome/browser/ash/arc/session",
diff --git a/chrome/browser/ui/ash/arc/arc_data_removal_dialog_view/arc_data_removal_dialog_view.cc b/chrome/browser/ui/ash/arc/arc_data_removal_dialog_view/arc_data_removal_dialog_view.cc index 3011e428..d25bde3 100644 --- a/chrome/browser/ui/ash/arc/arc_data_removal_dialog_view/arc_data_removal_dialog_view.cc +++ b/chrome/browser/ui/ash/arc/arc_data_removal_dialog_view/arc_data_removal_dialog_view.cc
@@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "ash/strings/grit/ash_strings.h" #include "base/memory/raw_ptr.h" #include "chrome/browser/ash/app_list/app_service/app_service_app_icon_loader.h" #include "chrome/browser/ash/app_list/arc/arc_data_removal_dialog.h" #include "chrome/browser/ash/arc/session/arc_session_manager.h" #include "chrome/browser/ash/arc/session/arc_session_manager_observer.h" -#include "chrome/grit/generated_resources.h" #include "chromeos/ash/experiences/arc/app/arc_app_constants.h" #include "components/constrained_window/constrained_window_views.h" #include "components/strings/grit/components_strings.h"
diff --git a/chrome/browser/ui/ash/login/login_display_host_common.cc b/chrome/browser/ui/ash/login/login_display_host_common.cc index 3c6f819..4b79eba1 100644 --- a/chrome/browser/ui/ash/login/login_display_host_common.cc +++ b/chrome/browser/ui/ash/login/login_display_host_common.cc
@@ -333,7 +333,7 @@ void LoginDisplayHostCommon::StartKiosk(const KioskAppId& kiosk_app_id, bool is_auto_launch) { VLOG(1) << "Login >> start kiosk of type " - << static_cast<int>(kiosk_app_id.type); + << std::to_underlying(kiosk_app_id.type); SetKioskLaunchStateCrashKey(KioskLaunchState::kAttemptToLaunch); @@ -546,7 +546,7 @@ // Force the TPM firmware update option to be enabled. local_state_->SetInteger( ash::prefs::kFactoryResetTPMFirmwareUpdateMode, - static_cast<int>(tpm_firmware_update_mode.value())); + std::to_underlying(tpm_firmware_update_mode.value())); } StartWizard(ResetView::kScreenId); } @@ -626,7 +626,7 @@ void LoginDisplayHostCommon::ShowSigninError(SigninError error, const std::string& details) { - VLOG(1) << "Show error, error_id: " << static_cast<int>(error); + VLOG(1) << "Show error, error_id: " << std::to_underlying(error); if (error == SigninError::kKnownUserFailedNetworkNotConnected || error == SigninError::kKnownUserFailedNetworkConnected) {
diff --git a/chrome/browser/ui/ash/login/login_display_host_webui.cc b/chrome/browser/ui/ash/login/login_display_host_webui.cc index adc47463..b97a2e0 100644 --- a/chrome/browser/ui/ash/login/login_display_host_webui.cc +++ b/chrome/browser/ui/ash/login/login_display_host_webui.cc
@@ -531,7 +531,7 @@ audio::SoundsManager* manager = audio::SoundsManager::Get(); ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); - manager->Initialize(static_cast<int>(Sound::kStartup), + manager->Initialize(std::to_underlying(Sound::kStartup), bundle.GetRawDataResource(IDR_SOUND_STARTUP_WAV), media::AudioCodec::kPCM); }
diff --git a/chrome/browser/ui/ash/login/login_screen_client_impl.cc b/chrome/browser/ui/ash/login/login_screen_client_impl.cc index 8f61658..c0972e357 100644 --- a/chrome/browser/ui/ash/login/login_screen_client_impl.cc +++ b/chrome/browser/ui/ash/login/login_screen_client_impl.cc
@@ -324,8 +324,8 @@ {chromeos::settings::mojom::kSecurityAndSignInSubpagePathV2, "?settingId=", base::NumberToString( - static_cast<int>(chromeos::settings::mojom::Setting:: - kLockScreenNotification))})}); + std::to_underlying(chromeos::settings::mojom::Setting:: + kLockScreenNotification))})}); } void LoginScreenClientImpl::OnFocusLeavingSystemTray(bool reverse) { @@ -442,8 +442,8 @@ // to remove the DumpWithoutCrashing if the number of reports will be low. base::debug::DumpWithoutCrashing(); LOG(WARNING) << __func__ << ": ignoring the call, session state: " - << static_cast<int>(session_manager::SessionManager::Get() - ->session_state()); + << std::to_underlying(session_manager::SessionManager::Get() + ->session_state()); } }
diff --git a/chrome/browser/ui/autofill/autofill_field_promo_controller_impl.cc b/chrome/browser/ui/autofill/autofill_field_promo_controller_impl.cc index c6b7bab..058d9b50 100644 --- a/chrome/browser/ui/autofill/autofill_field_promo_controller_impl.cc +++ b/chrome/browser/ui/autofill/autofill_field_promo_controller_impl.cc
@@ -75,10 +75,7 @@ params.show_promo_result_callback = base::BindOnce(&AutofillFieldPromoControllerImpl::OnShowPromoResult, weak_ptr_factory_.GetWeakPtr()); - if (interface->CanShowFeaturePromo(feature_promo_.get())) { - is_maybe_showing_ = true; - interface->MaybeShowFeaturePromo(std::move(params)); - } + is_maybe_showing_ = interface->MaybeShowFeaturePromo(std::move(params)); } void AutofillFieldPromoControllerImpl::Hide() {
diff --git a/chrome/browser/ui/autofill/autofill_field_promo_controller_impl_unittest.cc b/chrome/browser/ui/autofill/autofill_field_promo_controller_impl_unittest.cc index d8dd609..29340fda 100644 --- a/chrome/browser/ui/autofill/autofill_field_promo_controller_impl_unittest.cc +++ b/chrome/browser/ui/autofill/autofill_field_promo_controller_impl_unittest.cc
@@ -127,8 +127,6 @@ TEST_F(AutofillFieldPromoControllerImplTest, CloseViewOnFailingMaybeShowPromo) { auto promo_view = std::make_unique<MockAutofillFieldPromoView>(); - EXPECT_CALL(*user_education(), CanShowFeaturePromo) - .WillOnce(testing::Return(user_education::FeaturePromoResult::Success())); EXPECT_CALL(*user_education(), MaybeShowFeaturePromo) .WillOnce([this, promo_view_ptr = promo_view->GetWeakPtr()]( user_education::FeaturePromoParams params) { @@ -136,6 +134,7 @@ promo_view_ptr); std::move(params.show_promo_result_callback) .Run(user_education::FeaturePromoResult::kError); + return false; }); EXPECT_CALL(*promo_view, MakeInvisible()); @@ -155,10 +154,8 @@ // Makes sure the promo is not hidden immediately after being shown. // This also makes sure that `AutofillFieldPromoControllerImpl::Show()` // reaches `MaybeShowFeaturePromo()` and, therefore, doesn't return early. - EXPECT_CALL(*user_education(), CanShowFeaturePromo) - .WillOnce( - testing::Return(user_education::FeaturePromoResult::Success())); - EXPECT_CALL(*user_education(), MaybeShowFeaturePromo).Times(1); + EXPECT_CALL(*user_education(), MaybeShowFeaturePromo) + .WillOnce(testing::Return(true)); autofill_field_promo_controller()->Show(gfx::RectF(0, 0, 1, 1)); autofill_field_promo_controller()->SetPromoViewForTesting( promo_view_->GetWeakPtr());
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc b/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc index 701ffe5..7f1725d 100644 --- a/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc +++ b/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc
@@ -81,6 +81,8 @@ kTriggerSourcesExemptFromTimeReset = { AutofillSuggestionTriggerSource::kPlusAddressUpdatedInBrowserProcess}; +// TODO(crbug.com/491834951) Replace `SuggestionFiltrationResult` pair with +// struct. using SuggestionFiltrationResult = std::pair<std::vector<Suggestion>, std::vector<AutofillPopupController::SuggestionFilterMatch>>; @@ -89,6 +91,13 @@ const AutofillPopupController::SuggestionFilter& filter) { SuggestionFiltrationResult result; + auto add_suggestion_filtration_result = + [&result](const Suggestion& suggestion, + gfx::Range main_text_match = gfx::Range()) { + result.first.push_back(suggestion); + result.second.emplace_back(main_text_match); + }; + std::optional<std::u16string> lower_string_filter = std::holds_alternative<AutofillPopupController::StringFilter>(filter) ? std::optional(base::i18n::ToLower( @@ -100,17 +109,18 @@ continue; } else if (suggestion.filtration_policy == Suggestion::FiltrationPolicy::kStatic) { - result.first.push_back(suggestion); - result.second.emplace_back(); + add_suggestion_filtration_result(suggestion); } else if (lower_string_filter) { if (size_t pos = base::i18n::ToLower(suggestion.main_text.value) .find(lower_string_filter.value()); pos != std::u16string::npos) { - result.first.push_back(suggestion); - result.second.push_back(AutofillPopupController::SuggestionFilterMatch{ - .main_text_match = {pos, - pos + lower_string_filter.value().size()}}); + add_suggestion_filtration_result( + suggestion, + gfx::Range(pos, pos + lower_string_filter.value().size())); } + } else if (std::holds_alternative<SuggestionTabIndex>(filter) && + std::get<SuggestionTabIndex>(filter) == suggestion.tab_index) { + add_suggestion_filtration_result(suggestion); } }
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_impl_unittest.cc b/chrome/browser/ui/autofill/autofill_popup_controller_impl_unittest.cc index 70e7448..23e058f 100644 --- a/chrome/browser/ui/autofill/autofill_popup_controller_impl_unittest.cc +++ b/chrome/browser/ui/autofill/autofill_popup_controller_impl_unittest.cc
@@ -13,6 +13,7 @@ #include "chrome/browser/ui/autofill/autofill_suggestion_controller_test_base.h" #include "chrome/browser/ui/autofill/test_autofill_popup_controller_autofill_client.h" #include "components/autofill/core/browser/country_type.h" +#include "components/autofill/core/browser/payments/constants.h" #include "components/autofill/core/browser/suggestions/suggestion.h" #include "components/autofill/core/browser/suggestions/suggestion_type.h" #include "components/autofill/core/browser/ui/popup_interaction.h" @@ -695,6 +696,37 @@ } TEST_F(AutofillPopupControllerImplTest, + SuggestionFiltering_SuggestionsAreFilteredByTabIndex) { + Suggestion pay_later_tab_suggestion = Suggestion(SuggestionType::kBnplEntry); + pay_later_tab_suggestion.tab_index = kPayLaterSuggestionTabIndex; + Suggestion pay_later_tab_footer = Suggestion(SuggestionType::kBnplFootnote); + pay_later_tab_footer.tab_index = kPayLaterSuggestionTabIndex; + + AutofillPopupController& controller = + client().suggestion_controller(manager()); + ShowSuggestions(manager(), { + Suggestion(SuggestionType::kCreditCardEntry), + std::move(pay_later_tab_suggestion), + std::move(pay_later_tab_footer), + }); + + ASSERT_EQ(controller.GetSuggestions().size(), 3u); + + controller.SetFilter(kDefaultSuggestionTabIndex); + EXPECT_EQ(controller.GetSuggestions().size(), 1u); + EXPECT_THAT( + controller.GetSuggestions(), + ElementsAre(Field(&Suggestion::type, SuggestionType::kCreditCardEntry))); + + controller.SetFilter(kPayLaterSuggestionTabIndex); + EXPECT_EQ(controller.GetSuggestions().size(), 2u); + EXPECT_THAT( + controller.GetSuggestions(), + ElementsAre(Field(&Suggestion::type, SuggestionType::kBnplEntry), + Field(&Suggestion::type, SuggestionType::kBnplFootnote))); +} + +TEST_F(AutofillPopupControllerImplTest, SuggestionFiltering_HasFilteredOutSuggestions) { using enum SuggestionType;
diff --git a/chrome/browser/ui/browser_actions.cc b/chrome/browser/ui/browser_actions.cc index f1ecec88..a2c424f 100644 --- a/chrome/browser/ui/browser_actions.cc +++ b/chrome/browser/ui/browser_actions.cc
@@ -1524,6 +1524,30 @@ .Build()); } + // Registration of Gemini in Chrome Anchored Cues, but requires call-time + // configuration to update the label, button text, and suggested prompt. As + // such, this action is disabled upon registration, and enabled at call time + // by OnTriggerAnchoredMessage(). + if (glic_service) { + root_action_item_->AddChild( + actions::ActionItem::Builder( + base::BindRepeating([](actions::ActionItem* item, + actions::ActionInvocationContext context) { + DUMP_WILL_BE_NOTREACHED() + << "Contextual cueing action invoked without being " + "configured by OnTriggerAnchoredMessage"; + })) + .SetActionId(kActionGlicContextualCueing) + .SetEnabled(false) + .SetVisible(false) + .SetText(l10n_util::GetStringUTF16(IDS_SETTINGS_GLIC_PAGE_TITLE)) + .SetImage(ui::ImageModel::FromVectorIcon( + glic::GlicVectorIconManager::GetVectorIcon( + IDR_GLIC_BUTTON_VECTOR_ICON), + ui::kColorIcon)) + .Build()); + } + root_action_item_->AddChild( actions::ActionItem::Builder( base::BindRepeating(
diff --git a/chrome/browser/ui/browser_ui_prefs.cc b/chrome/browser/ui/browser_ui_prefs.cc index 771d846..25d238a 100644 --- a/chrome/browser/ui/browser_ui_prefs.cc +++ b/chrome/browser/ui/browser_ui_prefs.cc
@@ -122,6 +122,8 @@ registry->RegisterBooleanPref(prefs::kShowForwardButton, true, pref_registration_flags); + registry->RegisterInt64Pref(prefs::kBookmarkBarHoverCount, 0); + registry->RegisterInt64Pref(prefs::kBookmarkBarNavigationCount, 0); registry->RegisterBooleanPref(prefs::kPinContextualTaskButton, true, pref_registration_flags); registry->RegisterBooleanPref(prefs::kPinSplitTabButton, false,
diff --git a/chrome/browser/ui/browser_window/internal/BUILD.gn b/chrome/browser/ui/browser_window/internal/BUILD.gn index 255577f..2737471 100644 --- a/chrome/browser/ui/browser_window/internal/BUILD.gn +++ b/chrome/browser/ui/browser_window/internal/BUILD.gn
@@ -103,7 +103,7 @@ "//chrome/browser/ui/views/send_tab_to_self", "//chrome/browser/ui/views/side_panel", "//chrome/browser/ui/views/toolbar", - "//chrome/browser/ui/waap", + "//chrome/browser/ui/waap:manager", "//chrome/browser/ui/waap:window_metrics_manager", "//chrome/browser/ui/web_applications", "//chrome/browser/ui/web_applications:launch_utils",
diff --git a/chrome/browser/ui/desktop_to_mobile_promos/ios_promo_controller_browsertest.cc b/chrome/browser/ui/desktop_to_mobile_promos/ios_promo_controller_browsertest.cc index e59b2d8..0130987 100644 --- a/chrome/browser/ui/desktop_to_mobile_promos/ios_promo_controller_browsertest.cc +++ b/chrome/browser/ui/desktop_to_mobile_promos/ios_promo_controller_browsertest.cc
@@ -154,7 +154,7 @@ views::test::WaitForWidgetActive(widget, true); EXPECT_CALL(*mock_user_education_interface(), MaybeShowFeaturePromo(_)) - .Times(1); + .WillOnce(testing::Return(true)); // Trigger the promo. promo_service()->NotifyPromoShouldBeShown(PromoType::kPassword);
diff --git a/chrome/browser/ui/extensions/BUILD.gn b/chrome/browser/ui/extensions/BUILD.gn index 9ed9419..02d6b4b 100644 --- a/chrome/browser/ui/extensions/BUILD.gn +++ b/chrome/browser/ui/extensions/BUILD.gn
@@ -47,6 +47,7 @@ public_deps += [ ":extension_popup_types", "//base", + "//chrome/browser/download", "//chrome/browser/tab_list", "//chrome/browser/ui/browser_window", "//chrome/browser/ui/toolbar", @@ -131,6 +132,7 @@ sources += [ "controlled_home_dialog.cc", "controlled_home_dialog_controller.cc", + "download_danger_dialog.cc", "download_open_dialog.cc", "extension_action_view_model.cc", "extension_install_ask_parent_dialog.cc", @@ -154,6 +156,7 @@ "//chrome/browser/image_fetcher", "//chrome/browser/profiles:profile", "//chrome/browser/profiles:profile_util", + "//chrome/browser/safe_browsing:advanced_protection", "//chrome/browser/signin", "//chrome/browser/tab_list", "//chrome/browser/ui/browser_window",
diff --git a/chrome/browser/ui/extensions/download_danger_dialog.cc b/chrome/browser/ui/extensions/download_danger_dialog.cc new file mode 100644 index 0000000..bca61592 --- /dev/null +++ b/chrome/browser/ui/extensions/download_danger_dialog.cc
@@ -0,0 +1,221 @@ +// Copyright 2026 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <memory> +#include <utility> + +#include "base/functional/callback.h" +#include "base/memory/raw_ptr.h" +#include "base/memory/weak_ptr.h" +#include "base/notreached.h" +#include "base/task/single_thread_task_runner.h" +#include "chrome/browser/download/download_danger_prompt.h" +#include "chrome/browser/profiles/profile.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/ui/extensions/extension_dialog_utils.h" +#include "chrome/browser/ui/extensions/extensions_dialogs.h" +#include "chrome/grit/branded_strings.h" +#include "chrome/grit/generated_resources.h" +#include "components/download/public/common/download_item.h" +#include "components/strings/grit/components_strings.h" +#include "content/public/browser/web_contents.h" +#include "extensions/buildflags/buildflags.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/models/dialog_model.h" + +static_assert(BUILDFLAG(ENABLE_EXTENSIONS_CORE)); + +namespace { + +// A delegate for the danger prompt dialog shown when an extension tries to +// download a dangerous file. It observes the download item and dismisses the +// dialog if the download is no longer relevant. +class DownloadDangerDialogDelegate : public ui::DialogModelDelegate, + public download::DownloadItem::Observer { + public: + DownloadDangerDialogDelegate( + download::DownloadItem* download, + base::OnceCallback<void(DownloadDangerPrompt::Action)> callback); + DownloadDangerDialogDelegate(const DownloadDangerDialogDelegate&) = delete; + const DownloadDangerDialogDelegate& operator=( + const DownloadDangerDialogDelegate&) = delete; + ~DownloadDangerDialogDelegate() override; + + std::u16string GetMessageBody(Profile* profile) const; + void DismissDialog(); + + void OnDialogAccepted(); + void OnDialogCanceled(); + void OnDialogClosed(); + + // download::DownloadItem::Observer: + void OnDownloadUpdated(download::DownloadItem* download) override; + void OnDownloadRemoved(download::DownloadItem* download) override; + void OnDownloadDestroyed(download::DownloadItem* download) override; + + private: + // Stops observing the download item and clears the pointer. This is called + // when the dialog is being closed or the download is no longer relevant, + // ensuring no further observer notifications are processed. + void DetachFromDownload(); + + raw_ptr<download::DownloadItem> download_; + base::OnceCallback<void(DownloadDangerPrompt::Action)> callback_; +}; + +DownloadDangerDialogDelegate::DownloadDangerDialogDelegate( + download::DownloadItem* download, + base::OnceCallback<void(DownloadDangerPrompt::Action)> callback) + : download_(download), callback_(std::move(callback)) { + if (download_) { + download_->AddObserver(this); + } +} + +DownloadDangerDialogDelegate::~DownloadDangerDialogDelegate() { + DetachFromDownload(); +} + +std::u16string DownloadDangerDialogDelegate::GetMessageBody( + Profile* profile) const { + if (!download_) { + return std::u16string(); + } + + std::u16string filename = + download_->GetFileNameToReportUser().LossyDisplayName(); + switch (download_->GetDangerType()) { + case download::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE: + return l10n_util::GetStringFUTF16(IDS_PROMPT_DANGEROUS_DOWNLOAD, + filename); + case download::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL: + case download::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT: + case download::DOWNLOAD_DANGER_TYPE_DANGEROUS_ACCOUNT_COMPROMISE: + case download::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: + return l10n_util::GetStringFUTF16(IDS_PROMPT_MALICIOUS_DOWNLOAD_CONTENT, + filename); + case download::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT: + return l10n_util::GetStringFUTF16( + safe_browsing::AdvancedProtectionStatusManagerFactory::GetForProfile( + profile) + ->IsUnderAdvancedProtection() + ? IDS_PROMPT_UNCOMMON_DOWNLOAD_CONTENT_IN_ADVANCED_PROTECTION + : IDS_PROMPT_UNCOMMON_DOWNLOAD_CONTENT, + filename); + case download::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED: + return l10n_util::GetStringFUTF16(IDS_PROMPT_DOWNLOAD_CHANGES_SETTINGS, + filename); + default: + NOTREACHED(); + } +} + +void DownloadDangerDialogDelegate::DismissDialog() { + DetachFromDownload(); + if (callback_) { + std::move(callback_).Run(DownloadDangerPrompt::Action::DISMISS); + } + dialog_model()->host()->Close(); +} + +void DownloadDangerDialogDelegate::OnDialogAccepted() { + DetachFromDownload(); + // Accepting the dialog (the "OK" button) corresponds to the "Cancel" action + // for the download. + std::move(callback_).Run(DownloadDangerPrompt::Action::CANCEL); +} + +void DownloadDangerDialogDelegate::OnDialogCanceled() { + DetachFromDownload(); + // Canceling the dialog (the "Cancel" button) corresponds to the "Accept" + // action for the download. + std::move(callback_).Run(DownloadDangerPrompt::Action::ACCEPT); +} + +void DownloadDangerDialogDelegate::OnDialogClosed() { + if (callback_) { + std::move(callback_).Run(DownloadDangerPrompt::Action::DISMISS); + } +} + +void DownloadDangerDialogDelegate::OnDownloadUpdated( + download::DownloadItem* download) { + if (!download_ || !download->IsDangerous() || download->IsDone()) { + DismissDialog(); + } +} + +void DownloadDangerDialogDelegate::OnDownloadRemoved( + download::DownloadItem* download) { + DismissDialog(); +} + +void DownloadDangerDialogDelegate::OnDownloadDestroyed( + download::DownloadItem* download) { + DismissDialog(); +} + +void DownloadDangerDialogDelegate::DetachFromDownload() { + if (download_) { + download_->RemoveObserver(this); + download_ = nullptr; + } +} + +} // namespace + +namespace extensions { + +DEFINE_ELEMENT_IDENTIFIER_VALUE(kDownloadDangerDialogCancelButtonElementId); +DEFINE_ELEMENT_IDENTIFIER_VALUE(kDownloadDangerDialogKeepButtonElementId); + +void ShowDownloadDangerDialog( + download::DownloadItem* download_item, + content::WebContents* web_contents, + base::OnceCallback<void(DownloadDangerPrompt::Action)> done_callback) { + auto dialog_delegate_unique = std::make_unique<DownloadDangerDialogDelegate>( + download_item, std::move(done_callback)); + DownloadDangerDialogDelegate* dialog_delegate = dialog_delegate_unique.get(); + + Profile* profile = + Profile::FromBrowserContext(web_contents->GetBrowserContext()); + + std::unique_ptr<ui::DialogModel> dialog = + ui::DialogModel::Builder(std::move(dialog_delegate_unique)) + .SetTitle(l10n_util::GetStringUTF16( + IDS_CONFIRM_KEEP_DANGEROUS_DOWNLOAD_TITLE)) + // The "OK" button is the default action for the dialog. We use it for + // "Cancel" so that it is the default focused button, encouraging the + // safer choice. + .AddOkButton( + base::BindOnce(&DownloadDangerDialogDelegate::OnDialogAccepted, + base::Unretained(dialog_delegate)), + ui::DialogModel::Button::Params() + .SetLabel(l10n_util::GetStringUTF16(IDS_CANCEL)) + .SetId(kDownloadDangerDialogCancelButtonElementId)) + // The "Cancel" button is used for the "Keep" action so that it is + // not the default focused choice, reducing the risk of accidental + // acceptance. + .AddCancelButton( + base::BindOnce(&DownloadDangerDialogDelegate::OnDialogCanceled, + base::Unretained(dialog_delegate)), + ui::DialogModel::Button::Params() + .SetLabel(l10n_util::GetStringUTF16(IDS_CONFIRM_DOWNLOAD)) + .SetId(kDownloadDangerDialogKeepButtonElementId)) + .SetCloseActionCallback( + base::BindOnce(&DownloadDangerDialogDelegate::OnDialogClosed, + base::Unretained(dialog_delegate))) + .SetDialogDestroyingCallback( + base::BindOnce(&DownloadDangerDialogDelegate::OnDialogClosed, + base::Unretained(dialog_delegate))) + .OverrideShowCloseButton(/*show_close_button=*/false) + .AddParagraph( + ui::DialogModelLabel(dialog_delegate->GetMessageBody(profile))) + .Build(); + + ShowWebModalDialog(web_contents, std::move(dialog)); +} + +} // namespace extensions
diff --git a/chrome/browser/ui/extensions/download_danger_dialog_interactive_uitest.cc b/chrome/browser/ui/extensions/download_danger_dialog_interactive_uitest.cc new file mode 100644 index 0000000..c498e99 --- /dev/null +++ b/chrome/browser/ui/extensions/download_danger_dialog_interactive_uitest.cc
@@ -0,0 +1,117 @@ +// Copyright 2026 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <optional> + +#include "base/functional/bind.h" +#include "chrome/browser/download/download_danger_prompt.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/extensions/extensions_dialogs.h" +#include "chrome/test/interaction/interactive_browser_test.h" +#include "components/download/public/common/mock_download_item.h" +#include "content/public/test/browser_test.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "ui/base/interaction/element_identifier.h" +#include "ui/views/window/dialog_client_view.h" + +namespace extensions { + +using ::testing::Return; +using ::testing::ReturnRef; + +class DownloadDangerDialogInteractiveTest : public InteractiveBrowserTest { + public: + DownloadDangerDialogInteractiveTest() = default; + ~DownloadDangerDialogInteractiveTest() override = default; + + void SetUpOnMainThread() override { + InteractiveBrowserTest::SetUpOnMainThread(); + + // Set up basic mock expectations so the dialog can read the danger type + // and format the warning string correctly. + ON_CALL(mock_download_item_, GetFileNameToReportUser()) + .WillByDefault(Return(base::FilePath(FILE_PATH_LITERAL("evil.exe")))); + ON_CALL(mock_download_item_, GetDangerType()) + .WillByDefault(Return(download::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE)); + ON_CALL(mock_download_item_, IsDangerous()).WillByDefault(Return(true)); + } + + protected: + // Helper to trigger the dialog and capture the resulting Action. + auto ShowDialog() { + return Do([this]() { + dialog_result_.reset(); + ShowDownloadDangerDialog( + &mock_download_item_, + browser()->tab_strip_model()->GetActiveWebContents(), + base::BindOnce(&DownloadDangerDialogInteractiveTest::OnDialogResolved, + base::Unretained(this))); + }); + } + + // A custom Kombucha check to verify the callback result. + auto CheckResult(DownloadDangerPrompt::Action expected_action) { + return Check( + [this, expected_action]() { + return dialog_result_.has_value() && + dialog_result_.value() == expected_action; + }, + "Verify dialog callback result matches expected action."); + } + + testing::NiceMock<download::MockDownloadItem> mock_download_item_; + std::optional<DownloadDangerPrompt::Action> dialog_result_; + + private: + void OnDialogResolved(DownloadDangerPrompt::Action action) { + dialog_result_ = action; + } +}; + +// Tests that clicking the button labeled "Confirm Download" (which is wired +// to the DialogModel's Cancel button) results in the ACCEPT action. +IN_PROC_BROWSER_TEST_F(DownloadDangerDialogInteractiveTest, + ClickingKeepAcceptsDanger) { + RunTestSequence( + ShowDialog(), + // Wait for the dialog to appear by waiting for its button. + WaitForShow(kDownloadDangerDialogKeepButtonElementId), + // Press the button (which we labeled "Confirm Download"). + PressButton(kDownloadDangerDialogKeepButtonElementId), + // Ensure the dialog disappears. + WaitForHide(kDownloadDangerDialogKeepButtonElementId), + // Verify the extension API backend receives the ACCEPT signal. + CheckResult(DownloadDangerPrompt::Action::ACCEPT)); +} + +// Tests that clicking the button labeled "Cancel" (which is wired +// to the DialogModel's OK button) results in the CANCEL action. +IN_PROC_BROWSER_TEST_F(DownloadDangerDialogInteractiveTest, + ClickingCancelRejectsDanger) { + RunTestSequence( + ShowDialog(), + // Wait for the dialog to appear by waiting for its button. + WaitForShow(kDownloadDangerDialogCancelButtonElementId), + // Press the button (which we labeled "Cancel"). + PressButton(kDownloadDangerDialogCancelButtonElementId), + // Ensure the dialog disappears. + WaitForHide(kDownloadDangerDialogCancelButtonElementId), + // Verify the extension API backend receives the CANCEL signal. + CheckResult(DownloadDangerPrompt::Action::CANCEL)); +} + +// Tests that removing the DownloadItem while the dialog is open +// results in the DISMISS action and closes the dialog. +IN_PROC_BROWSER_TEST_F(DownloadDangerDialogInteractiveTest, + DownloadDestroyedDismissesDanger) { + RunTestSequence( + ShowDialog(), WaitForShow(kDownloadDangerDialogKeepButtonElementId), + Do([this]() { mock_download_item_.NotifyObserversDownloadRemoved(); }), + WaitForHide(kDownloadDangerDialogKeepButtonElementId), + CheckResult(DownloadDangerPrompt::Action::DISMISS)); +} + +} // namespace extensions
diff --git a/chrome/browser/ui/extensions/extensions_dialogs.h b/chrome/browser/ui/extensions/extensions_dialogs.h index 98ac8628..607d3f34 100644 --- a/chrome/browser/ui/extensions/extensions_dialogs.h +++ b/chrome/browser/ui/extensions/extensions_dialogs.h
@@ -10,6 +10,7 @@ #include "base/functional/callback_forward.h" #include "build/build_config.h" +#include "chrome/browser/download/download_danger_prompt.h" #include "chrome/browser/ui/extensions/mv2_disabled_dialog_controller.h" #include "extensions/buildflags/buildflags.h" #include "extensions/common/extension_id.h" @@ -38,6 +39,10 @@ class ProtocolHandler; } // namespace custom_handlers +namespace download { +class DownloadItem; +} // namespace download + namespace gfx { class ImageSkia; } // namespace gfx @@ -55,6 +60,8 @@ class Extension; DECLARE_ELEMENT_IDENTIFIER_VALUE(kControlledHomeDialogCancelButtonElementId); +DECLARE_ELEMENT_IDENTIFIER_VALUE(kDownloadDangerDialogCancelButtonElementId); +DECLARE_ELEMENT_IDENTIFIER_VALUE(kDownloadDangerDialogKeepButtonElementId); DECLARE_ELEMENT_IDENTIFIER_VALUE(kExtensionInstallFrictionLearnMoreLink); DECLARE_ELEMENT_IDENTIFIER_VALUE(kMv2DisabledDialogManageButtonElementId); DECLARE_ELEMENT_IDENTIFIER_VALUE(kMv2DisabledDialogParagraphElementId); @@ -97,6 +104,14 @@ const base::FilePath& file_path, base::OnceCallback<void(bool)> open_callback); +// Shows a dialog that prompts the user for whether to accept a dangerous +// DownloadItem using native UI. This step is necessary to prevent a malicious +// extension from accepting a dangerous download. +void ShowDownloadDangerDialog( + download::DownloadItem* download_item, + content::WebContents* web_contents, + base::OnceCallback<void(DownloadDangerPrompt::Action)> done_callback); + // Shows a modal dialog to Enhanced Safe Browsing users before the extension // install dialog if the extension is not included in the Safe Browsing CRX // allowlist. `callback` will be invoked with `true` if the user accepts or
diff --git a/chrome/browser/ui/extensions/extensions_toolbar_view_model.cc b/chrome/browser/ui/extensions/extensions_toolbar_view_model.cc index 023f31bc..8fbaecf 100644 --- a/chrome/browser/ui/extensions/extensions_toolbar_view_model.cc +++ b/chrome/browser/ui/extensions/extensions_toolbar_view_model.cc
@@ -303,7 +303,8 @@ return; } for (Observer& obs : observers_) { - obs.OnActiveWebContentsChanged(handle->IsSameDocument()); + obs.OnActiveWebContentsChanged(handle->IsSameDocument(), + handle->GetWebContents()); } } @@ -312,7 +313,7 @@ content::WebContents* contents = tab->GetContents(); WebContentsObserver::Observe(contents); for (Observer& obs : observers_) { - obs.OnActiveWebContentsChanged(/*is_same_document=*/false); + obs.OnActiveWebContentsChanged(/*is_same_document=*/false, contents); } }
diff --git a/chrome/browser/ui/extensions/extensions_toolbar_view_model.h b/chrome/browser/ui/extensions/extensions_toolbar_view_model.h index 31b4a0b..b18f9c0 100644 --- a/chrome/browser/ui/extensions/extensions_toolbar_view_model.h +++ b/chrome/browser/ui/extensions/extensions_toolbar_view_model.h
@@ -39,8 +39,6 @@ const ToolbarActionsModel::ActionId& action_id, ExtensionsContainer* extensions_container) = 0; // Hides any actively showing popups. - // TODO(crbug.com/473701535): Determine whether this method belongs in the - // delegate or the observer. virtual void HideActivePopup() = 0; // Closes the overflow menu, if it was open. Returns whether or not the @@ -85,7 +83,9 @@ // Called when the active WebContents is changed (e.g. tab change or page // navigation). `is_same_document` is true if the change was due to a // same-document navigation. - virtual void OnActiveWebContentsChanged(bool is_same_document) = 0; + virtual void OnActiveWebContentsChanged( + bool is_same_document, + content::WebContents* web_contents) = 0; // Called when the extensions that should be displayed in the request // access button to be recomputed.
diff --git a/chrome/browser/ui/extensions/extensions_toolbar_view_model_browsertest.cc b/chrome/browser/ui/extensions/extensions_toolbar_view_model_browsertest.cc index 714b549..29305719 100644 --- a/chrome/browser/ui/extensions/extensions_toolbar_view_model_browsertest.cc +++ b/chrome/browser/ui/extensions/extensions_toolbar_view_model_browsertest.cc
@@ -99,7 +99,10 @@ (const ToolbarActionsModel::ActionId&), (override)); MOCK_METHOD(void, OnPinnedActionsChanged, (), (override)); - MOCK_METHOD(void, OnActiveWebContentsChanged, (bool), (override)); + MOCK_METHOD(void, + OnActiveWebContentsChanged, + (bool, content::WebContents*), + (override)); }; } // namespace @@ -311,7 +314,7 @@ // Tests that the observer is notified when navigation happens. IN_PROC_BROWSER_TEST_F(ExtensionsToolbarViewModelBrowserTest, ObserverCalledOnNavigation) { - EXPECT_CALL(mock_observer(), OnActiveWebContentsChanged(_)) + EXPECT_CALL(mock_observer(), OnActiveWebContentsChanged(_, _)) .Times(testing::AtLeast(1)); NavigateTo("example.com"); @@ -320,7 +323,7 @@ // Tests that the observer is notified when the active tab changes. IN_PROC_BROWSER_TEST_F(ExtensionsToolbarViewModelBrowserTest, ObserverCalledOnActiveTabChanged) { - EXPECT_CALL(mock_observer(), OnActiveWebContentsChanged(_)) + EXPECT_CALL(mock_observer(), OnActiveWebContentsChanged(_, _)) .Times(testing::AtLeast(1)); TabListInterface* tab_list =
diff --git a/chrome/browser/ui/find_bar/BUILD.gn b/chrome/browser/ui/find_bar/BUILD.gn index 806a40f..1e3ef68 100644 --- a/chrome/browser/ui/find_bar/BUILD.gn +++ b/chrome/browser/ui/find_bar/BUILD.gn
@@ -77,6 +77,7 @@ deps = [ ":find_bar", + "//chrome/browser/ui:ui_features", "//chrome/browser/ui/browser_window", "//chrome/test:test_support", ]
diff --git a/chrome/browser/ui/find_bar/find_bar_host_browsertest.cc b/chrome/browser/ui/find_bar/find_bar_host_browsertest.cc index 6b18c7c..7707adb 100644 --- a/chrome/browser/ui/find_bar/find_bar_host_browsertest.cc +++ b/chrome/browser/ui/find_bar/find_bar_host_browsertest.cc
@@ -28,6 +28,7 @@ #include "chrome/browser/ui/find_bar/find_bar.h" #include "chrome/browser/ui/find_bar/find_bar_controller.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "chrome/browser/ui/ui_features.h" #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/toolbar/pinned_toolbar_actions_container.h" #include "chrome/browser/ui/views/toolbar/toolbar_view.h" @@ -94,10 +95,13 @@ FindInPageControllerTest() = default; protected: void SetUpOnMainThread() override { + CHECK(!features::IsWebUIPinnedToolbarActionsEnabled()) + << "Test needs modification to support WebUIPinnedToolbarActions"; views::test::WaitForAnimatingLayoutManager( - BrowserView::GetBrowserViewForBrowser(browser()) - ->toolbar() - ->pinned_toolbar_actions_container()); + static_cast<PinnedToolbarActionsContainer*>( + BrowserView::GetBrowserViewForBrowser(browser()) + ->toolbar() + ->pinned_toolbar_actions())); } bool GetFindBarWindowInfoForBrowser(Browser* browser,
diff --git a/chrome/browser/ui/login/BUILD.gn b/chrome/browser/ui/login/BUILD.gn index 6d6c7cab..cd9b4a83 100644 --- a/chrome/browser/ui/login/BUILD.gn +++ b/chrome/browser/ui/login/BUILD.gn
@@ -32,6 +32,7 @@ deps = [ ":login", "//chrome/browser/preloading/prefetch/no_state_prefetch", + "//chrome/browser/tab_contents", "//components/autofill/core/browser", "//components/no_state_prefetch/browser", "//components/strings:components_strings",
diff --git a/chrome/browser/ui/omnibox/ai_mode_page_action_controller.cc b/chrome/browser/ui/omnibox/ai_mode_page_action_controller.cc index 45ca7c57..aa9c0ac5 100644 --- a/chrome/browser/ui/omnibox/ai_mode_page_action_controller.cc +++ b/chrome/browser/ui/omnibox/ai_mode_page_action_controller.cc
@@ -9,6 +9,8 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/actions/chrome_action_id.h" #include "chrome/browser/ui/browser_window/public/browser_window_interface.h" +#include "chrome/browser/ui/color/chrome_color_id.h" +#include "chrome/browser/ui/layout_constants.h" #include "chrome/browser/ui/omnibox/omnibox_controller.h" #include "chrome/browser/ui/omnibox/omnibox_edit_model.h" #include "chrome/browser/ui/omnibox/omnibox_view.h" @@ -20,8 +22,11 @@ #include "components/omnibox/browser/omnibox_pref_names.h" #include "components/omnibox/browser/omnibox_triggered_feature_service.h" #include "components/omnibox/browser/page_classification_functions.h" +#include "components/omnibox/browser/vector_icons.h" #include "components/tabs/public/tab_interface.h" #include "third_party/metrics_proto/omnibox_event.pb.h" +#include "ui/base/models/image_model.h" +#include "ui/gfx/paint_vector_icon.h" #include "ui/views/focus/focus_manager.h" #include "ui/views/view.h" @@ -41,6 +46,18 @@ page_actions::PageActionController& page_action_controller, bool visible) { if (visible) { + page_action_controller.OverrideImage( + kActionAiMode, + ui::ImageModel::FromImageGenerator( + base::BindRepeating([](const ui::ColorProvider* color_provider) { + return gfx::CreateVectorIcon( + omnibox::kSearchSparkIcon, + GetLayoutConstant(LayoutConstant::kLocationBarChipIconSize), + color_provider->GetColor(kColorOmniboxIconForegroundTonal)); + }), + gfx::Size( + GetLayoutConstant(LayoutConstant::kLocationBarChipIconSize), + GetLayoutConstant(LayoutConstant::kLocationBarChipIconSize)))); page_action_controller.Show(kActionAiMode); page_action_controller.ShowSuggestionChip(kActionAiMode, {.should_animate = false}); @@ -93,8 +110,12 @@ return false; } - const OmniboxEditModel* edit_model = - location_bar_view.GetOmniboxController()->edit_model(); + auto* omnibox_controller = location_bar_view.GetOmniboxController(); + if (!omnibox_controller) { + return false; + } + + const OmniboxEditModel* edit_model = omnibox_controller->edit_model(); // If the user is currently in keyword mode, then suppress the AIM entrypoint. if (edit_model->is_keyword_selected()) {
diff --git a/chrome/browser/ui/omnibox/omnibox_context_menu_controller.cc b/chrome/browser/ui/omnibox/omnibox_context_menu_controller.cc index c1e3241b..e178d90 100644 --- a/chrome/browser/ui/omnibox/omnibox_context_menu_controller.cc +++ b/chrome/browser/ui/omnibox/omnibox_context_menu_controller.cc
@@ -1013,18 +1013,21 @@ return false; } - const omnibox::ToolMode aim_tool_mode = omnibox_popup_ui->composebox_handler() - ->input_state_model() - ->GetInputState() - .active_tool; + const auto& input_state = omnibox_popup_ui->composebox_handler() + ->input_state_model() + ->GetInputState(); + const omnibox::ToolMode aim_tool_mode = input_state.active_tool; + // If `allowed_models` is empty, the `input_state` is uninitialized and we + // fallback to a default limit of 10. Otherwise, we use the limit provided by + // the `input_state` even if it is 0. + const int max_num_files = + input_state.allowed_models.empty() ? 10 : input_state.max_total_inputs; - auto* session_handle = omnibox_popup_ui->GetOrCreateContextualSessionHandle(); std::vector<contextual_search::FileInfo> file_infos; - if (session_handle) { + if (auto* session_handle = + omnibox_popup_ui->GetOrCreateContextualSessionHandle()) { file_infos = session_handle->GetUploadedContextFileInfos(); } - auto max_num_files = - omnibox::FeatureConfig::Get().config.composebox().max_num_files(); return IsCommandIdEnabledHelper(command_id, aim_tool_mode, file_infos, max_num_files, page_type);
diff --git a/chrome/browser/ui/omnibox/omnibox_next_features.cc b/chrome/browser/ui/omnibox/omnibox_next_features.cc index 6438053..f4f523c 100644 --- a/chrome/browser/ui/omnibox/omnibox_next_features.cc +++ b/chrome/browser/ui/omnibox/omnibox_next_features.cc
@@ -98,8 +98,6 @@ default_config.mutable_entry_point()->set_num_page_load_animations(3); auto* composebox = default_config.mutable_composebox(); - composebox->set_close_by_escape(kCloseComposeboxByEscape.Get()); - composebox->set_close_by_click_outside(kCloseComposeboxByClickOutside.Get()); auto* image_upload = composebox->mutable_image_upload(); image_upload->set_enable_webp_encoding(false); @@ -115,7 +113,6 @@ attachment_upload->set_max_size_bytes(200000000); attachment_upload->set_mime_types_allowed(".pdf,application/pdf"); - composebox->set_max_num_files(kMaxNumFiles.Get()); composebox->set_input_placeholder_text( l10n_util::GetStringUTF8(IDS_NTP_COMPOSE_PLACEHOLDER_TEXT)); composebox->set_is_pdf_upload_enabled(true);
diff --git a/chrome/browser/ui/omnibox/omnibox_next_features_unittest.cc b/chrome/browser/ui/omnibox/omnibox_next_features_unittest.cc index 74c7648..ff232b95 100644 --- a/chrome/browser/ui/omnibox/omnibox_next_features_unittest.cc +++ b/chrome/browser/ui/omnibox/omnibox_next_features_unittest.cc
@@ -72,8 +72,6 @@ EXPECT_EQ(config.entry_point().num_page_load_animations(), 3); auto composebox = config.composebox(); - EXPECT_TRUE(composebox.close_by_escape()); - EXPECT_TRUE(composebox.close_by_click_outside()); auto image_upload = config.composebox().image_upload(); EXPECT_EQ(image_upload.enable_webp_encoding(), false); @@ -89,7 +87,6 @@ EXPECT_EQ(attachment_upload.max_size_bytes(), 200000000); EXPECT_THAT(attachment_upload.mime_types_allowed(), ".pdf,application/pdf"); - EXPECT_EQ(composebox.max_num_files(), 10); EXPECT_EQ(composebox.input_placeholder_text(), l10n_util::GetStringUTF8(IDS_NTP_COMPOSE_PLACEHOLDER_TEXT)); EXPECT_EQ(composebox.is_pdf_upload_enabled(), true);
diff --git a/chrome/browser/ui/read_anything/read_anything_omnibox_controller_browsertest.cc b/chrome/browser/ui/read_anything/read_anything_omnibox_controller_browsertest.cc index 264f58e..98eaeeb 100644 --- a/chrome/browser/ui/read_anything/read_anything_omnibox_controller_browsertest.cc +++ b/chrome/browser/ui/read_anything/read_anything_omnibox_controller_browsertest.cc
@@ -324,8 +324,15 @@ "Accessibility.ReadAnything.OpenedAfterOmniboxIPH", 0); } +// TODO(https://crbug.com/491392993): Re-enable this test +#if BUILDFLAG(IS_CHROMEOS) && \ + (defined(LEAK_SANITIZER) || defined(ADDRESS_SANITIZER)) +#define MAYBE_DidStopLoadingIsDebounced DISABLED_DidStopLoadingIsDebounced +#else +#define MAYBE_DidStopLoadingIsDebounced DidStopLoadingIsDebounced +#endif IN_PROC_BROWSER_TEST_P(ReadAnythingOmniboxControllerBrowserTest, - DidStopLoadingIsDebounced) { + MAYBE_DidStopLoadingIsDebounced) { RegisterPageActionObserver(); NavigateToDistillablePage(); WaitForPageActionShowing(true);
diff --git a/chrome/browser/ui/side_panel/BUILD.gn b/chrome/browser/ui/side_panel/BUILD.gn index 1dcee1c..941c3b1 100644 --- a/chrome/browser/ui/side_panel/BUILD.gn +++ b/chrome/browser/ui/side_panel/BUILD.gn
@@ -4,13 +4,6 @@ import("//extensions/buildflags/buildflags.gni") -if (is_android) { - import("//build/config/android/rules.gni") - import("//third_party/jni_zero/jni_zero.gni") -} - -# Contains side panel infrastructure code for all platforms. -# Platform-specific code is conditionally compiled in. source_set("side_panel") { sources = [ "side_panel_content_proxy.cc", @@ -51,39 +44,10 @@ deps += [ "//extensions/common:common_constants" ] } - if (!is_android) { - deps += [ "//chrome/browser/ui/tabs:tab_model" ] + if (is_android) { + deps += [ "//chrome/browser/ui/side_panel/android" ] } else { - sources += [ - "android/side_panel_native_view_android.cc", - "android/side_panel_native_view_android.h", - "android/side_panel_ui_android.cc", - "android/side_panel_ui_android.h", - ] - - deps += [ - ":jni_headers", - "//base", - "//third_party/jni_zero", - "//ui/base", - ] - } -} - -# Platform-specific targets that don't fit in the "side_panel" target above. -if (is_android) { - android_library("java") { - srcjar_deps = [ ":jni_headers" ] - sources = [ "android/java/src/org/chromium/chrome/browser/ui/side_panel/SidePanelUIAndroidBridge.java" ] - - deps = [ - "//build/android:build_java", - "//third_party/jni_zero:jni_zero_java", - ] - } - - generate_jni("jni_headers") { - sources = [ "android/java/src/org/chromium/chrome/browser/ui/side_panel/SidePanelUIAndroidBridge.java" ] + deps += [ "//chrome/browser/ui/tabs:tab_model" ] } } @@ -113,6 +77,7 @@ "//ui/base/unowned_user_data", ] + # No views dependency is allowed on Android. if (!is_android) { deps += [ "//chrome/browser/ui/tabs:tab_strip", @@ -125,13 +90,10 @@ } } -# Contains C++ unit tests for side panel infrastructure on all platforms. -# Platform-specific tests are conditionally compiled in. source_set("unit_tests") { testonly = true - - # Cross-platform unit tests sources = [ "side_panel_entry_key_unittest.cc" ] + deps = [ ":side_panel", "//chrome/browser/ui/actions:actions_headers", @@ -139,15 +101,7 @@ "//ui/actions:actions_headers", ] - if (is_android) { - # Android unit tests - sources += [ "android/side_panel_ui_android_unittest.cc" ] - deps += [ - "//base", - "//chrome/browser/ui/side_panel/test:native_unit_test_support_jni", - ] - } else { - # Unit tests for Windows/Max/Linux + if (!is_android) { sources += [ "side_panel_metrics_unittest.cc" ] deps += [ ":side_panel_views_dependent",
diff --git a/chrome/browser/ui/side_panel/android/BUILD.gn b/chrome/browser/ui/side_panel/android/BUILD.gn new file mode 100644 index 0000000..20905fa --- /dev/null +++ b/chrome/browser/ui/side_panel/android/BUILD.gn
@@ -0,0 +1,47 @@ +# Copyright 2026 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//build/config/android/rules.gni") +import("//third_party/jni_zero/jni_zero.gni") + +source_set("android") { + sources = [ + "side_panel_native_view_android.cc", + "side_panel_native_view_android.h", + "side_panel_ui_android.cc", + "side_panel_ui_android.h", + ] + + deps = [ + ":jni_headers", + "//base", + "//third_party/jni_zero", + "//ui/base", + ] +} + +android_library("java") { + srcjar_deps = [ ":jni_headers" ] + sources = [ "java/src/org/chromium/chrome/browser/ui/side_panel/SidePanelUIAndroidBridge.java" ] + + deps = [ + "//build/android:build_java", + "//third_party/jni_zero:jni_zero_java", + ] +} + +generate_jni("jni_headers") { + sources = [ "java/src/org/chromium/chrome/browser/ui/side_panel/SidePanelUIAndroidBridge.java" ] +} + +source_set("unit_tests") { + testonly = true + sources = [ "side_panel_ui_android_unittest.cc" ] + deps = [ + ":android", + "//base", + "//chrome/browser/ui/side_panel/test/android:native_unit_test_support_jni", + "//testing/gtest", + ] +}
diff --git a/chrome/browser/ui/side_panel/android/side_panel_ui_android.cc b/chrome/browser/ui/side_panel/android/side_panel_ui_android.cc index 7296ac4..0cb6582 100644 --- a/chrome/browser/ui/side_panel/android/side_panel_ui_android.cc +++ b/chrome/browser/ui/side_panel/android/side_panel_ui_android.cc
@@ -9,7 +9,7 @@ #include "base/android/jni_android.h" #include "base/android/scoped_java_ref.h" #include "base/check.h" -#include "chrome/browser/ui/side_panel/jni_headers/SidePanelUIAndroidBridge_jni.h" +#include "chrome/browser/ui/side_panel/android/jni_headers/SidePanelUIAndroidBridge_jni.h" using base::android::JavaRef; using base::android::ScopedJavaLocalRef;
diff --git a/chrome/browser/ui/side_panel/android/side_panel_ui_android_unittest.cc b/chrome/browser/ui/side_panel/android/side_panel_ui_android_unittest.cc index feba6e1..d40b972 100644 --- a/chrome/browser/ui/side_panel/android/side_panel_ui_android_unittest.cc +++ b/chrome/browser/ui/side_panel/android/side_panel_ui_android_unittest.cc
@@ -8,7 +8,7 @@ #include "base/android/jni_android.h" #include "base/android/scoped_java_ref.h" -#include "chrome/browser/ui/side_panel/test/native_unit_test_support_jni/SidePanelUIAndroidNativeUnitTestSupport_jni.h" +#include "chrome/browser/ui/side_panel/test/android/native_unit_test_support_jni/SidePanelUIAndroidNativeUnitTestSupport_jni.h" #include "testing/gtest/include/gtest/gtest.h" namespace {
diff --git a/chrome/browser/ui/side_panel/test/BUILD.gn b/chrome/browser/ui/side_panel/test/BUILD.gn deleted file mode 100644 index eb07aeed5..0000000 --- a/chrome/browser/ui/side_panel/test/BUILD.gn +++ /dev/null
@@ -1,29 +0,0 @@ -# Copyright 2026 The Chromium Authors -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# Android targets need to be guarded by is_android because: -# (1) Android GNI files may assert is_android, and -# (2) The rest of this file can be included in non-Android builds. -if (is_android) { - import("//build/config/android/rules.gni") - import("//third_party/jni_zero/jni_zero.gni") - - # Supports native unit tests. - android_library("native_unit_test_support_java") { - testonly = true - sources = [ "android/java/src/org/chromium/chrome/browser/ui/side_panel/SidePanelUIAndroidNativeUnitTestSupport.java" ] - deps = [ - "//build/android:build_java", - "//chrome/browser/ui/side_panel:java", - "//third_party/jni_zero:jni_zero_java", - ] - srcjar_deps = [ ":native_unit_test_support_jni" ] - } - - # JNI for native unit tests. - generate_jni("native_unit_test_support_jni") { - testonly = true - sources = [ "android/java/src/org/chromium/chrome/browser/ui/side_panel/SidePanelUIAndroidNativeUnitTestSupport.java" ] - } -}
diff --git a/chrome/browser/ui/side_panel/test/android/BUILD.gn b/chrome/browser/ui/side_panel/test/android/BUILD.gn new file mode 100644 index 0000000..c7465227 --- /dev/null +++ b/chrome/browser/ui/side_panel/test/android/BUILD.gn
@@ -0,0 +1,24 @@ +# Copyright 2026 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//build/config/android/rules.gni") +import("//third_party/jni_zero/jni_zero.gni") + +# Supports native unit tests. +android_library("native_unit_test_support_java") { + testonly = true + sources = [ "java/src/org/chromium/chrome/browser/ui/side_panel/SidePanelUIAndroidNativeUnitTestSupport.java" ] + deps = [ + "//build/android:build_java", + "//chrome/browser/ui/side_panel/android:java", + "//third_party/jni_zero:jni_zero_java", + ] + srcjar_deps = [ ":native_unit_test_support_jni" ] +} + +# JNI for native unit tests. +generate_jni("native_unit_test_support_jni") { + testonly = true + sources = [ "java/src/org/chromium/chrome/browser/ui/side_panel/SidePanelUIAndroidNativeUnitTestSupport.java" ] +}
diff --git a/chrome/browser/ui/side_ui/internal/BUILD.gn b/chrome/browser/ui/side_ui/internal/BUILD.gn index d1f44033..7f771a3 100644 --- a/chrome/browser/ui/side_ui/internal/BUILD.gn +++ b/chrome/browser/ui/side_ui/internal/BUILD.gn
@@ -33,6 +33,7 @@ "//base:base_java_test_support", "//base:base_junit_test_support", "//chrome/browser/ui/side_ui/public:java", + "//chrome/browser/ui/side_ui/test/android:test_support_java", "//third_party/androidx:androidx_annotation_annotation_java", "//third_party/junit", "//third_party/mockito:mockito_java",
diff --git a/chrome/browser/ui/side_ui/internal/android/java/src/org/chromium/chrome/browser/ui/side_ui/SideUiCoordinatorImpl.java b/chrome/browser/ui/side_ui/internal/android/java/src/org/chromium/chrome/browser/ui/side_ui/SideUiCoordinatorImpl.java index 6c9dc5e..73ba206 100644 --- a/chrome/browser/ui/side_ui/internal/android/java/src/org/chromium/chrome/browser/ui/side_ui/SideUiCoordinatorImpl.java +++ b/chrome/browser/ui/side_ui/internal/android/java/src/org/chromium/chrome/browser/ui/side_ui/SideUiCoordinatorImpl.java
@@ -10,9 +10,12 @@ import android.view.ViewParent; import android.view.ViewStub; +import androidx.annotation.Px; + import org.chromium.base.ObserverList; import org.chromium.build.annotations.NullMarked; import org.chromium.build.annotations.Nullable; +import org.chromium.build.annotations.RequiresNonNull; /** Implementation of {@link SideUiCoordinator}. */ @NullMarked @@ -55,37 +58,26 @@ @Override public void requestUpdateContainer(SideUiContainerProperties properties) { + // 1. Verify the request is valid. assert mSideUiContainer != null : "#requestUpdateContainer called with null SideUiContainer."; + assert properties.mWidth >= 0 : "SideUiContainer unexpectedly requested a negative width."; - int requestedWidth = properties.mWidth; - assert requestedWidth >= 0 : "SideUiContainer unexpectedly requested a negative width."; + // 2. Determine containers' widths and the upcoming SideUiSpecs. + // TODO(crbug.com/478306743): Loop through the registered SideUiContainers and call + // SideUiContainer#determineContainerWidth to determine all of the containers' accepted + // widths, rather than just implicitly accepting the requested width. Determine the + // upcoming SideUiSpecs based on the accepted widths. + @Px int acceptedWidth = properties.mWidth; - // Determine the container widths. - // TODO(crbug.com/478306743): Validate the request based on the available space, - // SideUiContainer#determineContainerWidth, etc. in this step instead of just accepting the - // request. When we support multiple SideUiContainers, we'll also need to loop through and - // determine all the final widths before pushing any of the individual changes (e.g. we'll - // want to aggregate all the animators before kicking off any individual one). - @AnchorSide int anchorSide = properties.mAnchorSide; - SideUiSpecs newSideUiSpecs = SideUiSpecs.EMPTY_SIDE_UI_SPECS; - if (anchorSide == AnchorSide.START) { - newSideUiSpecs = new SideUiSpecs(requestedWidth, /* endContainerWidth= */ 0); - } else if (anchorSide == AnchorSide.END) { - newSideUiSpecs = new SideUiSpecs(/* startContainerWidth= */ 0, requestedWidth); - } else { - assert false : "SideUiContainer requested an unknown AnchorSide."; - } - notifyObservers(newSideUiSpecs); + // 3. If animating, notify observers of the upcoming SideUiSpecs from the previous step. + // TODO(crbug.com/491606333): Use the new SideUiSpecs calculated in the previous step to + // notify observers and collect animators. See the proposed event (#onPreSideUiSpecsChange) + // in SideUiObserver.java for more details. - // Push the new container widths. Attach/detach views if needed. - View sideUiContainerView = mSideUiContainer.getView(); - if (requestedWidth == 0) { - detachSideUiContainerView(sideUiContainerView); - } else { - attachSideUiContainerView(sideUiContainerView, properties.mAnchorSide); - } - mSideUiContainer.setWidth(properties.mWidth); + // 4. Commit the new SideUiSpecs. + // TODO(crbug.com/478338737): Track accepted widths for all of the registered containers. + commitNewSideUiSpecs(properties.mAnchorSide, acceptedWidth); } @Override @@ -111,9 +103,7 @@ @Override public SideUiSpecs getCurrentSideUiSpecs() { - // Infers based on measuring the two parent containers. Should not be used in - // #requestUpdateContainer as that notifies Observers of the updated SideUiSpecs before any - // UI changes are actually made. + // Infers by measuring the two parent containers. mStartAnchorContainer.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); mEndAnchorContainer.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); return new SideUiSpecs( @@ -121,6 +111,32 @@ } /** + * Commits a {@link SideUiContainer}'s requested update. Currently, statically resizes and + * attaches/detaches as necessary. As per the inline TODO, this will eventually support + * dynamic/animated resizes, where we'll instead kick off animators to handle the resizes. + * + * @param anchorSide The requesting container's desired {@link AnchorSide}. + * @param acceptedWidth The requesting container's accepted width in px. + */ + @RequiresNonNull("mSideUiContainer") + private void commitNewSideUiSpecs(@AnchorSide int anchorSide, @Px int acceptedWidth) { + // TODO(crbug.com/491606333): Support dynamically updating/animating the changes. i.e. + // Rather than statically changing the SideUiContainers here, we would instead kick off + // animators to handle the width changes. We'd also defer 1) detaching the backing views + // and 2) notifying observers that the change is complete to #onAnimationEnd, as those + // depend on first reaching the resting state. + View sideUiContainerView = mSideUiContainer.getView(); + if (acceptedWidth == 0) { + detachSideUiContainerView(sideUiContainerView); + } else { + attachSideUiContainerView(sideUiContainerView, anchorSide); + } + mSideUiContainer.setWidth(acceptedWidth); + + notifySideUiSpecsChanged(); + } + + /** * Attach the provided {@link SideUiContainer}'s {@link View} to its appropriate ViewGroup * determined by the {@link AnchorSide}. * @@ -191,13 +207,12 @@ } /** - * Notifies each {@link SideUiObserver} of the new {@link SideUiSpecs}. Called when new {@link - * SideUiSpecs} have been determined, but before these specs are actually used to statically - * kick off a UI change. - * - * @param newSideUiSpecs The update {@link SideUiSpecs}. + * Notifies each {@link SideUiObserver} of the new {@link SideUiSpecs}. Called after the + * containers and their views have reached their resting state (and {@link + * #getCurrentSideUiSpecs()} represents this resting state). */ - private void notifyObservers(SideUiSpecs newSideUiSpecs) { + private void notifySideUiSpecsChanged() { + SideUiSpecs newSideUiSpecs = getCurrentSideUiSpecs(); for (SideUiObserver observer : mSideUiObservers) { observer.onSideUiSpecsChanged(newSideUiSpecs); }
diff --git a/chrome/browser/ui/side_ui/internal/android/java/src/org/chromium/chrome/browser/ui/side_ui/SideUiCoordinatorImplTest.java b/chrome/browser/ui/side_ui/internal/android/java/src/org/chromium/chrome/browser/ui/side_ui/SideUiCoordinatorImplTest.java index ceeed51..76eec52 100644 --- a/chrome/browser/ui/side_ui/internal/android/java/src/org/chromium/chrome/browser/ui/side_ui/SideUiCoordinatorImplTest.java +++ b/chrome/browser/ui/side_ui/internal/android/java/src/org/chromium/chrome/browser/ui/side_ui/SideUiCoordinatorImplTest.java
@@ -9,7 +9,6 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import android.app.Activity; @@ -24,7 +23,6 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.Mockito; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; import org.robolectric.Robolectric; @@ -44,12 +42,12 @@ @Mock private ViewStub mStartAnchorContainerStub; @Mock private ViewStub mEndAnchorContainerStub; - @Mock private SideUiContainer mSideUiContainer; @Mock private SideUiObserver mSideUiObserver; private ViewGroup mStartAnchorContainer; private ViewGroup mEndAnchorContainer; private View mSideUiContainerView; + private TestSideUiContainer mSideUiContainer; private SideUiCoordinatorImpl mCoordinator; @@ -60,10 +58,10 @@ mStartAnchorContainer = new FrameLayout(context); mEndAnchorContainer = new FrameLayout(context); mSideUiContainerView = new View(context); + mSideUiContainer = new TestSideUiContainer(mSideUiContainerView); doReturn(mStartAnchorContainer).when(mStartAnchorContainerStub).inflate(); doReturn(mEndAnchorContainer).when(mEndAnchorContainerStub).inflate(); - doReturn(mSideUiContainerView).when(mSideUiContainer).getView(); mCoordinator = new SideUiCoordinatorImpl(mStartAnchorContainerStub, mEndAnchorContainerStub); @@ -85,25 +83,10 @@ @Test public void testAddObserver_NotifyCurrentSpecs() { - // When an observer is added, it's immediately notified of the current specs. This is - // inferred from the anchor containers' measured width. Re-build with mocks, so we can - // fake the measure pass and return the expected values. - ViewStub startAnchorContainerSpyStub = Mockito.mock(ViewStub.class); - ViewStub endAnchorContainerSpyStub = Mockito.mock(ViewStub.class); - - ViewGroup startAnchorContainerSpy = spy(mStartAnchorContainer); - ViewGroup endAnchorContainerSpy = spy(mEndAnchorContainer); - - doReturn(startAnchorContainerSpy).when(startAnchorContainerSpyStub).inflate(); - doReturn(endAnchorContainerSpy).when(endAnchorContainerSpyStub).inflate(); - int startContainerWidth = 25; int endContainerWidth = 75; - doReturn(startContainerWidth).when(startAnchorContainerSpy).getMeasuredWidth(); - doReturn(endContainerWidth).when(endAnchorContainerSpy).getMeasuredWidth(); - - mCoordinator = - new SideUiCoordinatorImpl(startAnchorContainerSpyStub, endAnchorContainerSpyStub); + mStartAnchorContainer.setMinimumWidth(startContainerWidth); + mEndAnchorContainer.setMinimumWidth(endContainerWidth); // Add the observer after requesting an update. mCoordinator.addObserver(mSideUiObserver); @@ -138,7 +121,7 @@ // Verify view attached to start container. assertEquals(mStartAnchorContainer, mSideUiContainerView.getParent()); - verify(mSideUiContainer).setWidth(width); + assertEquals(width, getSideUiContainerViewWidth()); } @Test @@ -156,7 +139,7 @@ // Verify view attached to end container. assertEquals(mEndAnchorContainer, mSideUiContainerView.getParent()); - verify(mSideUiContainer).setWidth(width); + assertEquals(width, getSideUiContainerViewWidth()); } @Test @@ -167,13 +150,12 @@ mCoordinator.requestUpdateContainer( new SideUiContainerProperties(AnchorSide.START, /* width= */ 100)); assertEquals(mStartAnchorContainer, mSideUiContainerView.getParent()); - clearInvocations(mSideUiContainer); // Then update to width 0. mCoordinator.requestUpdateContainer( new SideUiContainerProperties(AnchorSide.START, /* width= */ 0)); assertNull(mSideUiContainerView.getParent()); - verify(mSideUiContainer).setWidth(0); + assertEquals(0, getSideUiContainerViewWidth()); } @Test @@ -190,4 +172,8 @@ new SideUiContainerProperties(AnchorSide.END, /* width= */ 200)); assertEquals(mEndAnchorContainer, mSideUiContainerView.getParent()); } + + private int getSideUiContainerViewWidth() { + return mSideUiContainerView.getLayoutParams().width; + } }
diff --git a/chrome/browser/ui/side_ui/public/android/java/src/org/chromium/chrome/browser/ui/side_ui/SideUiObserver.java b/chrome/browser/ui/side_ui/public/android/java/src/org/chromium/chrome/browser/ui/side_ui/SideUiObserver.java index 1f89ad31..8bc87d7a 100644 --- a/chrome/browser/ui/side_ui/public/android/java/src/org/chromium/chrome/browser/ui/side_ui/SideUiObserver.java +++ b/chrome/browser/ui/side_ui/public/android/java/src/org/chromium/chrome/browser/ui/side_ui/SideUiObserver.java
@@ -11,13 +11,26 @@ @NullMarked public interface SideUiObserver { + // TODO(crbug.com/491606333): Support animations by adding a new observer event: + // * @Nullable Animator onPreSideUiSpecsChange(SideUiSpecs) + // This new event will be called after the new SideUiSpecs have been determined, but before + // these specs are actually used by the SideUiCoordinator to animate the UI change, so that the + // SideUiCoordinator can kick off all of the animators together. The return type is @Nullable + // to allow for clients to skip animating (e.g. if they're not visible). They are still + // expected to statically resize through the #onSideUiSpecsChanged below. + /** - * Called when new {@link SideUiSpecs} have been determined, but before these specs are actually - * used by the {@link SideUiCoordinator} to statically kick off a UI change (i.e. statically - * resizing any registered {@link SideUiContainer}s. This is intended to be used by UI elements - * that need to resize themselves in response to the changes in the Side UI. + * Called after the Side UI has reached its new resting UI state to handle a resize. This will + * either be 1) after a static resize or 2) after an animated resize has completely finished. * - * @param sideUiSpecs The new {@link SideUiSpecs} + * <p>The {@link SideUiSpecs} that are passed represent the resting state after the + * aforementioned resize has been completed. These specs are also the same as the ones queryable + * through {@link SideUiCoordinator#getCurrentSideUiSpecs()}. + * + * <p>This is intended to be used by UI elements that need to resize themselves in response to + * the changes in the Side UI. + * + * @param sideUiSpecs The new {@link SideUiSpecs}. */ void onSideUiSpecsChanged(SideUiSpecs sideUiSpecs); }
diff --git a/chrome/browser/ui/side_ui/test/android/BUILD.gn b/chrome/browser/ui/side_ui/test/android/BUILD.gn new file mode 100644 index 0000000..aabfa4f --- /dev/null +++ b/chrome/browser/ui/side_ui/test/android/BUILD.gn
@@ -0,0 +1,17 @@ +# Copyright 2026 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//build/config/android/config.gni") +import("//build/config/android/rules.gni") + +android_library("test_support_java") { + testonly = true + sources = [ + "java/src/org/chromium/chrome/browser/ui/side_ui/TestSideUiContainer.java", + ] + deps = [ + "//build/android:build_java", + "//chrome/browser/ui/side_ui/public:java", + ] +}
diff --git a/chrome/browser/ui/side_ui/test/android/java/src/org/chromium/chrome/browser/ui/side_ui/TestSideUiContainer.java b/chrome/browser/ui/side_ui/test/android/java/src/org/chromium/chrome/browser/ui/side_ui/TestSideUiContainer.java new file mode 100644 index 0000000..5740ff77 --- /dev/null +++ b/chrome/browser/ui/side_ui/test/android/java/src/org/chromium/chrome/browser/ui/side_ui/TestSideUiContainer.java
@@ -0,0 +1,39 @@ +// Copyright 2026 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.ui.side_ui; + +import android.view.View; +import android.view.ViewGroup.LayoutParams; + +/** Minimum implementation of {@link SideUiContainer} to allow setting/getting width for tests. */ +public class TestSideUiContainer implements SideUiContainer { + private final View mSideUiContainerView; + + public TestSideUiContainer(View view) { + mSideUiContainerView = view; + } + + @Override + public View getView() { + return mSideUiContainerView; + } + + @Override + public int determineContainerWidth(int availableWidth, int windowWidth) { + return 0; + } + + @Override + public int getCurrentWidth() { + return mSideUiContainerView.getWidth(); + } + + @Override + public void setWidth(int width) { + LayoutParams layoutParams = mSideUiContainerView.getLayoutParams(); + layoutParams.width = width; + mSideUiContainerView.setLayoutParams(layoutParams); + } +}
diff --git a/chrome/browser/ui/startup/BUILD.gn b/chrome/browser/ui/startup/BUILD.gn index 8af35d5..66847f85 100644 --- a/chrome/browser/ui/startup/BUILD.gn +++ b/chrome/browser/ui/startup/BUILD.gn
@@ -222,7 +222,7 @@ "//chrome/browser/ui/tabs:tab_strip", "//chrome/browser/ui/toasts", "//chrome/browser/ui/toasts/api:toasts", - "//chrome/browser/ui/waap", + "//chrome/browser/ui/waap:manager", "//chrome/browser/ui/webui/whats_new", "//chrome/browser/web_applications", "//chrome/common",
diff --git a/chrome/browser/ui/startup/bad_flags_prompt.cc b/chrome/browser/ui/startup/bad_flags_prompt.cc index 027f02d..da61cdd9 100644 --- a/chrome/browser/ui/startup/bad_flags_prompt.cc +++ b/chrome/browser/ui/startup/bad_flags_prompt.cc
@@ -55,6 +55,8 @@ #endif #if BUILDFLAG(IS_ANDROID) +#include "base/android/command_line_android.h" +#include "base/android/jni_android.h" #include "chrome/browser/android/flags/bad_flags_snackbar_manager.h" #include "chrome/browser/flags/android/chrome_feature_list.h" #else @@ -257,6 +259,20 @@ } #endif +#if BUILDFLAG(IS_ANDROID) + JNIEnv* env = base::android::AttachCurrentThread(); + base::CommandLine* commandLine = base::CommandLine::ForCurrentProcess(); + bool isTestIntent = commandLine->HasSwitch("enable-test-intents"); + if (base::android::WasFlagsLoadedFromFile(env) && + !commandLine->HasSwitch(switches::kEnableAutomation) && !isTestIntent) { + // If the command line file was loaded, we show a snackbar warning about + // all the flags in the file. + ShowBadFlagsSnackbar( + web_contents, + l10n_util::GetStringUTF16(IDS_BAD_FLAGS_FROM_FILE_WARNING_MESSAGE)); + } +#endif + for (const auto& flag_or_feature : kBadFeatureFlagsInAboutFlags) { std::string bad_flag_name = std::visit( absl::Overload{[](const base::Feature* feature) -> std::string {
diff --git a/chrome/browser/ui/tab_helpers.cc b/chrome/browser/ui/tab_helpers.cc index 0b9f4d9b..ea7617a 100644 --- a/chrome/browser/ui/tab_helpers.cc +++ b/chrome/browser/ui/tab_helpers.cc
@@ -646,8 +646,10 @@ ContextMenuHelper::CreateForWebContents(web_contents); if (base::FeatureList::IsEnabled(chrome::android::kChromeFinds)) { - finds::FindsTabHelper::CreateForWebContents( - web_contents, finds::FindsServiceFactory::GetForProfile(profile)); + if (auto* finds_service = + finds::FindsServiceFactory::GetForProfile(profile)) { + finds::FindsTabHelper::CreateForWebContents(web_contents, finds_service); + } } if (base::FeatureList::IsEnabled(
diff --git a/chrome/browser/ui/tabs/features.cc b/chrome/browser/ui/tabs/features.cc index 0e0c101..ee0c38e 100644 --- a/chrome/browser/ui/tabs/features.cc +++ b/chrome/browser/ui/tabs/features.cc
@@ -22,6 +22,8 @@ BASE_FEATURE(kVerticalTabsNewBadge, base::FEATURE_DISABLED_BY_DEFAULT); +BASE_FEATURE(kVerticalTabsExpandOnHover, base::FEATURE_DISABLED_BY_DEFAULT); + BASE_FEATURE(kTabSelectionByPointer, base::FEATURE_ENABLED_BY_DEFAULT); BASE_FEATURE(kHorizontalTabStripComboButton, base::FEATURE_DISABLED_BY_DEFAULT); @@ -36,4 +38,9 @@ ; } +bool IsVerticalTabsExpandOnHoverFeatureEnabled() { + return IsVerticalTabsFeatureEnabled() && + base::FeatureList::IsEnabled(kVerticalTabsExpandOnHover); +} + } // namespace tabs
diff --git a/chrome/browser/ui/tabs/features.h b/chrome/browser/ui/tabs/features.h index b876b84..578aef91 100644 --- a/chrome/browser/ui/tabs/features.h +++ b/chrome/browser/ui/tabs/features.h
@@ -31,6 +31,8 @@ BASE_DECLARE_FEATURE(kVerticalTabsNewBadge); +BASE_DECLARE_FEATURE(kVerticalTabsExpandOnHover); + BASE_DECLARE_FEATURE(kTabSelectionByPointer); BASE_DECLARE_FEATURE(kBackToOpener); @@ -39,6 +41,8 @@ bool IsVerticalTabsFeatureEnabled(); +bool IsVerticalTabsExpandOnHoverFeatureEnabled(); + } // namespace tabs #endif // CHROME_BROWSER_UI_TABS_FEATURES_H_
diff --git a/chrome/browser/ui/tabs/tab_strip_api/tab_strip_model_impl/tab_strip_model_event_bridge.cc b/chrome/browser/ui/tabs/tab_strip_api/tab_strip_model_impl/tab_strip_model_event_bridge.cc index ab6d7afc..106e8996 100644 --- a/chrome/browser/ui/tabs/tab_strip_api/tab_strip_model_impl/tab_strip_model_event_bridge.cc +++ b/chrome/browser/ui/tabs/tab_strip_api/tab_strip_model_impl/tab_strip_model_event_bridge.cc
@@ -68,7 +68,17 @@ void BridgeInstance::OnChildrenRemoved( const tabs::TabCollection::Position& position, const tabs::TabCollectionNodes& handles) { - ForwardToObserver(events::ToEvent(handles)); + tabs::TabCollectionNodes filtered_handles; + for (const auto& handle : handles) { + // We only forward TabCollectionHandles because tab removal events do not + // bubble up to the root when their parent collection is detached from the + // tree (e.g. closing the last tab in a group removes the group first). + // Tab removals are instead handled via OnTabStripModelChanged. + if (std::holds_alternative<tabs::TabCollectionHandle>(handle)) { + filtered_handles.push_back(handle); + } + } + ForwardToObserver(events::ToEvent(filtered_handles)); } void BridgeInstance::OnChildMoved( @@ -85,7 +95,15 @@ TabStripModel* tab_strip_model, const TabStripModelChange& change, const TabStripSelectionChange& selection) { - // Avoid listening to add, remove and move changes as this is handled by the + if (change.type() == TabStripModelChange::Type::kRemoved) { + const TabStripModelChange::Remove* remove = change.GetRemove(); + tabs::TabCollectionNodes removed_nodes; + for (const auto& contents : remove->contents) { + removed_nodes.push_back(contents.tab->GetHandle()); + } + ForwardToObserver(events::ToEvent(removed_nodes)); + } + // Avoid listening to add and move changes as this is handled by the // TabCollection observation methods. if (change.type() == TabStripModelChange::Type::kReplaced) { NOTIMPLEMENTED();
diff --git a/chrome/browser/ui/tabs/tab_strip_api/tab_strip_model_impl/tab_strip_service_impl_browsertest.cc b/chrome/browser/ui/tabs/tab_strip_api/tab_strip_model_impl/tab_strip_service_impl_browsertest.cc index 59e9394b..fe9137f 100644 --- a/chrome/browser/ui/tabs/tab_strip_api/tab_strip_model_impl/tab_strip_service_impl_browsertest.cc +++ b/chrome/browser/ui/tabs/tab_strip_api/tab_strip_model_impl/tab_strip_service_impl_browsertest.cc
@@ -16,6 +16,7 @@ #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/browser_window/public/browser_window_interface.h" #include "chrome/browser/ui/tabs/split_tab_metrics.h" +#include "chrome/browser/ui/tabs/tab_enums.h" #include "chrome/browser/ui/tabs/tab_group_model.h" #include "chrome/browser/ui/tabs/tab_strip_api/adapters/browser_adapter.h" #include "chrome/browser/ui/tabs/tab_strip_api/observation/tab_strip_api_batched_observer.h" @@ -71,6 +72,7 @@ for (auto& id : event->tabs) { tabs.erase(std::string(id.Id())); } + tab_closed_events.push_back(event.Clone()); } void OnNodeMoved(tabs_api::mojom::OnNodeMovedEventPtr event) { @@ -127,6 +129,7 @@ std::vector<tabs_api::mojom::OnNodeMovedEventPtr> move_events; std::vector<tabs_api::mojom::OnCollectionCreatedEventPtr> created_events; std::vector<tabs_api::mojom::OnTabsCreatedEventPtr> tab_created_events; + std::vector<tabs_api::mojom::OnTabsClosedEventPtr> tab_closed_events; std::map<std::string, tabs_api::mojom::TabPtr> tabs; }; @@ -266,6 +269,31 @@ return std::nullopt; } + tabs_api::mojom::TabPtr CreateTabAt( + mojo::Remote<TabStripService>& remote, + std::optional<tabs_api::Position> position = std::nullopt, + std::optional<GURL> url = std::nullopt) { + base::RunLoop run_loop; + TabStripService::CreateTabAtResult result; + remote->CreateTabAt( + position, url, + base::BindLambdaForTesting([&](TabStripService::CreateTabAtResult in) { + result = std::move(in); + run_loop.Quit(); + })); + run_loop.Run(); + EXPECT_TRUE(result.has_value()); + return result.has_value() ? std::move(result.value()) : nullptr; + } + + void CreateTabs(mojo::Remote<TabStripService>& remote, + int count, + std::optional<GURL> url = std::nullopt) { + for (int i = 0; i < count; ++i) { + CreateTabAt(remote, std::nullopt, url); + } + } + base::test::ScopedFeatureList feature_list_; std::unique_ptr<TabStripServiceMojoHandler> tab_strip_service_mojo_handler_; }; @@ -325,23 +353,13 @@ const int expected_tab_count = model->count() + 1; const GURL url("http://example.com/"); - base::RunLoop run_loop; + auto tab = CreateTabAt(remote, tabs_api::Position(0), url); - TabStripService::CreateTabAtResult result; - remote->CreateTabAt( - tabs_api::Position(0), std::make_optional(url), - base::BindLambdaForTesting([&](TabStripService::CreateTabAtResult in) { - result = std::move(in); - run_loop.Quit(); - })); - run_loop.Run(); - - ASSERT_TRUE(result.has_value()); - EXPECT_TRUE(result.value()); + ASSERT_TRUE(tab); EXPECT_EQ(model->count(), expected_tab_count); auto handle = model->GetTabAtIndex(0)->GetHandle(); - ASSERT_EQ(base::NumberToString(handle.raw_value()), result.value()->id.Id()); + ASSERT_EQ(base::NumberToString(handle.raw_value()), tab->id.Id()); // Assert that newly created tabs are also activated. ASSERT_EQ(model->GetActiveTab()->GetHandle(), handle); } @@ -375,15 +393,8 @@ std::optional<GURL> url("http://example.com/"); auto [pinned_path, unpinned_path] = get_snapshot_collection_paths(); // Test creating a tab in the pinned collection - base::RunLoop pinned_create_loop; - observation->remote->CreateTabAt( - tabs_api::Position(0, tabs_api::Path(pinned_path)), url, - base::BindLambdaForTesting( - [&](TabStripService::CreateTabAtResult result) { - ASSERT_TRUE(result.has_value()); - pinned_create_loop.Quit(); - })); - pinned_create_loop.Run(); + CreateTabAt(observation->remote, + tabs_api::Position(0, tabs_api::Path(pinned_path)), url); observation->receiver.FlushForTesting(); ASSERT_EQ(model->count(), 2); ASSERT_TRUE(model->IsTabPinned(0)); @@ -396,15 +407,8 @@ EXPECT_EQ(0u, pinned_event->tabs[0]->position.index()); // Test creating the tab in an unpinned collection. - base::RunLoop unpinned_create_loop; - observation->remote->CreateTabAt( - tabs_api::Position(0, tabs_api::Path(unpinned_path)), url, - base::BindLambdaForTesting( - [&](TabStripService::CreateTabAtResult result) { - ASSERT_TRUE(result.has_value()); - unpinned_create_loop.Quit(); - })); - unpinned_create_loop.Run(); + CreateTabAt(observation->remote, + tabs_api::Position(0, tabs_api::Path(unpinned_path)), url); observation->receiver.FlushForTesting(); ASSERT_EQ(model->count(), 3); @@ -425,15 +429,8 @@ std::vector<tabs_api::NodeId> group_path = unpinned_path; group_path.push_back(group_node_id); - base::RunLoop group_create_loop; - observation->remote->CreateTabAt( - tabs_api::Position(0, tabs_api::Path(group_path)), url, - base::BindLambdaForTesting( - [&](TabStripService::CreateTabAtResult result) { - ASSERT_TRUE(result.has_value()); - group_create_loop.Quit(); - })); - group_create_loop.Run(); + CreateTabAt(observation->remote, + tabs_api::Position(0, tabs_api::Path(group_path)), url); observation->receiver.FlushForTesting(); ASSERT_EQ(model->count(), 4); @@ -454,7 +451,6 @@ uint32_t target_index = 0; auto original_tab_id = tabs_api::NodeId::FromTabHandle( GetTabStripModel()->GetTabAtIndex(0)->GetHandle()); - base::RunLoop run_loop; base::RunLoop get_tabs_loop; remote->GetTabs( @@ -466,22 +462,13 @@ })); get_tabs_loop.Run(); - TabStripService::CreateTabAtResult result; - remote->CreateTabAt( - tabs_api::Position(target_index), std::make_optional(url), - base::BindLambdaForTesting([&](TabStripService::CreateTabAtResult in) { - result = std::move(in); - run_loop.Quit(); - })); - run_loop.Run(); + auto created_tab = CreateTabAt(remote, tabs_api::Position(target_index), url); // Ensure that we've received the observation callback, which are not // guaranteed to happen immediately. receiver.FlushForTesting(); - ASSERT_TRUE(result.has_value()) - << "CreateTabAt failed: " << (result.error()->message); - auto created_tab = std::move(result.value()); + ASSERT_TRUE(created_tab); ASSERT_EQ(1ul, client.tabs.size()); ASSERT_TRUE(client.tabs.contains(std::string(created_tab->id.Id()))); @@ -517,15 +504,7 @@ const int starting_num_tabs = GetTabStripModel()->count(); - base::RunLoop create_loop; - remote->CreateTabAt(tabs_api::Position(0), - std::make_optional(GURL("http://dark.web")), - base::BindLambdaForTesting( - [&](TabStripService::CreateTabAtResult result) { - ASSERT_TRUE(result.has_value()); - create_loop.Quit(); - })); - create_loop.Run(); + CreateTabAt(remote, tabs_api::Position(0), GURL("http://dark.web")); // We should now have one more tab than when we first started. ASSERT_EQ(starting_num_tabs + 1, GetTabStripModel()->count()); @@ -546,21 +525,37 @@ ASSERT_EQ(starting_num_tabs, GetTabStripModel()->count()); } +IN_PROC_BROWSER_TEST_F(TabStripServiceImplBrowserTest, RemoveTabGroup) { + mojo::Remote<TabStripService> remote; + tab_strip_service_mojo_handler_->Accept(remote.BindNewPipeAndPassReceiver()); + auto observation = SetUpObservation(); + TabStripModel* model = GetTabStripModel(); + CreateTabs(remote, 3, GURL("http://somwewhere.nowhere")); + ASSERT_EQ(model->count(), 4); + + const tab_groups::TabGroupId group_id = model->AddToNewGroup({0, 1, 2}); + observation->receiver.FlushForTesting(); + + model->CloseAllTabsInGroup(group_id); + observation->receiver.FlushForTesting(); + + // Total number of nodes closed (3 tabs + 1 group collection). + int closed_node_count = 0; + for (const auto& event : observation->client.tab_closed_events) { + closed_node_count += event->tabs.size(); + } + EXPECT_EQ(closed_node_count, 4); + EXPECT_EQ(model->count(), 1); +} + IN_PROC_BROWSER_TEST_F(TabStripServiceImplBrowserTest, ActivateTab) { mojo::Remote<TabStripService> remote; tab_strip_service_mojo_handler_->Accept(remote.BindNewPipeAndPassReceiver()); tabs_api::NodeId created_id; - base::RunLoop create_loop; // Append a new tab to the end, which will also focus it. - remote->CreateTabAt(std::nullopt, std::make_optional(GURL("http://dark.web")), - base::BindLambdaForTesting( - [&](TabStripService::CreateTabAtResult result) { - ASSERT_TRUE(result.has_value()); - created_id = result.value()->id; - create_loop.Quit(); - })); - create_loop.Run(); + auto tab = CreateTabAt(remote, std::nullopt, GURL("http://dark.web")); + created_id = tab->id; auto old_tab_handle = GetTabStripModel()->GetTabAtIndex(0)->GetHandle(); // Creating a new tab should have caused the old tab to lose active state. @@ -590,17 +585,7 @@ auto observation = SetUpObservation(); // Created 5 tabs. - for (int i = 0; i < 5; ++i) { - base::RunLoop create_loop; - remote->CreateTabAt(std::nullopt, - std::make_optional(GURL("http://some.where/nowhere")), - base::BindLambdaForTesting( - [&](TabStripService::CreateTabAtResult result) { - ASSERT_TRUE(result.has_value()); - create_loop.Quit(); - })); - create_loop.Run(); - } + CreateTabs(remote, 5, GURL("http://some.where/nowhere")); observation->receiver.FlushForTesting(); // TODO(crbug.com/412738255): need to account for the initial tab. @@ -659,15 +644,7 @@ auto observation = SetUpObservation(); // Append a new tab to the end, so we have two tabs to work with. - base::RunLoop create_loop; - remote->CreateTabAt(std::nullopt, - std::make_optional(GURL("http://somwewhere.nowhere")), - base::BindLambdaForTesting( - [&](TabStripService::CreateTabAtResult result) { - ASSERT_TRUE(result.has_value()); - create_loop.Quit(); - })); - create_loop.Run(); + CreateTabAt(remote, std::nullopt, GURL("http://somwewhere.nowhere")); auto handle_to_move = GetTabStripModel()->GetTabAtIndex(0)->GetHandle(); auto to_move_id = @@ -704,17 +681,7 @@ auto observation = SetUpObservation(); TabStripModel* model = GetTabStripModel(); - for (int i = 0; i < 3; i++) { - base::RunLoop create_loop; - remote->CreateTabAt(std::nullopt, - std::make_optional(GURL("http://somwewhere.nowhere")), - base::BindLambdaForTesting( - [&](TabStripService::CreateTabAtResult result) { - ASSERT_TRUE(result.has_value()); - create_loop.Quit(); - })); - create_loop.Run(); - } + CreateTabs(remote, 3, GURL("http://somwewhere.nowhere")); ASSERT_EQ(model->count(), 4); const tab_groups::TabGroupId group_id = model->AddToNewGroup({0, 1}); @@ -777,17 +744,7 @@ tab_strip_service_mojo_handler_->Accept(remote.BindNewPipeAndPassReceiver()); TabStripModel* model = GetTabStripModel(); - for (int i = 0; i < 3; i++) { - base::RunLoop create_loop; - remote->CreateTabAt(std::nullopt, - std::make_optional(GURL("http://somwewhere.nowhere")), - base::BindLambdaForTesting( - [&](TabStripService::CreateTabAtResult result) { - ASSERT_TRUE(result.has_value()); - create_loop.Quit(); - })); - create_loop.Run(); - } + CreateTabs(remote, 3, GURL("http://somwewhere.nowhere")); ASSERT_EQ(model->count(), 4); const tab_groups::TabGroupId group_id = model->AddToNewGroup({2, 3}); @@ -822,17 +779,7 @@ tab_strip_service_mojo_handler_->Accept(remote.BindNewPipeAndPassReceiver()); TabStripModel* model = GetTabStripModel(); - for (int i = 0; i < 3; i++) { - base::RunLoop create_loop; - remote->CreateTabAt(std::nullopt, - std::make_optional(GURL("http://somwewhere.nowhere")), - base::BindLambdaForTesting( - [&](TabStripService::CreateTabAtResult result) { - ASSERT_TRUE(result.has_value()); - create_loop.Quit(); - })); - create_loop.Run(); - } + CreateTabs(remote, 3, GURL("http://somwewhere.nowhere")); ASSERT_EQ(model->count(), 4); model->ActivateTabAt(2); @@ -872,17 +819,7 @@ experiment_remote.BindNewPipeAndPassReceiver()); TabStripModel* model = GetTabStripModel(); - for (int i = 0; i < 3; i++) { - base::RunLoop create_loop; - remote->CreateTabAt(std::nullopt, - std::make_optional(GURL("http://somewhere.nowhere")), - base::BindLambdaForTesting( - [&](TabStripService::CreateTabAtResult result) { - ASSERT_TRUE(result.has_value()); - create_loop.Quit(); - })); - create_loop.Run(); - } + CreateTabs(remote, 3, GURL("http://somewhere.nowhere")); ASSERT_EQ(model->count(), 4); // Create a split with tabs at index 2 and 3. @@ -927,15 +864,7 @@ experiment_remote.BindNewPipeAndPassReceiver()); TabStripModel* model = GetTabStripModel(); - base::RunLoop create_loop; - remote->CreateTabAt(std::nullopt, - std::make_optional(GURL("http://somewhere.nowhere")), - base::BindLambdaForTesting( - [&](TabStripService::CreateTabAtResult result) { - ASSERT_TRUE(result.has_value()); - create_loop.Quit(); - })); - create_loop.Run(); + CreateTabAt(remote, std::nullopt, GURL("http://somewhere.nowhere")); ASSERT_EQ(model->count(), 2); const tab_groups::TabGroupId group_id = model->AddToNewGroup({0, 1}); @@ -980,16 +909,9 @@ experiment_remote.BindNewPipeAndPassReceiver()); tabs_api::NodeId created_id; - base::RunLoop create_loop; - remote->CreateTabAt(std::nullopt, - std::make_optional(GURL("http://somewhere.nowhere")), - base::BindLambdaForTesting( - [&](TabStripService::CreateTabAtResult result) { - ASSERT_TRUE(result.has_value()); - created_id = result.value()->id; - create_loop.Quit(); - })); - create_loop.Run(); + auto tab = + CreateTabAt(remote, std::nullopt, GURL("http://somewhere.nowhere")); + created_id = tab->id; base::RunLoop run_loop; experiment_remote->ShowTabContextMenu(
diff --git a/chrome/browser/ui/toolbar/cast/cast_toolbar_button_controller_browsertest.cc b/chrome/browser/ui/toolbar/cast/cast_toolbar_button_controller_browsertest.cc index cb785f68..064a9314 100644 --- a/chrome/browser/ui/toolbar/cast/cast_toolbar_button_controller_browsertest.cc +++ b/chrome/browser/ui/toolbar/cast/cast_toolbar_button_controller_browsertest.cc
@@ -11,6 +11,7 @@ #include "chrome/browser/media/router/media_router_feature.h" #include "chrome/browser/ui/actions/chrome_action_id.h" #include "chrome/browser/ui/toolbar/pinned_toolbar/pinned_toolbar_actions_model.h" +#include "chrome/browser/ui/ui_features.h" #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/toolbar/pinned_toolbar_actions_container.h" #include "chrome/browser/ui/views/toolbar/toolbar_view.h" @@ -52,10 +53,13 @@ } bool IsIconShown() const { + CHECK(!features::IsWebUIPinnedToolbarActionsEnabled()) + << "Test needs modification to support WebUIPinnedToolbarActions"; views::test::WaitForAnimatingLayoutManager( - BrowserView::GetBrowserViewForBrowser(browser()) - ->toolbar() - ->pinned_toolbar_actions_container()); + static_cast<PinnedToolbarActionsContainer*>( + BrowserView::GetBrowserViewForBrowser(browser()) + ->toolbar() + ->pinned_toolbar_actions())); auto* cast_button = BrowserView::GetBrowserViewForBrowser(browser()) ->toolbar() ->GetCastButton();
diff --git a/chrome/browser/ui/toolbar/pinned_toolbar/tab_search_toolbar_button_controller.cc b/chrome/browser/ui/toolbar/pinned_toolbar/tab_search_toolbar_button_controller.cc index 2bb710f..77918ff 100644 --- a/chrome/browser/ui/toolbar/pinned_toolbar/tab_search_toolbar_button_controller.cc +++ b/chrome/browser/ui/toolbar/pinned_toolbar/tab_search_toolbar_button_controller.cc
@@ -10,7 +10,7 @@ #include "chrome/browser/ui/browser_actions.h" #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/tab_search_bubble_host.h" -#include "chrome/browser/ui/views/toolbar/pinned_toolbar_actions_container.h" +#include "chrome/browser/ui/views/toolbar/pinned_toolbar_actions.h" #include "chrome/browser/ui/views/toolbar/toolbar_view.h" TabSearchToolbarButtonController::TabSearchToolbarButtonController( @@ -22,24 +22,24 @@ void TabSearchToolbarButtonController::OnBubbleInitializing() { actions::ActionItem* tab_search_action_item = GetTabSearchActionItem(); tab_search_action_item->SetIsShowingBubble(true); - PinnedToolbarActionsContainer* pinned_toolbar_actions_container = - browser_view_->toolbar()->pinned_toolbar_actions_container(); + PinnedToolbarActions* pinned_toolbar_actions = + browser_view_->toolbar()->pinned_toolbar_actions(); - if (pinned_toolbar_actions_container->IsActionPinned(kActionTabSearch)) { + if (pinned_toolbar_actions->IsActionPinned(kActionTabSearch)) { return; } - pinned_toolbar_actions_container->ShowActionEphemerallyInToolbar( - kActionTabSearch, true); + pinned_toolbar_actions->ShowActionEphemerallyInToolbar(kActionTabSearch, + true); } void TabSearchToolbarButtonController::OnBubbleDestroying() { actions::ActionItem* tab_search_action_item = GetTabSearchActionItem(); tab_search_action_item->SetIsShowingBubble(false); - PinnedToolbarActionsContainer* pinned_toolbar_actions_container = - browser_view_->toolbar()->pinned_toolbar_actions_container(); + PinnedToolbarActions* pinned_toolbar_actions = + browser_view_->toolbar()->pinned_toolbar_actions(); - if (pinned_toolbar_actions_container->IsActionPinned(kActionTabSearch)) { + if (pinned_toolbar_actions->IsActionPinned(kActionTabSearch)) { return; } @@ -82,16 +82,16 @@ } void TabSearchToolbarButtonController::MaybeHideActionEphemerallyInToolbar() { - PinnedToolbarActionsContainer* pinned_toolbar_actions_container = - browser_view_->toolbar()->pinned_toolbar_actions_container(); + PinnedToolbarActions* pinned_toolbar_actions = + browser_view_->toolbar()->pinned_toolbar_actions(); if (GetTabSearchActionItem()->GetIsShowingBubble() || - pinned_toolbar_actions_container->IsActionPinned(kActionTabSearch)) { + pinned_toolbar_actions->IsActionPinned(kActionTabSearch)) { return; } - pinned_toolbar_actions_container->ShowActionEphemerallyInToolbar( - kActionTabSearch, false); + pinned_toolbar_actions->ShowActionEphemerallyInToolbar(kActionTabSearch, + false); } actions::ActionItem*
diff --git a/chrome/browser/ui/ui_features.cc b/chrome/browser/ui/ui_features.cc index 706693c2..4e9506b 100644 --- a/chrome/browser/ui/ui_features.cc +++ b/chrome/browser/ui/ui_features.cc
@@ -116,6 +116,11 @@ BASE_FEATURE(kPressAndHoldEscToExitBrowserFullscreen, base::FEATURE_ENABLED_BY_DEFAULT); +#if BUILDFLAG(IS_WIN) +// Enables the UI for Process Isolation in chrome://settings/system. +BASE_FEATURE(kProcessIsolationSettings, base::FEATURE_DISABLED_BY_DEFAULT); +#endif // BUILDFLAG(IS_WIN) + #if BUILDFLAG(IS_MAC) // Add tab group colours when viewing tab groups using the top mac OS menu bar. BASE_FEATURE(kShowTabGroupsMacSystemMenu, base::FEATURE_DISABLED_BY_DEFAULT); @@ -475,9 +480,14 @@ } #endif // BUILDFLAG(IS_ANDROID) -BASE_FEATURE(kWhatsNewDesktopRefresh, base::FEATURE_DISABLED_BY_DEFAULT); +BASE_FEATURE(kWhatsNewDesktopRefresh, base::FEATURE_ENABLED_BY_DEFAULT); BASE_FEATURE(kAiOverlayDialog, base::FEATURE_DISABLED_BY_DEFAULT); +BASE_FEATURE_PARAM(std::string, + kAiOverlayDialogApiKey, + &kAiOverlayDialog, + "api_key", + ""); BASE_FEATURE(kTabGroupsFocusing, base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/chrome/browser/ui/ui_features.h b/chrome/browser/ui/ui_features.h index 6023ea0..4f7104e 100644 --- a/chrome/browser/ui/ui_features.h +++ b/chrome/browser/ui/ui_features.h
@@ -152,6 +152,10 @@ BASE_DECLARE_FEATURE(kPressAndHoldEscToExitBrowserFullscreen); +#if BUILDFLAG(IS_WIN) +BASE_DECLARE_FEATURE(kProcessIsolationSettings); +#endif // BUILDFLAG(IS_WIN) + BASE_DECLARE_FEATURE(kScrimForBrowserWindowModal); BASE_DECLARE_FEATURE(kSplitViewTabDraggingUpdates); @@ -368,6 +372,7 @@ BASE_DECLARE_FEATURE(kWhatsNewDesktopRefresh); BASE_DECLARE_FEATURE(kAiOverlayDialog); +BASE_DECLARE_FEATURE_PARAM(std::string, kAiOverlayDialogApiKey); BASE_DECLARE_FEATURE(kTabGroupsFocusing); BASE_DECLARE_FEATURE_PARAM(bool, kTabGroupsFocusingPinnedTabs);
diff --git a/chrome/browser/ui/user_education/browser_user_education_interface.h b/chrome/browser/ui/user_education/browser_user_education_interface.h index 6b7ef2e..6691519d 100644 --- a/chrome/browser/ui/user_education/browser_user_education_interface.h +++ b/chrome/browser/ui/user_education/browser_user_education_interface.h
@@ -120,7 +120,11 @@ // If determining whether to call this method would involve significant // expense, you *may* first call `CanShowFeaturePromo()` before doing the // required computation; otherwise just call this method. - virtual void MaybeShowFeaturePromo( + // + // Returns true if the promo is shown *or* queued; false if it was rejected + // right away. This can be used to make snap decisions on whether to show UI + // that could interfere with an IPH. + virtual bool MaybeShowFeaturePromo( user_education::FeaturePromoParams params) = 0; // Maybe shows an in-product help promo at startup, whenever the Feature @@ -143,7 +147,11 @@ // some other reason*. You can therefore safely call this method at browser // window creation, as subsequent browser windows in the same profile won't be // able to re-show the promo. - virtual void MaybeShowStartupFeaturePromo( + // + // Returns true if the promo is shown *or* queued; false if it was rejected + // right away. This can be used to make snap decisions on whether to show UI + // that could interfere with an IPH. + virtual bool MaybeShowStartupFeaturePromo( user_education::FeaturePromoParams params) = 0; // Aborts the in-product help promo for `iph_feature` if it is showing or
diff --git a/chrome/browser/ui/views/accessibility/caption_bubble_controller_views_browsertest.cc b/chrome/browser/ui/views/accessibility/caption_bubble_controller_views_browsertest.cc index 8767dc4d..f6d940e 100644 --- a/chrome/browser/ui/views/accessibility/caption_bubble_controller_views_browsertest.cc +++ b/chrome/browser/ui/views/accessibility/caption_bubble_controller_views_browsertest.cc
@@ -96,13 +96,12 @@ params["live_caption_scrollable_max_lines"] = "9"; // Same size as non-scrollable. scoped_feature_list_.InitWithFeaturesAndParameters( - {{media::kLiveTranslate, {}}, - {media::kFeatureManagementLiveTranslateCrOS, {}}, + {{media::kFeatureManagementLiveTranslateCrOS, {}}, {kLiveCaptionScrollable, params}}, {}); } else { scoped_feature_list_.InitWithFeatures( - {media::kLiveTranslate, media::kFeatureManagementLiveTranslateCrOS}, + {media::kFeatureManagementLiveTranslateCrOS}, {captions::kLiveCaptionScrollable}); } }
diff --git a/chrome/browser/ui/views/autofill/popup/popup_view_views.cc b/chrome/browser/ui/views/autofill/popup/popup_view_views.cc index 07dbfc23..6e6e5ac8 100644 --- a/chrome/browser/ui/views/autofill/popup/popup_view_views.cc +++ b/chrome/browser/ui/views/autofill/popup/popup_view_views.cc
@@ -839,6 +839,10 @@ return controller_->HandleKeyPressEvent(input::NativeWebKeyboardEvent(event)); } +void PopupViewViews::TabSelectedAt(int index) { + controller_->SetFilter(SuggestionTabIndex(index)); +} + void PopupViewViews::SetSelectedCell( std::optional<CellIndex> cell_index, PopupCellSelectionSource source, @@ -1275,6 +1279,10 @@ // Calculate and set the preferred size for the tabbed pane based on its // contents. tabbed_pane->SetPreferredSize(tabbed_pane->GetPreferredSize()); + tabbed_pane->SetListener(this); + + // Filter suggestions for the default tab. + controller_->SetFilter(kDefaultSuggestionTabIndex); tabbed_pane_ = AddChildView(std::move(tabbed_pane)); }
diff --git a/chrome/browser/ui/views/autofill/popup/popup_view_views.h b/chrome/browser/ui/views/autofill/popup/popup_view_views.h index 13e80c1..b483c7f 100644 --- a/chrome/browser/ui/views/autofill/popup/popup_view_views.h +++ b/chrome/browser/ui/views/autofill/popup/popup_view_views.h
@@ -29,6 +29,7 @@ #include "ui/base/interaction/element_identifier.h" #include "ui/base/metadata/metadata_header_macros.h" #include "ui/events/event.h" +#include "ui/views/controls/tabbed_pane/tabbed_pane_listener.h" #include "ui/views/widget/widget.h" namespace views { @@ -67,7 +68,8 @@ public AutofillPopupView, public PopupRowView::SelectionDelegate, public ExpandablePopupParentView, - public PopupSearchBarView::Delegate { + public PopupSearchBarView::Delegate, + public views::TabbedPaneListener { METADATA_HEADER(PopupViewViews, PopupBaseView) public: @@ -162,6 +164,9 @@ void SearchBarOnFocusLost() override; bool SearchBarHandleKeyPressed(const ui::KeyEvent& event) override; + // TabbedPaneListener:: + void TabSelectedAt(int index) override; + private: friend class PopupViewViewsTestApi;
diff --git a/chrome/browser/ui/views/autofill/popup/popup_view_views_unittest.cc b/chrome/browser/ui/views/autofill/popup/popup_view_views_unittest.cc index ae658c77..a1988637 100644 --- a/chrome/browser/ui/views/autofill/popup/popup_view_views_unittest.cc +++ b/chrome/browser/ui/views/autofill/popup/popup_view_views_unittest.cc
@@ -2485,6 +2485,22 @@ EXPECT_EQ(tabbed_pane->GetTabAt(1)->GetTitleText(), u"Pay Later Test"); } +TEST_F(PopupViewViewsTest, TabbedPane_SuggestionFilteredForInitialShow) { + AutofillPopupView::TabbedPaneConfig tabbed_pane_config( + {{AutofillPopupView::TabbedPaneConfig::TabType::kPayNow, u"Pay Now Test"}, + {AutofillPopupView::TabbedPaneConfig::TabType::kPayLater, + u"Pay Later Test"}}); + + EXPECT_CALL(controller(), + SetFilter(Eq(AutofillPopupController::SuggestionFilter( + kDefaultSuggestionTabIndex)))); + + CreateAndShowView({SuggestionType::kCreditCardEntry}, + /*widget_params=*/std::nullopt, + /*search_bar_config=*/std::nullopt, + std::move(tabbed_pane_config)); +} + TEST_F(PopupViewViewsTest, WarningOnShowA11yFocus) { views::test::AXEventCounter counter(views::AXUpdateNotifier::Get()); CreateAndShowView({SuggestionType::kMixedFormMessage}); @@ -2631,5 +2647,13 @@ EXPECT_TRUE(test_api(view()).HandleKeyPressEvent(event)); } +TEST_F(PopupViewViewsTest, TabSelectionUpdatesSuggestionFilter) { + CreateAndShowView(); + EXPECT_CALL(controller(), + SetFilter(Eq(AutofillPopupController::SuggestionFilter( + SuggestionTabIndex(3))))); + view().TabSelectedAt(3); +} + } // namespace } // namespace autofill
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view_browsertest.cc b/chrome/browser/ui/views/bookmarks/bookmark_bar_view_browsertest.cc index 31ed121..bf846f8 100644 --- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view_browsertest.cc +++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view_browsertest.cc
@@ -30,6 +30,7 @@ #include "chrome/browser/ui/views/bookmarks/bookmark_bar_view_test_helper.h" #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/common/chrome_paths.h" +#include "chrome/common/pref_names.h" #include "chrome/common/url_constants.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" @@ -1059,6 +1060,55 @@ kFinalStatusActivated, 1); } +// Verifies that metrics are recorded when interacting with bookmark buttons. +IN_PROC_BROWSER_TEST_F( + PreloadBookmarkBarPrefetchEnabledPrerenderEnabledNavigationTest, + MetricsRecording) { + StartServers(); + base::HistogramTester histogram_tester; + + ASSERT_TRUE(ui_test_utils::NavigateToURL( + browser(), https_test_server()->GetURL("/empty.html"))); + + GURL preload_url = https_test_server()->GetURL("/empty.html?preload"); + + CreateBookmarkButton(preload_url); + views::LabelButton* button = GetBookmarkButton(0); + + gfx::Point center(10, 10); + + EXPECT_EQ(0, browser()->profile()->GetPrefs()->GetInt64( + prefs::kBookmarkBarHoverCount)); + EXPECT_EQ(0, browser()->profile()->GetPrefs()->GetInt64( + prefs::kBookmarkBarNavigationCount)); + + // Trigger on-hover recording. + button->OnMouseEntered(ui::MouseEvent(ui::EventType::kMouseEntered, center, + center, ui::EventTimeForNow(), + /*flags=*/ui::EF_NONE, + /*changed_button_flags=*/ui::EF_NONE)); + + EXPECT_EQ(1, browser()->profile()->GetPrefs()->GetInt64( + prefs::kBookmarkBarHoverCount)); + EXPECT_EQ(0, browser()->profile()->GetPrefs()->GetInt64( + prefs::kBookmarkBarNavigationCount)); + + content::TestNavigationObserver observer( + browser()->tab_strip_model()->GetActiveWebContents(), 1); + ; + // Trigger navigation recording. + button->OnMousePressed(ui::MouseEvent( + ui::EventType::kMousePressed, center, center, ui::EventTimeForNow(), + ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON)); + button->OnMouseReleased(ui::MouseEvent( + ui::EventType::kMouseReleased, center, center, ui::EventTimeForNow(), + ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON)); + observer.Wait(); + + EXPECT_EQ(1, browser()->profile()->GetPrefs()->GetInt64( + prefs::kBookmarkBarNavigationCount)); +} + namespace { class BookmarkBarTest : public BookmarkBarTestBase {
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_button.cc b/chrome/browser/ui/views/bookmarks/bookmark_button.cc index ca72c436..56e9679 100644 --- a/chrome/browser/ui/views/bookmarks/bookmark_button.cc +++ b/chrome/browser/ui/views/bookmarks/bookmark_button.cc
@@ -14,6 +14,7 @@ #include "chrome/browser/preloading/bookmarkbar_preload/bookmarkbar_preload_pipeline_manager.h" #include "chrome/browser/preloading/chrome_preloading.h" #include "chrome/browser/preloading/prerender/prerender_manager.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/layout_constants.h" #include "chrome/browser/ui/tabs/public/tab_features.h" @@ -22,7 +23,9 @@ #include "chrome/browser/ui/views/bookmarks/bookmark_button_util.h" #include "chrome/browser/ui/views/event_utils.h" #include "chrome/browser/ui/views/toolbar/toolbar_ink_drop_util.h" +#include "chrome/common/pref_names.h" #include "chrome/grit/generated_resources.h" +#include "components/prefs/pref_service.h" #include "content/public/browser/navigation_handle.h" #include "content/public/browser/preloading_data.h" #include "content/public/browser/web_contents.h" @@ -114,6 +117,18 @@ BookmarkButton::~BookmarkButton() = default; +void BookmarkButton::OnButtonPressed(const ui::Event& event) { + if (base::FeatureList::IsEnabled(features::kBookmarkTriggerForPrefetch) && + browser_) { + browser_->profile()->GetPrefs()->SetInt64( + prefs::kBookmarkBarNavigationCount, + browser_->profile()->GetPrefs()->GetInt64( + prefs::kBookmarkBarNavigationCount) + + 1); + } + callback_.Run(event); +} + void BookmarkButton::AddedToWidget() { BookmarkButtonBase::AddedToWidget(); @@ -168,6 +183,15 @@ BookmarkButtonBase::OnMouseEntered(event); + if (base::FeatureList::IsEnabled(features::kBookmarkTriggerForPrefetch) && + browser_) { + browser_->profile()->GetPrefs()->SetInt64( + prefs::kBookmarkBarHoverCount, + browser_->profile()->GetPrefs()->GetInt64( + prefs::kBookmarkBarHoverCount) + + 1); + } + if (base::FeatureList::IsEnabled(features::kBookmarkTriggerForPreconnect)) { preconnect_timer_.Start( FROM_HERE,
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_button.h b/chrome/browser/ui/views/bookmarks/bookmark_button.h index b58e324..5a55c7e 100644 --- a/chrome/browser/ui/views/bookmarks/bookmark_button.h +++ b/chrome/browser/ui/views/bookmarks/bookmark_button.h
@@ -57,7 +57,7 @@ BookmarkButton& operator=(const BookmarkButton&) = delete; ~BookmarkButton() override; - void OnButtonPressed(const ui::Event& event) { callback_.Run(event); } + void OnButtonPressed(const ui::Event& event); void UpdateTooltipText();
diff --git a/chrome/browser/ui/views/bookmarks/saved_tab_groups/resumption_rail_iph_test.cc b/chrome/browser/ui/views/bookmarks/saved_tab_groups/resumption_rail_iph_test.cc index 96e64bc..f538e9c1 100644 --- a/chrome/browser/ui/views/bookmarks/saved_tab_groups/resumption_rail_iph_test.cc +++ b/chrome/browser/ui/views/bookmarks/saved_tab_groups/resumption_rail_iph_test.cc
@@ -6,26 +6,32 @@ #include "base/strings/stringprintf.h" #include "base/test/scoped_feature_list.h" #include "base/uuid.h" +#include "chrome/browser/autocomplete/aim_eligibility_service_factory.h" +#include "chrome/browser/glic/public/glic_enabling.h" #include "chrome/browser/tab_group_sync/tab_group_sync_service_factory.h" #include "chrome/browser/ui/bookmarks/bookmark_bar.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_commands.h" #include "chrome/browser/ui/browser_element_identifiers.h" #include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/browser_window/public/browser_window_features.h" #include "chrome/browser/ui/tabs/features.h" +#include "chrome/browser/ui/tabs/projects/projects_panel_state_controller.h" #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.h" #include "chrome/browser/ui/tabs/tab_group_theme.h" #include "chrome/browser/ui/tabs/vertical_tab_strip_state_controller.h" #include "chrome/browser/ui/ui_features.h" -#include "chrome/browser/ui/user_education/browser_user_education_interface.h" #include "chrome/browser/ui/views/bookmarks/bookmark_bar_view.h" #include "chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_everything_menu.h" #include "chrome/browser/ui/views/tabs/projects/projects_panel_view.h" #include "chrome/common/pref_names.h" +#include "chrome/grit/generated_resources.h" #include "chrome/test/interaction/interactive_browser_test.h" #include "chrome/test/user_education/interactive_feature_promo_test.h" #include "components/bookmarks/common/bookmark_pref_names.h" #include "components/feature_engagement/public/feature_list.h" +#include "components/keyed_service/content/browser_context_dependency_manager.h" +#include "components/omnibox/browser/aim_eligibility_service.h" #include "components/prefs/pref_service.h" #include "components/saved_tab_groups/public/features.h" #include "components/saved_tab_groups/public/saved_tab_group.h" @@ -35,11 +41,34 @@ #include "components/user_education/views/help_bubble_view.h" #include "content/public/test/browser_test.h" #include "ui/base/interaction/element_identifier.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/views/controls/label.h" namespace { constexpr int kNumTabGroupsToForceOverflow = 30; } // namespace +class MockProjectsPanelStateController : public ProjectsPanelStateController { + public: + explicit MockProjectsPanelStateController( + BrowserWindowInterface* browser_window, + bool* can_show_aim, + bool* can_show_gemini) + : ProjectsPanelStateController(browser_window, + /*root_action_item=*/nullptr, + /*aim_eligibility_service=*/nullptr, + /*glic_enabling=*/nullptr), + can_show_aim_(can_show_aim), + can_show_gemini_(can_show_gemini) {} + + bool CanShowAimThreads() override { return *can_show_aim_; } + bool CanShowGeminiThreads() override { return *can_show_gemini_; } + + private: + raw_ptr<bool> can_show_aim_; + raw_ptr<bool> can_show_gemini_; +}; + class ResumptionRailPromoTest : public InteractiveFeaturePromoTest { public: ResumptionRailPromoTest() @@ -55,6 +84,27 @@ ~ResumptionRailPromoTest() override = default; + void SetUpInProcessBrowserTestFixture() override { + InteractiveFeaturePromoTest::SetUpInProcessBrowserTestFixture(); + projects_panel_override_ = + BrowserWindowFeatures::GetUserDataFactoryForTesting() + .AddOverrideForTesting<MockProjectsPanelStateController>( + base::BindRepeating( + [](bool* can_show_aim, bool* can_show_gemini, + BrowserWindowInterface& browser) + -> std::unique_ptr<MockProjectsPanelStateController> { + return std::make_unique<MockProjectsPanelStateController>( + &browser, can_show_aim, can_show_gemini); + }, + base::Unretained(&can_show_aim_), + base::Unretained(&can_show_gemini_))); + } + + void TearDownInProcessBrowserTestFixture() override { + projects_panel_override_ = ui::UserDataFactory::ScopedOverride(); + InteractiveFeaturePromoTest::TearDownInProcessBrowserTestFixture(); + } + void SetUpOnMainThread() override { InteractiveFeaturePromoTest::SetUpOnMainThread(); browser()->profile()->GetPrefs()->SetBoolean( @@ -91,11 +141,34 @@ }); } + protected: + bool can_show_aim_ = false; + bool can_show_gemini_ = false; + private: base::test::ScopedFeatureList feature_list_; + ui::UserDataFactory::ScopedOverride projects_panel_override_; }; -IN_PROC_BROWSER_TEST_F(ResumptionRailPromoTest, TriggerPromo) { +struct ResumptionRailPromoBodyTestCase { + bool can_show_aim; + bool can_show_gemini; + int expected_string_id; + std::string test_name; +}; + +class ResumptionRailPromoBodyTest + : public ResumptionRailPromoTest, + public testing::WithParamInterface<ResumptionRailPromoBodyTestCase> { + public: + void SetUpOnMainThread() override { + can_show_aim_ = GetParam().can_show_aim; + can_show_gemini_ = GetParam().can_show_gemini; + ResumptionRailPromoTest::SetUpOnMainThread(); + } +}; + +IN_PROC_BROWSER_TEST_P(ResumptionRailPromoBodyTest, CheckPromoString) { RunTestSequence(WaitForShow(kBookmarkBarElementId), Do([this]() { RunScheduledLayouts(); }), WaitForShow(kVerticalTabStripProjectsButtonElementId), @@ -107,11 +180,45 @@ PressButton(kSavedTabGroupOverflowButtonElementId), // The IPH SHOULD trigger, and the menu should not open. WaitForPromo(feature_engagement::kIPHResumptionRailFeature), + // Check the IPH body text. + CheckViewProperty( + user_education::HelpBubbleView::kBodyTextIdForTesting, + &views::Label::GetText, + l10n_util::GetStringUTF16(GetParam().expected_string_id)), // Click the new Projects button to dismiss the promo. PressButton(kVerticalTabStripProjectsButtonElementId), + // Should hide the Everything menu button. WaitForHide(kSavedTabGroupOverflowButtonElementId)); } +INSTANTIATE_TEST_SUITE_P( + All, + ResumptionRailPromoBodyTest, + testing::Values( + ResumptionRailPromoBodyTestCase{ + .can_show_aim = false, + .can_show_gemini = false, + .expected_string_id = IDS_RESUMPTION_RAIL_IPH_BODY_NO_THREADS, + .test_name = "NoThreads"}, + ResumptionRailPromoBodyTestCase{ + .can_show_aim = true, + .can_show_gemini = false, + .expected_string_id = IDS_RESUMPTION_RAIL_IPH_BODY_ONLY_AI_MODE, + .test_name = "OnlyAim"}, + ResumptionRailPromoBodyTestCase{ + .can_show_aim = false, + .can_show_gemini = true, + .expected_string_id = IDS_RESUMPTION_RAIL_IPH_BODY_ONLY_GEMINI, + .test_name = "OnlyGemini"}, + ResumptionRailPromoBodyTestCase{ + .can_show_aim = true, + .can_show_gemini = true, + .expected_string_id = IDS_RESUMPTION_RAIL_IPH_BODY, + .test_name = "Both"}), + [](const testing::TestParamInfo<ResumptionRailPromoBodyTestCase>& info) { + return info.param.test_name; + }); + IN_PROC_BROWSER_TEST_F(ResumptionRailPromoTest, OpenProjectsPanelThenTriggerPromo) { RunTestSequence(WaitForShow(kBookmarkBarElementId),
diff --git a/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_bar.cc b/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_bar.cc index 6669d88..caf057f 100644 --- a/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_bar.cc +++ b/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_bar.cc
@@ -23,6 +23,7 @@ #include "chrome/browser/ui/browser_window/public/desktop_browser_window_capabilities.h" #include "chrome/browser/ui/color/chrome_color_id.h" #include "chrome/browser/ui/layout_constants.h" +#include "chrome/browser/ui/tabs/projects/projects_panel_state_controller.h" #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_metrics.h" #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" @@ -434,6 +435,28 @@ if (auto* interface = BrowserUserEducationInterface::From(browser_)) { user_education::FeaturePromoParams params( feature_engagement::kIPHResumptionRailFeature); + + // Determine the appropriate promo text based on the eligibility of AIM + // and Gemini threads. We default to a generic message if neither are + // available or if the controller itself isn't present. + int string_id = IDS_RESUMPTION_RAIL_IPH_BODY_NO_THREADS; + auto* projects_panel_state_controller = + ProjectsPanelStateController::From(browser_); + CHECK(projects_panel_state_controller); + const bool can_show_aim = + projects_panel_state_controller->CanShowAimThreads(); + const bool can_show_gemini = + projects_panel_state_controller->CanShowGeminiThreads(); + + if (can_show_aim && can_show_gemini) { + string_id = IDS_RESUMPTION_RAIL_IPH_BODY; + } else if (can_show_aim) { + string_id = IDS_RESUMPTION_RAIL_IPH_BODY_ONLY_AI_MODE; + } else if (can_show_gemini) { + string_id = IDS_RESUMPTION_RAIL_IPH_BODY_ONLY_GEMINI; + } + params.body_params = l10n_util::GetStringUTF16(string_id); + params.close_callback = base::BindOnce(&SavedTabGroupBar::OnResumptionRailPromoClosed, weak_ptr_factory_.GetWeakPtr());
diff --git a/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_bar_unittest.cc b/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_bar_unittest.cc index f83d7dcb..93f74e150 100644 --- a/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_bar_unittest.cc +++ b/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_bar_unittest.cc
@@ -13,7 +13,10 @@ #include "base/uuid.h" #include "chrome/browser/tab_group_sync/tab_group_sync_service_factory.h" #include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_window/public/browser_window_features.h" +#include "chrome/browser/ui/frame/window_frame_util.h" #include "chrome/browser/ui/layout_constants.h" +#include "chrome/browser/ui/tabs/projects/projects_panel_state_controller.h" #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.h" #include "chrome/browser/ui/ui_features.h" #include "chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_button.h" @@ -22,9 +25,11 @@ #include "chrome/grit/generated_resources.h" #include "chrome/test/base/test_browser_window.h" #include "chrome/test/base/testing_profile.h" +#include "chrome/test/user_education/mock_browser_user_education_interface.h" #include "chrome/test/views/chrome_views_test_base.h" #include "components/collaboration/public/features.h" #include "components/data_sharing/public/features.h" +#include "components/feature_engagement/public/feature_constants.h" #include "components/prefs/pref_service.h" #include "components/saved_tab_groups/internal/tab_group_sync_service_impl.h" #include "components/saved_tab_groups/public/collaboration_finder.h" @@ -59,6 +64,18 @@ const tab_groups::TabGroupColorId kNewColor = tab_groups::TabGroupColorId::kRed; } // anonymous namespace +class MockProjectsPanelStateController : public ProjectsPanelStateController { + public: + explicit MockProjectsPanelStateController( + BrowserWindowInterface* browser_window) + : ProjectsPanelStateController(browser_window, + /*root_action_item=*/nullptr, + /*aim_eligibility_service=*/nullptr, + /*glic_enabling=*/nullptr) {} + MOCK_METHOD(bool, CanShowAimThreads, (), (override)); + MOCK_METHOD(bool, CanShowGeminiThreads, (), (override)); +}; + class SavedTabGroupBarUnitTest : public TestWithBrowserView { public: SavedTabGroupBarUnitTest() : SavedTabGroupBarUnitTest(true) {} @@ -636,4 +653,148 @@ EXPECT_EQ(focused_group.value(), local_id); } +// Tests the integration between SavedTabGroupBar and +// ProjectsPanelStateController, specifically verifying that the Resumption Rail +// IPH promo text adapts correctly based on whether AIM and/or Gemini threads +// are available. +class SavedTabGroupBarProjectsPanelUnitTest : public SavedTabGroupBarUnitTest { + public: + SavedTabGroupBarProjectsPanelUnitTest() : SavedTabGroupBarUnitTest(false) { + feature_list_.InitWithFeatures( + /*enabled_features=*/{tab_groups::kProjectsPanel, + data_sharing::features::kDataSharingFeature}, + {collaboration::features::kCollaborationMessaging}); + } + + void SetUp() override { + user_ed_override_ = + BrowserWindowFeatures::GetUserDataFactoryForTesting() + .AddOverrideForTesting<MockBrowserUserEducationInterface>( + base::BindRepeating( + [](raw_ptr<MockBrowserUserEducationInterface>* out_mock, + BrowserWindowInterface& browser) + -> std::unique_ptr<MockBrowserUserEducationInterface> { + auto mock = std::make_unique< + testing::NiceMock<MockBrowserUserEducationInterface>>( + &browser); + *out_mock = mock.get(); + return mock; + }, + base::Unretained(&mock_user_education_interface_))); + + projects_panel_override_ = + BrowserWindowFeatures::GetUserDataFactoryForTesting() + .AddOverrideForTesting<MockProjectsPanelStateController>( + base::BindRepeating( + [](raw_ptr<MockProjectsPanelStateController>* out_mock, + BrowserWindowInterface& browser) + -> std::unique_ptr<MockProjectsPanelStateController> { + auto mock = std::make_unique< + testing::NiceMock<MockProjectsPanelStateController>>( + &browser); + *out_mock = mock.get(); + return mock; + }, + base::Unretained(&mock_projects_panel_state_controller_))); + + SavedTabGroupBarUnitTest::SetUp(); + } + + void TearDown() override { + mock_user_education_interface_ = nullptr; + mock_projects_panel_state_controller_ = nullptr; + user_ed_override_ = ui::UserDataFactory::ScopedOverride(); + projects_panel_override_ = ui::UserDataFactory::ScopedOverride(); + SavedTabGroupBarUnitTest::TearDown(); + } + + MockProjectsPanelStateController* projects_panel_state_controller() { + return mock_projects_panel_state_controller_; + } + + MockBrowserUserEducationInterface* user_education_interface() { + return mock_user_education_interface_; + } + + private: + base::test::ScopedFeatureList feature_list_; + ui::UserDataFactory::ScopedOverride user_ed_override_; + ui::UserDataFactory::ScopedOverride projects_panel_override_; + raw_ptr<MockBrowserUserEducationInterface> mock_user_education_interface_ = + nullptr; + raw_ptr<MockProjectsPanelStateController> + mock_projects_panel_state_controller_ = nullptr; +}; + +// Test parameters for verifying the dynamic IPH body string resolution +// based on the user's eligibility for AIM and Gemini threads. +struct ResumptionRailIPHBodyTestCase { + bool can_show_aim; + bool can_show_gemini; + int expected_string_id; + std::string test_name; +}; + +class SavedTabGroupBarResumptionRailIPHTest + : public SavedTabGroupBarProjectsPanelUnitTest, + public testing::WithParamInterface<ResumptionRailIPHBodyTestCase> {}; + +TEST_P(SavedTabGroupBarResumptionRailIPHTest, SetsCorrectBodyString) { + const auto& param = GetParam(); + + // Setup mock eligibility. + EXPECT_CALL(*projects_panel_state_controller(), CanShowAimThreads()) + .WillRepeatedly(testing::Return(param.can_show_aim)); + EXPECT_CALL(*projects_panel_state_controller(), CanShowGeminiThreads()) + .WillRepeatedly(testing::Return(param.can_show_gemini)); + + // Capture the promo parameters to inspect the body string. + std::optional<user_education::FeaturePromoParams> captured_params; + EXPECT_CALL(*user_education_interface(), MaybeShowFeaturePromo) + .WillOnce([&](user_education::FeaturePromoParams params) { + captured_params = std::move(params); + return true; + }); + + // Trigger the IPH. + saved_tab_group_bar()->ShowEverythingMenu(); + + // Verify the correct string was passed. + ASSERT_TRUE(captured_params); + EXPECT_EQ(&feature_engagement::kIPHResumptionRailFeature, + &*captured_params->feature); + EXPECT_TRUE( + std::holds_alternative<std::u16string>(captured_params->body_params)); + EXPECT_EQ(std::get<std::u16string>(captured_params->body_params), + l10n_util::GetStringUTF16(param.expected_string_id)); +} + +INSTANTIATE_TEST_SUITE_P( + All, + SavedTabGroupBarResumptionRailIPHTest, + testing::Values( + ResumptionRailIPHBodyTestCase{ + .can_show_aim = false, + .can_show_gemini = false, + .expected_string_id = IDS_RESUMPTION_RAIL_IPH_BODY_NO_THREADS, + .test_name = "NoThreads"}, + ResumptionRailIPHBodyTestCase{ + .can_show_aim = false, + .can_show_gemini = true, + .expected_string_id = IDS_RESUMPTION_RAIL_IPH_BODY_ONLY_GEMINI, + .test_name = "OnlyGemini"}, + ResumptionRailIPHBodyTestCase{ + .can_show_aim = true, + .can_show_gemini = false, + .expected_string_id = IDS_RESUMPTION_RAIL_IPH_BODY_ONLY_AI_MODE, + .test_name = "OnlyAim"}, + ResumptionRailIPHBodyTestCase{ + .can_show_aim = true, + .can_show_gemini = true, + .expected_string_id = IDS_RESUMPTION_RAIL_IPH_BODY, + .test_name = "Both"}), + [](const testing::TestParamInfo<ResumptionRailIPHBodyTestCase>& info) { + return info.param.test_name; + }); + } // namespace tab_groups
diff --git a/chrome/browser/ui/views/download/BUILD.gn b/chrome/browser/ui/views/download/BUILD.gn index 1863fa6..18598ca2 100644 --- a/chrome/browser/ui/views/download/BUILD.gn +++ b/chrome/browser/ui/views/download/BUILD.gn
@@ -6,7 +6,6 @@ source_set("download") { sources = [ - "download_danger_prompt_views.cc", "download_in_progress_dialog_view.cc", "download_in_progress_dialog_view.h", ]
diff --git a/chrome/browser/ui/views/download/bubble/download_bubble_interactive_uitest.cc b/chrome/browser/ui/views/download/bubble/download_bubble_interactive_uitest.cc index 7274259..7e4bda6 100644 --- a/chrome/browser/ui/views/download/bubble/download_bubble_interactive_uitest.cc +++ b/chrome/browser/ui/views/download/bubble/download_bubble_interactive_uitest.cc
@@ -18,6 +18,7 @@ #include "chrome/browser/ui/browser_element_identifiers.h" #include "chrome/browser/ui/browser_window/public/browser_window_features.h" #include "chrome/browser/ui/exclusive_access/exclusive_access_test.h" +#include "chrome/browser/ui/ui_features.h" #include "chrome/browser/ui/views/download/bubble/download_bubble_contents_view.h" #include "chrome/browser/ui/views/download/bubble/download_toolbar_ui_controller.h" #include "chrome/browser/ui/views/exclusive_access_bubble_views.h" @@ -303,9 +304,12 @@ } views::View* GetContainerView() { - return BrowserView::GetBrowserViewForBrowser(browser()) - ->toolbar() - ->pinned_toolbar_actions_container(); + CHECK(!features::IsWebUIPinnedToolbarActionsEnabled()) + << "Test needs modification to support WebUIPinnedToolbarActions"; + return static_cast<PinnedToolbarActionsContainer*>( + BrowserView::GetBrowserViewForBrowser(browser()) + ->toolbar() + ->pinned_toolbar_actions()); } private:
diff --git a/chrome/browser/ui/views/download/download_danger_prompt_views.cc b/chrome/browser/ui/views/download/download_danger_prompt_views.cc deleted file mode 100644 index c222109..0000000 --- a/chrome/browser/ui/views/download/download_danger_prompt_views.cc +++ /dev/null
@@ -1,258 +0,0 @@ -// Copyright 2013 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/compiler_specific.h" -#include "base/feature_list.h" -#include "base/memory/raw_ptr.h" -#include "base/notreached.h" -#include "base/strings/utf_string_conversions.h" -#include "chrome/browser/download/download_danger_prompt.h" -#include "chrome/browser/download/download_stats.h" -#include "chrome/browser/download/download_ui_safe_browsing_util.h" -#include "chrome/browser/profiles/profile.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/ui/hats/trust_safety_sentiment_service.h" -#include "chrome/browser/ui/hats/trust_safety_sentiment_service_factory.h" -#include "chrome/browser/ui/views/chrome_layout_provider.h" -#include "chrome/grit/branded_strings.h" -#include "chrome/grit/generated_resources.h" -#include "components/constrained_window/constrained_window_views.h" -#include "components/download/public/common/download_danger_type.h" -#include "components/download/public/common/download_item.h" -#include "components/safe_browsing/core/common/features.h" -#include "components/safe_browsing/core/common/safe_browsing_prefs.h" -#include "components/strings/grit/components_strings.h" -#include "content/public/browser/browser_context.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/download_item_utils.h" -#include "content/public/browser/web_contents.h" -#include "ui/base/buildflags.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/metadata/metadata_header_macros.h" -#include "ui/base/metadata/metadata_impl_macros.h" -#include "ui/base/mojom/dialog_button.mojom.h" -#include "ui/base/mojom/ui_base_types.mojom-shared.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/views/controls/label.h" -#include "ui/views/layout/fill_layout.h" -#include "ui/views/window/dialog_delegate.h" -#include "url/gurl.h" - -using safe_browsing::ClientSafeBrowsingReportRequest; - -// Views-specific implementation of download danger prompt dialog, which -// implements danger warning bypass from the downloads extension API. We use -// this class rather than a TabModalConfirmDialog so that we can use custom -// formatting on the text in the body of the dialog. -// TODO(chlily): This probably does not handle (both dangerous and) insecure -// downloads very coherently. -class DownloadDangerPromptViews : public DownloadDangerPrompt, - public download::DownloadItem::Observer, - public views::DialogDelegateView { - METADATA_HEADER(DownloadDangerPromptViews, views::DialogDelegateView) - - public: - DownloadDangerPromptViews(download::DownloadItem* item, - Profile* profile, - OnDone done); - ~DownloadDangerPromptViews() override; - - // DownloadDangerPrompt: - void InvokeActionForTesting(Action action) override; - - // views::DialogDelegateView: - std::u16string GetWindowTitle() const override; - - // download::DownloadItem::Observer: - void OnDownloadUpdated(download::DownloadItem* download) override; - - private: - std::u16string GetMessageBody() const; - void RunDone(Action action); - - raw_ptr<download::DownloadItem> download_; - raw_ptr<Profile> profile_; - OnDone done_; -}; - -DownloadDangerPromptViews::DownloadDangerPromptViews( - download::DownloadItem* item, - Profile* profile, - OnDone done) - : download_(item), profile_(profile), done_(std::move(done)) { - // Note that this prompt is asking whether to cancel a dangerous download, so - // the accept path is titled "Cancel". - SetButtonLabel(ui::mojom::DialogButton::kOk, - l10n_util::GetStringUTF16(IDS_CANCEL)); - SetButtonLabel(ui::mojom::DialogButton::kCancel, - l10n_util::GetStringUTF16(IDS_CONFIRM_DOWNLOAD)); - SetModalType(ui::mojom::ModalType::kChild); - - set_fixed_width(views::LayoutProvider::Get()->GetDistanceMetric( - views::DISTANCE_BUBBLE_PREFERRED_WIDTH)); - - auto make_done_callback = [&](DownloadDangerPrompt::Action action) { - return base::BindOnce(&DownloadDangerPromptViews::RunDone, - base::Unretained(this), action); - }; - - // Note that the presentational concept of "Accept/Cancel" is inverted from - // the model's concept of ACCEPT/CANCEL. In the UI, the safe path is "Accept" - // and the dangerous path is "Cancel". - SetAcceptCallback(make_done_callback(CANCEL)); - SetCancelCallback(make_done_callback(ACCEPT)); - SetCloseCallback(make_done_callback(DISMISS)); - - download_->AddObserver(this); - - set_margins(ChromeLayoutProvider::Get()->GetDialogInsetsForContentType( - views::DialogContentType::kText, views::DialogContentType::kText)); - SetUseDefaultFillLayout(true); - - auto message_body_label = std::make_unique<views::Label>(GetMessageBody()); - message_body_label->SetMultiLine(true); - message_body_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); - message_body_label->SetAllowCharacterBreak(true); - - AddChildView(std::move(message_body_label)); -} - -DownloadDangerPromptViews::~DownloadDangerPromptViews() { - if (download_) { - download_->RemoveObserver(this); - } -} - -// DownloadDangerPrompt methods: -void DownloadDangerPromptViews::InvokeActionForTesting(Action action) { - switch (action) { - case ACCEPT: - // This inversion is intentional. - Cancel(); - break; - - case DISMISS: - Close(); - break; - - case CANCEL: - Accept(); - break; - - default: - NOTREACHED(); - } -} - -// views::DialogDelegate methods: -std::u16string DownloadDangerPromptViews::GetWindowTitle() const { - return l10n_util::GetStringUTF16(IDS_CONFIRM_KEEP_DANGEROUS_DOWNLOAD_TITLE); -} - -// download::DownloadItem::Observer: -void DownloadDangerPromptViews::OnDownloadUpdated( - download::DownloadItem* download) { - // If the download is nolonger dangerous (accepted externally) or the download - // is in a terminal state, then the download danger prompt is no longer - // necessary. - if (!download_->IsDangerous() || download_->IsDone()) { - RunDone(DISMISS); - Cancel(); - } -} - -std::u16string DownloadDangerPromptViews::GetMessageBody() const { - std::u16string filename = - download_->GetFileNameToReportUser().LossyDisplayName(); - switch (download_->GetDangerType()) { - case download::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE: - return l10n_util::GetStringFUTF16(IDS_PROMPT_DANGEROUS_DOWNLOAD, - filename); - case download::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL: - case download::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT: - case download::DOWNLOAD_DANGER_TYPE_DANGEROUS_ACCOUNT_COMPROMISE: - case download::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: - return l10n_util::GetStringFUTF16(IDS_PROMPT_MALICIOUS_DOWNLOAD_CONTENT, - filename); - case download::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT: - return l10n_util::GetStringFUTF16( - safe_browsing::AdvancedProtectionStatusManagerFactory::GetForProfile( - profile_) - ->IsUnderAdvancedProtection() - ? IDS_PROMPT_UNCOMMON_DOWNLOAD_CONTENT_IN_ADVANCED_PROTECTION - : IDS_PROMPT_UNCOMMON_DOWNLOAD_CONTENT, - filename); - case download::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED: - return l10n_util::GetStringFUTF16(IDS_PROMPT_DOWNLOAD_CHANGES_SETTINGS, - filename); - default: - NOTREACHED(); - } -} - -void DownloadDangerPromptViews::RunDone(Action action) { - // Invoking the callback can cause the download item state to change or cause - // the window to close, and |callback| refers to a member variable. - OnDone done = std::move(done_); - if (download_) { - const bool accept = action == DownloadDangerPrompt::ACCEPT; - // If this download is no longer dangerous, is already canceled or - // completed, don't send any report. - if (download_->IsDangerous() && !download_->IsDone()) { - // Survey triggered on ACCEPT action, since this is where the user - // confirms their choice to keep a dangerous download, rather than - // triggering a survey after selecting to KEEP in the downloads page UI. - if (safe_browsing::IsSafeBrowsingSurveysEnabled(*profile_->GetPrefs()) && - accept) { - TrustSafetySentimentService* trust_safety_sentiment_service = - TrustSafetySentimentServiceFactory::GetForProfile(profile_); - if (trust_safety_sentiment_service) { - trust_safety_sentiment_service->InteractedWithDownloadWarningUI( - DownloadItemWarningData::WarningSurface::DOWNLOAD_PROMPT, - DownloadItemWarningData::WarningAction::PROCEED); - } - } - // Log here for "Shown" unconditionally, and for "Proceed" iff the dialog - // was accepted. This assumes the dialog cannot be dismissed once it is - // shown without taking some action on it. - RecordDownloadDangerPromptHistogram("Shown", *download_); - if (accept) { - RecordDownloadDangerPromptHistogram("Proceed", *download_); - } - RecordDownloadWarningEvent(action, download_); -#if BUILDFLAG(SAFE_BROWSING_AVAILABLE) - // Do not send cancel report since it's not a terminal action. - if (accept) { - SendSafeBrowsingDownloadReport( - ClientSafeBrowsingReportRequest::DANGEROUS_DOWNLOAD_BY_API, accept, - download_); - } -#endif - } - download_->RemoveObserver(this); - download_ = nullptr; - } - if (done) { - std::move(done).Run(action); - } -} - -BEGIN_METADATA(DownloadDangerPromptViews) -ADD_READONLY_PROPERTY_METADATA(std::u16string, MessageBody) -END_METADATA - -// static -DownloadDangerPrompt* DownloadDangerPrompt::Create( - download::DownloadItem* item, - content::WebContents* web_contents, - OnDone done) { - Profile* profile = - Profile::FromBrowserContext(web_contents->GetBrowserContext()); - DownloadDangerPromptViews* download_danger_prompt = - new DownloadDangerPromptViews(item, profile, std::move(done)); - constrained_window::ShowWebModalDialogViews(download_danger_prompt, - web_contents); - return download_danger_prompt; -}
diff --git a/chrome/browser/ui/views/extensions/extensions_toolbar_desktop.cc b/chrome/browser/ui/views/extensions/extensions_toolbar_desktop.cc index 7182f309..e3756f4 100644 --- a/chrome/browser/ui/views/extensions/extensions_toolbar_desktop.cc +++ b/chrome/browser/ui/views/extensions/extensions_toolbar_desktop.cc
@@ -744,8 +744,8 @@ } void ExtensionsToolbarDesktop::OnActiveWebContentsChanged( - bool is_same_document) { - content::WebContents* current_web_contents = GetCurrentWebContents(); + bool is_same_document, + content::WebContents* current_web_contents) { if (active_web_contents_.get() != current_web_contents) { // Tab switched BrowserUserEducationInterface::From(browser_)
diff --git a/chrome/browser/ui/views/extensions/extensions_toolbar_desktop.h b/chrome/browser/ui/views/extensions/extensions_toolbar_desktop.h index 344bb379..6bf9fc67 100644 --- a/chrome/browser/ui/views/extensions/extensions_toolbar_desktop.h +++ b/chrome/browser/ui/views/extensions/extensions_toolbar_desktop.h
@@ -241,7 +241,8 @@ void OnActionRemoved(const ToolbarActionsModel::ActionId& action_id) override; void OnActionUpdated(const ToolbarActionsModel::ActionId& action_id) override; void OnPinnedActionsChanged() override; - void OnActiveWebContentsChanged(bool is_same_document) override; + void OnActiveWebContentsChanged(bool is_same_document, + content::WebContents* web_contents) override; void OnRequestAccessButtonParamsChanged( content::WebContents* web_contents) override; void OnToolbarControlStateUpdated() override;
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc index da492c0..3baf99bc 100644 --- a/chrome/browser/ui/views/frame/browser_view.cc +++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -1026,7 +1026,8 @@ ProjectsPanelStateController::From(browser_); if (projects_panel_state_controller) { auto projects_panel_container = std::make_unique<ProjectsPanelView>( - browser_.get(), browser_->GetActions()->root_action_item()); + browser_.get(), browser_->GetActions()->root_action_item(), + projects_panel_state_controller); projects_panel_container_ = AddChildView(std::move(projects_panel_container)); projects_panel_subscription_ = @@ -3029,8 +3030,7 @@ bool should_show = tabs::GetTabSearchPosition(browser()) == tabs::TabSearchPosition::kToolbarButton && - toolbar_->pinned_toolbar_actions_container()->IsActionPinned( - kActionTabSearch); + toolbar_->pinned_toolbar_actions()->IsActionPinned(kActionTabSearch); if (should_show) { BrowserUserEducationInterface::From(browser()) ->MaybeShowStartupFeaturePromo( @@ -4866,56 +4866,56 @@ } } - // Determine if the TabStrip exists and is capable of being clicked on. We - // might be a popup window without a TabStrip. Use `GetTabStripVisible` as the - // tabstrip might have been hidden in immersive mode. - if (GetTabStripVisible()) { - if (vertical_tab_strip_region_view_ && - vertical_tab_strip_region_view_->GetVisible()) { - // See if the mouse pointer is within the bounds of the - // VerticalTabStripRegionView. - gfx::Point test_point(point); - if (ConvertedHitTest(parent(), vertical_tab_strip_region_view_, - &test_point)) { - if (vertical_tab_strip_region_view_->IsPositionInWindowCaption( - test_point)) { - return HTCAPTION; - } - return HTCLIENT; - } else { - gfx::Point test_point2(point); - if (ConvertedHitTest(parent(), top_container_, &test_point2) && - top_container_->IsPositionInWindowCaption(test_point2)) { - return HTCAPTION; - } + if (vertical_tab_strip_region_view_ && + vertical_tab_strip_region_view_->GetVisible()) { + // See if the mouse pointer is within the bounds of the + // VerticalTabStripRegionView. + gfx::Point test_point(point); + if (ConvertedHitTest(parent(), vertical_tab_strip_region_view_, + &test_point)) { + if (vertical_tab_strip_region_view_->IsPositionInWindowCaption( + test_point)) { + return HTCAPTION; } + return HTCLIENT; } else { - // See if the mouse pointer is within the bounds of the - // HorizontalTabStripRegionView. - gfx::Point test_point(point); - if (ConvertedHitTest(parent(), horizontal_tab_strip_region_view_, - &test_point)) { - if (horizontal_tab_strip_region_view_->IsPositionInWindowCaption( - test_point)) { - return HTCAPTION; - } - return HTCLIENT; + gfx::Point test_point2(point); + if (ConvertedHitTest(parent(), top_container_, &test_point2) && + top_container_->IsPositionInWindowCaption(test_point2)) { + return HTCAPTION; } + } + } else if (GetTabStripVisible()) { + // Determine if the Horizontal TabStrip exists and is capable of being + // clicked on. We might be a popup window without a TabStrip. Use + // `GetTabStripVisible` as the tabstrip might have been hidden in immersive + // mode. - // The top few pixels of the TabStrip are a drop-shadow - as we're pretty - // starved of draggable area, let's give it to window dragging (this also - // makes sense visually). - // TODO(tluk): Investigate the impact removing this has on draggable area - // given the tab strip no longer uses shadows. - views::Widget* widget = GetWidget(); - if (!(widget->IsMaximized() || widget->IsFullscreen()) && - (point_in_browser_view_coords.y() < - (horizontal_tab_strip_region_view_->y() + kTabShadowSize))) { - // We return HTNOWHERE as this is a signal to our containing - // NonClientView that it should figure out what the correct hit-test - // code is given the mouse position... - return HTNOWHERE; + // See if the mouse pointer is within the bounds of the + // HorizontalTabStripRegionView. + gfx::Point test_point(point); + if (ConvertedHitTest(parent(), horizontal_tab_strip_region_view_, + &test_point)) { + if (horizontal_tab_strip_region_view_->IsPositionInWindowCaption( + test_point)) { + return HTCAPTION; } + return HTCLIENT; + } + + // The top few pixels of the TabStrip are a drop-shadow - as we're pretty + // starved of draggable area, let's give it to window dragging (this also + // makes sense visually). + // TODO(tluk): Investigate the impact removing this has on draggable area + // given the tab strip no longer uses shadows. + views::Widget* widget = GetWidget(); + if (!(widget->IsMaximized() || widget->IsFullscreen()) && + (point_in_browser_view_coords.y() < + (horizontal_tab_strip_region_view_->y() + kTabShadowSize))) { + // We return HTNOWHERE as this is a signal to our containing + // NonClientView that it should figure out what the correct hit-test + // code is given the mouse position... + return HTNOWHERE; } }
diff --git a/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos.cc b/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos.cc index 5017b2f..2e331f58 100644 --- a/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos.cc +++ b/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos.cc
@@ -300,11 +300,15 @@ DCHECK(browser_view->browser()); DCHECK(browser_view->GetIsNormalType()); DCHECK(browser_view->browser()->tab_strip_model()); - DCHECK(browser_view->GetLocationBarView()); - DCHECK(browser_view->GetLocationBarView()->omnibox_view()); - observed_omni_box_ = browser_view->GetLocationBarView()->omnibox_view(); - observed_omni_box_->AddObserver(this); + // TODO(crbug.com/474059135): If WebUILocationBar ship on ChromeOS, + // this will need adjustment. + if (browser_view->GetLocationBarView()) { + DCHECK(browser_view->GetLocationBarView()->omnibox_view()); + + observed_omni_box_ = browser_view->GetLocationBarView()->omnibox_view(); + observed_omni_box_->AddObserver(this); + } browser_view_->browser()->tab_strip_model()->AddObserver(this);
diff --git a/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos_browsertest.cc b/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos_browsertest.cc index 5fcc26d..63573d7 100644 --- a/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos_browsertest.cc +++ b/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos_browsertest.cc
@@ -956,14 +956,13 @@ const std::string display_id = display_unit_info->id; for (const auto& rotation : rotations_to_try) { BrowserViewLayoutWaiter browser_view_layout_waiter(browser_view()); - auto config_properties = crosapi::mojom::DisplayConfigProperties::New(); - config_properties->rotation = - crosapi::mojom::DisplayRotation::New(rotation); - crosapi::mojom::DisplayConfigResult result = + ash::DisplayConfigProperties config_properties; + config_properties.rotation = rotation; + ash::DisplayConfigResult result = cros_display_config->SetDisplayProperties( - display_id, std::move(config_properties), + display_id, config_properties, crosapi::mojom::DisplayConfigSource::kUser); - EXPECT_EQ(result, crosapi::mojom::DisplayConfigResult::kSuccess); + EXPECT_EQ(result, ash::DisplayConfigResult::kSuccess); // Wait for the browser view to change its bounds as a result of display // rotation.
diff --git a/chrome/browser/ui/views/global_media_controls/media_dialog_view_interactive_browsertest.cc b/chrome/browser/ui/views/global_media_controls/media_dialog_view_interactive_browsertest.cc index aeb2f3c..2c33eb7 100644 --- a/chrome/browser/ui/views/global_media_controls/media_dialog_view_interactive_browsertest.cc +++ b/chrome/browser/ui/views/global_media_controls/media_dialog_view_interactive_browsertest.cc
@@ -132,10 +132,9 @@ class MediaDialogViewBrowserTest : public InProcessBrowserTest { public: MediaDialogViewBrowserTest() { - feature_list_.InitWithFeatures( - {feature_engagement::kIPHLiveCaptionFeature, - media::kFeatureManagementLiveTranslateCrOS, media::kLiveTranslate}, - {}); + feature_list_.InitWithFeatures({feature_engagement::kIPHLiveCaptionFeature, + media::kFeatureManagementLiveTranslateCrOS}, + {}); } MediaDialogViewBrowserTest(const MediaDialogViewBrowserTest&) = delete;
diff --git a/chrome/browser/ui/views/location_bar/ai_mode_page_action_icon_view.cc b/chrome/browser/ui/views/location_bar/ai_mode_page_action_icon_view.cc index 7dc96548..89cd2ecd 100644 --- a/chrome/browser/ui/views/location_bar/ai_mode_page_action_icon_view.cc +++ b/chrome/browser/ui/views/location_bar/ai_mode_page_action_icon_view.cc
@@ -10,6 +10,7 @@ #include "chrome/browser/ui/actions/chrome_action_id.h" #include "chrome/browser/ui/browser_element_identifiers.h" #include "chrome/browser/ui/browser_window/public/browser_window_interface.h" +#include "chrome/browser/ui/layout_constants.h" #include "chrome/browser/ui/omnibox/ai_mode_page_action_controller.h" #include "chrome/browser/ui/omnibox/omnibox_controller.h" #include "chrome/browser/ui/search/omnibox_utils.h" @@ -25,10 +26,12 @@ #include "content/public/browser/web_contents.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/metadata/metadata_impl_macros.h" +#include "ui/base/models/image_model.h" #include "ui/events/event.h" #include "ui/gfx/vector_icon_types.h" #include "ui/views/accessibility/view_accessibility.h" #include "ui/views/bubble/bubble_dialog_delegate_view.h" +#include "ui/views/cascading_property.h" #include "ui/views/interaction/element_tracker_views.h" #include "ui/views/view_class_properties.h" @@ -78,6 +81,26 @@ return omnibox::kSearchSparkIcon; } +void AiModePageActionIconView::UpdateIconImage() { + if (!GetWidget()) { + return; + } + + SkColor icon_color = GetActive() + ? views::GetCascadingAccentColor( + const_cast<AiModePageActionIconView*>(this)) + : GetIconColor(); + if (IconColorShouldMatchForeground()) { + icon_color = GetForegroundColor(); + } + + SetImageModel( + views::Button::STATE_NORMAL, + ui::ImageModel::FromVectorIcon( + GetVectorIcon(), icon_color, + GetLayoutConstant(LayoutConstant::kLocationBarChipIconSize))); +} + // This event handler exists because, on Mac, the <return> key doesn't activate // buttons in the omnibox or on the toolbelt. However, this page action is // designed to act like part of the popup when the popup is open and <return>
diff --git a/chrome/browser/ui/views/location_bar/ai_mode_page_action_icon_view.h b/chrome/browser/ui/views/location_bar/ai_mode_page_action_icon_view.h index f1aa358..16f7de55 100644 --- a/chrome/browser/ui/views/location_bar/ai_mode_page_action_icon_view.h +++ b/chrome/browser/ui/views/location_bar/ai_mode_page_action_icon_view.h
@@ -39,6 +39,7 @@ views::BubbleDialogDelegate* GetBubble() const override; void OnExecuting(PageActionIconView::ExecuteSource execute_source) override; const gfx::VectorIcon& GetVectorIcon() const override; + void UpdateIconImage() override; // views::View: bool OnKeyPressed(const ui::KeyEvent& event) override;
diff --git a/chrome/browser/ui/views/location_bar/cookie_controls/cookie_controls_page_action_controller_unittest.cc b/chrome/browser/ui/views/location_bar/cookie_controls/cookie_controls_page_action_controller_unittest.cc index b05988f..13c7869 100644 --- a/chrome/browser/ui/views/location_bar/cookie_controls/cookie_controls_page_action_controller_unittest.cc +++ b/chrome/browser/ui/views/location_bar/cookie_controls/cookie_controls_page_action_controller_unittest.cc
@@ -126,6 +126,7 @@ .WillByDefault([](user_education::FeaturePromoParams params) { std::move(params.show_promo_result_callback) .Run(user_education::FeaturePromoResult::Success()); + return true; }); ON_CALL(*fake_bubble_delegate_, HasBubble()).WillByDefault(Return(false)); @@ -279,6 +280,7 @@ .WillOnce([](user_education::FeaturePromoParams params) { std::move(params.show_promo_result_callback) .Run(user_education::FeaturePromoResult::kError); + return false; }); EXPECT_CALL(page_action_controller(), ShowSuggestionChip(kActionShowCookieControls, _)) @@ -293,6 +295,7 @@ .WillOnce([](user_education::FeaturePromoParams params) { std::move(params.show_promo_result_callback) .Run(user_education::FeaturePromoResult::Success()); + return true; }); EXPECT_CALL(page_action_controller(), AddActivity(kActionShowCookieControls)) .Times(1)
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.cc b/chrome/browser/ui/views/location_bar/location_bar_view.cc index 82b71b5..4a6435d 100644 --- a/chrome/browser/ui/views/location_bar/location_bar_view.cc +++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc
@@ -1369,10 +1369,10 @@ return false; } - PinnedToolbarActionsContainer* pinned_toolbar_actions_container = - browser_view->toolbar()->pinned_toolbar_actions_container(); - return pinned_toolbar_actions_container && - pinned_toolbar_actions_container->IsActionPinnedOrPoppedOut( + PinnedToolbarActions* pinned_toolbar_actions = + browser_view->toolbar()->pinned_toolbar_actions(); + return pinned_toolbar_actions && + pinned_toolbar_actions->IsActionPinnedOrPoppedOut( icon_view->action_id().value_or(-1)); }
diff --git a/chrome/browser/ui/views/location_bar/merchant_trust_chip_button_controller.cc b/chrome/browser/ui/views/location_bar/merchant_trust_chip_button_controller.cc index 88f6663..2bfcc1f0 100644 --- a/chrome/browser/ui/views/location_bar/merchant_trust_chip_button_controller.cc +++ b/chrome/browser/ui/views/location_bar/merchant_trust_chip_button_controller.cc
@@ -192,11 +192,7 @@ if (auto* interface = BrowserUserEducationInterface::MaybeGetForWebContentsInTab( web_contents())) { - bool can_show_promo = interface->CanShowFeaturePromo( + interface->MaybeShowFeaturePromo( feature_engagement::kIPHMerchantTrustFeature); - if (can_show_promo) { - interface->MaybeShowFeaturePromo( - feature_engagement::kIPHMerchantTrustFeature); - } } }
diff --git a/chrome/browser/ui/views/location_bar/webui_location_bar.cc b/chrome/browser/ui/views/location_bar/webui_location_bar.cc index 31d87b72..89f3f95e 100644 --- a/chrome/browser/ui/views/location_bar/webui_location_bar.cc +++ b/chrome/browser/ui/views/location_bar/webui_location_bar.cc
@@ -12,6 +12,7 @@ #include "chrome/browser/ui/omnibox/chrome_omnibox_client.h" #include "chrome/browser/ui/omnibox/omnibox_controller.h" #include "chrome/browser/ui/views/bubble_anchor_util_views.h" +#include "chrome/browser/ui/views/omnibox/webui_readonly_omnibox.h" #include "chrome/browser/ui/views/permissions/chip/permission_dashboard_controller.h" #include "chrome/browser/ui/views/permissions/chip/permission_dashboard_view.h" #include "chrome/browser/ui/views/toolbar/webui_toolbar_web_view.h" @@ -40,6 +41,8 @@ omnibox_controller_ = std::make_unique<OmniboxController>(std::make_unique<ChromeOmniboxClient>( /*location_bar=*/this, browser_, browser_->profile())); + omnibox_view_ = + std::make_unique<WebUIReadOnlyOmnibox>(omnibox_controller_.get(), this); is_initialized_ = true; } @@ -62,16 +65,15 @@ } void WebUILocationBar::SaveStateToContents(content::WebContents* contents) { - NOTIMPLEMENTED(); + omnibox_view_->SaveStateToTab(contents); } void WebUILocationBar::Revert() { - NOTIMPLEMENTED(); + omnibox_view_->RevertAll(); } OmniboxView* WebUILocationBar::GetOmniboxView() { - NOTIMPLEMENTED(); - return nullptr; + return omnibox_view_.get(); } OmniboxController* WebUILocationBar::GetOmniboxController() { @@ -114,7 +116,7 @@ } void WebUILocationBar::UpdateWithoutTabRestore() { - NOTIMPLEMENTED(); + Update(nullptr); } bool WebUILocationBar::IsInitialized() const { @@ -134,12 +136,13 @@ } bool WebUILocationBar::IsEditingOrEmpty() const { - NOTIMPLEMENTED(); - return false; + return omnibox_view_->IsEditingOrEmpty(); } void WebUILocationBar::InvalidateLayout() { - NOTIMPLEMENTED(); + base::SequencedTaskRunner::GetCurrentDefault()->PostTask( + FROM_HERE, base::BindOnce(&WebUILocationBar::OnChanged, + weak_ptr_factory_.GetWeakPtr())); } gfx::Rect WebUILocationBar::Bounds() const { @@ -158,11 +161,19 @@ } void WebUILocationBar::Update(content::WebContents* contents) { - NOTIMPLEMENTED(); + NOTIMPLEMENTED(); // Or rather needs a bunch more + + if (contents) { + omnibox_view_->OnTabChanged(contents); + } else { + omnibox_view_->Update(); + } + + OnChanged(); } void WebUILocationBar::ResetTabState(content::WebContents* contents) { - NOTIMPLEMENTED(); + omnibox_view_->ResetTabState(contents); } bool WebUILocationBar::HasSecurityStateChanged() {
diff --git a/chrome/browser/ui/views/location_bar/webui_location_bar.h b/chrome/browser/ui/views/location_bar/webui_location_bar.h index 94cb74e..89c5f5a 100644 --- a/chrome/browser/ui/views/location_bar/webui_location_bar.h +++ b/chrome/browser/ui/views/location_bar/webui_location_bar.h
@@ -6,6 +6,7 @@ #define CHROME_BROWSER_UI_VIEWS_LOCATION_BAR_WEBUI_LOCATION_BAR_H_ #include "base/memory/raw_ptr.h" +#include "base/memory/weak_ptr.h" #include "chrome/browser/ui/location_bar/location_bar.h" #include "chrome/browser/ui/views/location_bar/content_setting_image_view.h" #include "chrome/browser/ui/views/location_bar/location_bar_view.h" @@ -14,6 +15,7 @@ class OmniboxController; class PermissionDashboardController; class PermissionDashboardView; +class WebUIReadOnlyOmnibox; class WebUIToolbarWebView; // A LocationBar implementation using WebUI. @@ -75,8 +77,9 @@ raw_ptr<PermissionDashboardView> permission_dashboard_view_ = nullptr; std::unique_ptr<OmniboxController> omnibox_controller_; - + std::unique_ptr<WebUIReadOnlyOmnibox> omnibox_view_; bool is_initialized_ = false; + base::WeakPtrFactory<WebUILocationBar> weak_ptr_factory_{this}; }; #endif // CHROME_BROWSER_UI_VIEWS_LOCATION_BAR_WEBUI_LOCATION_BAR_H_
diff --git a/chrome/browser/ui/views/location_bar/webui_location_bar_browsertest.cc b/chrome/browser/ui/views/location_bar/webui_location_bar_browsertest.cc index 8b831c5a..52c56ab 100644 --- a/chrome/browser/ui/views/location_bar/webui_location_bar_browsertest.cc +++ b/chrome/browser/ui/views/location_bar/webui_location_bar_browsertest.cc
@@ -4,24 +4,24 @@ #include "chrome/browser/ui/views/location_bar/webui_location_bar.h" +#include "base/strings/utf_string_conversions.h" #include "base/test/run_until.h" #include "base/test/scoped_feature_list.h" #include "build/build_config.h" +#include "chrome/browser/ui/browser_commands.h" #include "chrome/browser/ui/browser_element_identifiers.h" #include "chrome/browser/ui/interaction/browser_elements.h" #include "chrome/browser/ui/layout_constants.h" +#include "chrome/browser/ui/omnibox/omnibox_view.h" #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/waap/initial_web_ui_manager.h" #include "chrome/common/chrome_features.h" #include "chrome/test/base/in_process_browser_test.h" +#include "chrome/test/base/ui_test_utils.h" #include "content/public/common/content_features.h" #include "content/public/test/browser_test.h" #include "ui/webui/tracked_element/tracked_element_web_ui.h" - -// kWebUILocationBar currently doesn't work on CrOS because -// TopControlsSlideControllerChromeOS relies on LocationBarView; but CrOS -// is also not a targeted platform. -#if !BUILDFLAG(IS_CHROMEOS) +#include "url/gurl.h" namespace { @@ -71,6 +71,33 @@ << location_bar_rect.ToString() << " " << reload_rect.ToString(); } -} // namespace +// Test that basic state management of the omnibox works --- e.g. it gets +// the URL as its state when navigating and switching tabs. +IN_PROC_BROWSER_TEST_F(WebUILocationBarBrowserTest, BasicOmniboxState) { + ASSERT_TRUE(WaitForInitialLoad()); + LocationBar* location_bar = + BrowserView::GetBrowserViewForBrowser(browser())->GetLocationBar(); + auto* tab_strip_model = browser()->tab_strip_model(); -#endif + auto* omnibox = location_bar->GetOmniboxView(); + ASSERT_TRUE(omnibox); + EXPECT_EQ("about:blank", base::UTF16ToUTF8(omnibox->GetText())); + + chrome::NewTab(browser()); + tab_strip_model->SelectTabAt(1); + + ASSERT_TRUE( + ui_test_utils::NavigateToURL(browser(), GURL("chrome://version"))); + EXPECT_EQ("chrome://version", base::UTF16ToUTF8(omnibox->GetText())); + + tab_strip_model->SelectTabAt(0); + EXPECT_EQ("about:blank", base::UTF16ToUTF8(omnibox->GetText())); + ASSERT_TRUE( + ui_test_utils::NavigateToURL(browser(), GURL("chrome://chrome-urls"))); + EXPECT_EQ("chrome://chrome-urls", base::UTF16ToUTF8(omnibox->GetText())); + + tab_strip_model->SelectTabAt(1); + EXPECT_EQ("chrome://version", base::UTF16ToUTF8(omnibox->GetText())); +} + +} // namespace
diff --git a/chrome/browser/ui/views/media_router/cast_browser_controller_browsertest.cc b/chrome/browser/ui/views/media_router/cast_browser_controller_browsertest.cc index d27e6d6..a46a0f0 100644 --- a/chrome/browser/ui/views/media_router/cast_browser_controller_browsertest.cc +++ b/chrome/browser/ui/views/media_router/cast_browser_controller_browsertest.cc
@@ -13,6 +13,7 @@ #include "chrome/browser/ui/browser_window/public/browser_window_features.h" #include "chrome/browser/ui/color/chrome_color_id.h" #include "chrome/browser/ui/media_router/media_router_ui_service.h" +#include "chrome/browser/ui/ui_features.h" #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/toolbar/pinned_action_toolbar_button.h" #include "chrome/browser/ui/views/toolbar/pinned_toolbar_actions_container.h" @@ -64,9 +65,12 @@ PinnedToolbarActionsModel::Get(browser()->profile()) ->UpdatePinnedState(kActionRouteMedia, true); - button_ = BrowserView::GetBrowserViewForBrowser(browser()) - ->toolbar() - ->pinned_toolbar_actions_container() + CHECK(!features::IsWebUIPinnedToolbarActionsEnabled()) + << "Test needs modification to support WebUIPinnedToolbarActions"; + button_ = static_cast<PinnedToolbarActionsContainer*>( + BrowserView::GetBrowserViewForBrowser(browser()) + ->toolbar() + ->pinned_toolbar_actions()) ->GetButtonFor(kActionRouteMedia); controller_ = browser()->browser_window_features()->cast_browser_controller();
diff --git a/chrome/browser/ui/views/media_router/media_router_ui_browsertest.cc b/chrome/browser/ui/views/media_router/media_router_ui_browsertest.cc index cd3a9e7..0145c1b7 100644 --- a/chrome/browser/ui/views/media_router/media_router_ui_browsertest.cc +++ b/chrome/browser/ui/views/media_router/media_router_ui_browsertest.cc
@@ -16,6 +16,7 @@ #include "chrome/browser/ui/media_router/media_router_ui_service.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/toolbar/cast/cast_toolbar_button_controller.h" +#include "chrome/browser/ui/ui_features.h" #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/media_router/app_menu_test_api.h" #include "chrome/browser/ui/views/media_router/cast_dialog_view.h" @@ -57,10 +58,13 @@ MediaSource("urn:x-org.chromium.media:source:tab:*"), "sinkId1", "description", true)}; + CHECK(!features::IsWebUIPinnedToolbarActionsEnabled()) + << "Test needs modification to support WebUIPinnedToolbarActions"; auto* pinned_toolbar_actions_container = - BrowserView::GetBrowserViewForBrowser(browser()) - ->toolbar() - ->pinned_toolbar_actions_container(); + static_cast<PinnedToolbarActionsContainer*>( + BrowserView::GetBrowserViewForBrowser(browser()) + ->toolbar() + ->pinned_toolbar_actions()); views::test::ReduceAnimationDuration(pinned_toolbar_actions_container); }
diff --git a/chrome/browser/ui/views/media_router/media_router_ui_interactive_uitest.cc b/chrome/browser/ui/views/media_router/media_router_ui_interactive_uitest.cc index 3af21b9..9c65378 100644 --- a/chrome/browser/ui/views/media_router/media_router_ui_interactive_uitest.cc +++ b/chrome/browser/ui/views/media_router/media_router_ui_interactive_uitest.cc
@@ -67,10 +67,13 @@ } void WaitForAnimations() { - auto* container = BrowserView::GetBrowserViewForBrowser(browser()) - ->toolbar() - ->pinned_toolbar_actions_container(); - views::test::WaitForAnimatingLayoutManager(container); + CHECK(!features::IsWebUIPinnedToolbarActionsEnabled()) + << "Test needs modification to support WebUIPinnedToolbarActions"; + views::test::WaitForAnimatingLayoutManager( + static_cast<PinnedToolbarActionsContainer*>( + BrowserView::GetBrowserViewForBrowser(browser()) + ->toolbar() + ->pinned_toolbar_actions())); } void PressToolbarIcon() {
diff --git a/chrome/browser/ui/views/omnibox/omnibox_context_menu.cc b/chrome/browser/ui/views/omnibox/omnibox_context_menu.cc index aa96b56..23303b6 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_context_menu.cc +++ b/chrome/browser/ui/views/omnibox/omnibox_context_menu.cc
@@ -90,7 +90,7 @@ glic_nudge_controller->UpdateNudgeLabel( browser_window_interface->GetActiveTabInterface()->GetContents(), "", - std::nullopt, + std::nullopt, /*anchored_message_text=*/std::string(), glic::GlicNudgeActivity::kNudgeIgnoredOmniboxContextMenuInteraction, base::DoNothing()); }
diff --git a/chrome/browser/ui/views/omnibox/webui_readonly_omnibox.cc b/chrome/browser/ui/views/omnibox/webui_readonly_omnibox.cc new file mode 100644 index 0000000..b044b16 --- /dev/null +++ b/chrome/browser/ui/views/omnibox/webui_readonly_omnibox.cc
@@ -0,0 +1,204 @@ +// Copyright 2026 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/views/omnibox/webui_readonly_omnibox.h" + +#include <memory> + +#include "base/notimplemented.h" +#include "base/strings/utf_string_conversions.h" +#include "base/supports_user_data.h" +#include "chrome/browser/ui/omnibox/omnibox_controller.h" +#include "chrome/browser/ui/omnibox/omnibox_tab_helper.h" +#include "content/public/browser/web_contents.h" + +namespace { + +struct OmniboxState : public base::SupportsUserData::Data { + explicit OmniboxState(const OmniboxEditModel::State& model_state, + const gfx::Range& selection); + + ~OmniboxState() override; + + const OmniboxEditModel::State model_state; + // Views omnibox also keeps track of saved selection when focused out; + // it's likely not needed here since the selection state in + // WebUIReadOnlyOmnibox is disconnected from that in the actual HTML UI. + const gfx::Range selection; +}; + +OmniboxState::OmniboxState(const OmniboxEditModel::State& model_state, + const gfx::Range& selection) + : model_state(model_state), selection(selection) {} + +OmniboxState::~OmniboxState() = default; + +} // namespace + +WebUIReadOnlyOmnibox::WebUIReadOnlyOmnibox(OmniboxController* controller, + WebUILocationBar* location_bar) + : OmniboxView(controller), selection_(gfx::Range::InvalidRange()) {} + +WebUIReadOnlyOmnibox::~WebUIReadOnlyOmnibox() = default; + +void WebUIReadOnlyOmnibox::SaveStateToTab(content::WebContents* tab) { + const OmniboxEditModel::State state = + controller()->edit_model()->GetStateForTabSwitch(); + tab->SetUserData(OmniboxTabHelper::kOmniboxStateKey, + std::make_unique<OmniboxState>(state, selection_)); +} + +void WebUIReadOnlyOmnibox::OnTabChanged( + const content::WebContents* web_contents) { + const OmniboxState* state = static_cast<OmniboxState*>( + web_contents->GetUserData(OmniboxTabHelper::kOmniboxStateKey)); + controller()->edit_model()->RestoreState(state ? &state->model_state + : nullptr); + if (state) { + selection_ = state->selection; + } + + // TODO: Update WebUI. +} + +void WebUIReadOnlyOmnibox::ResetTabState(content::WebContents* web_contents) { + web_contents->SetUserData(OmniboxTabHelper::kOmniboxStateKey, nullptr); +} + +void WebUIReadOnlyOmnibox::Update() { + // TODO: Identical to OmniboxViewViews; need a sharing strategy. + if (controller()->edit_model()->ResetDisplayTexts()) { + RevertAll(); + + // Only select all when we have focus. If we don't have focus, selecting + // all is unnecessary since the selection will change on regaining focus. + if (controller()->edit_model()->has_focus()) { + SelectAll(true); + } + } else { + // If the text is unchanged, we still need to re-emphasize the text, as the + // security state may be different from before the Update. + EmphasizeURLComponents(); + } +} + +std::u16string WebUIReadOnlyOmnibox::GetText() const { + return text_; +} + +void WebUIReadOnlyOmnibox::SetWindowTextAndCaretPos(const std::u16string& text, + size_t caret_pos, + bool update_popup, + bool notify_text_changed) { + text_ = text; + selection_ = gfx::Range(caret_pos); + + // TODO: update_popup? + + if (notify_text_changed) { + TextChanged(); + } + + // TODO: Update WebUI. +} + +void WebUIReadOnlyOmnibox::SetCaretPos(size_t caret_pos) { + selection_ = gfx::Range(caret_pos); + + // TODO: Update WebUI. +} + +void WebUIReadOnlyOmnibox::SetAdditionalText( + const std::u16string& additional_text) { + NOTIMPLEMENTED(); +} + +void WebUIReadOnlyOmnibox::EnterKeywordModeForDefaultSearchProvider() { + NOTIMPLEMENTED(); +} + +bool WebUIReadOnlyOmnibox::IsSelectAll() const { + if (text_.empty()) { + return false; + } + + return selection_.GetMin() == 0 && selection_.length() == text_.length(); +} + +gfx::Range WebUIReadOnlyOmnibox::GetSelectionBounds() const { + return selection_; +} + +void WebUIReadOnlyOmnibox::SelectAll(bool reversed) { + size_t length = text_.size(); + selection_ = reversed ? gfx::Range(length, 0) : gfx::Range(0, length); + // TODO: Update WebUI. +} + +void WebUIReadOnlyOmnibox::UpdatePopup() { + NOTIMPLEMENTED(); +} + +void WebUIReadOnlyOmnibox::SetFocus(bool is_user_initiated) { + NOTIMPLEMENTED(); +} + +bool WebUIReadOnlyOmnibox::AimButtonVisible() const { + NOTIMPLEMENTED(); + return false; +} + +void WebUIReadOnlyOmnibox::ApplyCaretVisibility() { + NOTIMPLEMENTED(); +} + +void WebUIReadOnlyOmnibox::OnTemporaryTextMaybeChanged( + const std::u16string& display_text, + const AutocompleteMatch& match, + bool save_original_selection, + bool notify_text_changed) { + NOTIMPLEMENTED(); +} + +void WebUIReadOnlyOmnibox::OnInlineAutocompleteTextMaybeChanged( + const std::u16string& user_text, + const std::u16string& inline_autocompletion) { + NOTIMPLEMENTED(); +} + +void WebUIReadOnlyOmnibox::OnInlineAutocompleteTextCleared() { + NOTIMPLEMENTED(); +} + +void WebUIReadOnlyOmnibox::OnRevertTemporaryText( + const std::u16string& display_text, + const AutocompleteMatch& match) { + NOTIMPLEMENTED(); +} + +void WebUIReadOnlyOmnibox::OnBeforePossibleChange() { + NOTIMPLEMENTED(); +} + +bool WebUIReadOnlyOmnibox::OnAfterPossibleChange(bool allow_keyword_ui_change) { + NOTIMPLEMENTED(); + return false; +} + +int WebUIReadOnlyOmnibox::GetOmniboxTextLength() const { + return text_.size(); +} + +void WebUIReadOnlyOmnibox::EmphasizeURLComponents() { + NOTIMPLEMENTED(); +} + +void WebUIReadOnlyOmnibox::SetEmphasis(bool emphasize, + const gfx::Range& range) { + NOTIMPLEMENTED(); +} + +void WebUIReadOnlyOmnibox::UpdateSchemeStyle(const gfx::Range& range) { + NOTIMPLEMENTED(); +}
diff --git a/chrome/browser/ui/views/omnibox/webui_readonly_omnibox.h b/chrome/browser/ui/views/omnibox/webui_readonly_omnibox.h new file mode 100644 index 0000000..3b52e9f --- /dev/null +++ b/chrome/browser/ui/views/omnibox/webui_readonly_omnibox.h
@@ -0,0 +1,90 @@ +// Copyright 2026 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_VIEWS_OMNIBOX_WEBUI_READONLY_OMNIBOX_H_ +#define CHROME_BROWSER_UI_VIEWS_OMNIBOX_WEBUI_READONLY_OMNIBOX_H_ + +#include <stddef.h> + +#include <memory> +#include <set> +#include <string> +#include <string_view> + +#include "base/gtest_prod_util.h" +#include "base/memory/raw_ptr.h" +#include "base/scoped_observation.h" +#include "base/time/time.h" +#include "build/build_config.h" +#include "chrome/browser/ui/omnibox/omnibox_view.h" +#include "ui/gfx/range/range.h" + +namespace content { +class WebContents; +} // namespace content + +class WebUILocationBar; + +// WebUI-implementation of OmniboxView, which happens to be readonly, +// as it counts on the popup to handle the editing. +// TODO(crbug.com/474060468): Rename it in a manner more consistent with other +// classes here. +class WebUIReadOnlyOmnibox : public OmniboxView { + public: + WebUIReadOnlyOmnibox(OmniboxController* controller, + WebUILocationBar* location_bar); + WebUIReadOnlyOmnibox(const WebUIReadOnlyOmnibox&) = delete; + WebUIReadOnlyOmnibox& operator=(const WebUIReadOnlyOmnibox&) = delete; + ~WebUIReadOnlyOmnibox() override; + + // Called from the location bar. + void SaveStateToTab(content::WebContents* tab); + void OnTabChanged(const content::WebContents* web_contents); + void ResetTabState(content::WebContents* web_contents); + + // OmniboxView: + void Update() override; + std::u16string GetText() const override; + void SetWindowTextAndCaretPos(const std::u16string& text, + size_t caret_pos, + bool update_popup, + bool notify_text_changed) override; + void SetCaretPos(size_t caret_pos) override; + void SetAdditionalText(const std::u16string& text) override; + void EnterKeywordModeForDefaultSearchProvider() override; + bool IsSelectAll() const override; + gfx::Range GetSelectionBounds() const override; + void SelectAll(bool reversed) override; + void UpdatePopup() override; + void SetFocus(bool is_user_initiated) override; + bool AimButtonVisible() const override; + void ApplyCaretVisibility() override; + void OnTemporaryTextMaybeChanged(const std::u16string& display_text, + const AutocompleteMatch& match, + bool save_original_selection, + bool notify_text_changed) override; + void OnInlineAutocompleteTextMaybeChanged( + const std::u16string& user_text, + const std::u16string& inline_autocompletion) override; + void OnInlineAutocompleteTextCleared() override; + void OnRevertTemporaryText(const std::u16string& display_text, + const AutocompleteMatch& match) override; + void OnBeforePossibleChange() override; + bool OnAfterPossibleChange(bool allow_keyword_ui_change) override; + int GetOmniboxTextLength() const override; + void EmphasizeURLComponents() override; + void SetEmphasis(bool emphasize, const gfx::Range& range) override; + void UpdateSchemeStyle(const gfx::Range& range) override; + + private: + // Text and selection (or caret) we were asked to display (e.g. via + // SetWindowTextAndCaretPos()) by either the base class or OmniboxEditModel. + std::u16string text_; + + // When start and end positions match, this represents a caret position; + // if they don't, it's a selection. + gfx::Range selection_; +}; + +#endif // CHROME_BROWSER_UI_VIEWS_OMNIBOX_WEBUI_READONLY_OMNIBOX_H_
diff --git a/chrome/browser/ui/views/omnibox/webui_readonly_omnibox_unittest.cc b/chrome/browser/ui/views/omnibox/webui_readonly_omnibox_unittest.cc new file mode 100644 index 0000000..efa9b5e --- /dev/null +++ b/chrome/browser/ui/views/omnibox/webui_readonly_omnibox_unittest.cc
@@ -0,0 +1,111 @@ +// Copyright 2026 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/views/omnibox/webui_readonly_omnibox.h" + +#include <memory> +#include <string> +#include <string_view> +#include <utility> + +#include "base/memory/raw_ptr.h" +#include "chrome/browser/ui/omnibox/omnibox_controller.h" +#include "chrome/test/base/testing_profile.h" +#include "components/omnibox/browser/test_omnibox_client.h" +#include "content/public/browser/web_contents.h" +#include "content/public/test/browser_task_environment.h" +#include "content/public/test/test_web_contents_factory.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" + +class WebUIReadOnlyOmniboxTest : public testing::Test { + protected: + TestLocationBarModel* location_bar_model() { + return omnibox_client_->location_bar_model(); + } + + // testing::Test: + void SetUp() override; + void TearDown() override; + + content::BrowserTaskEnvironment browser_threads_; + std::unique_ptr<TestingProfile> profile_; + std::unique_ptr<OmniboxController> omnibox_controller_; + raw_ptr<TestOmniboxClient> omnibox_client_; + std::unique_ptr<WebUIReadOnlyOmnibox> omnibox_view_; + + content::TestWebContentsFactory web_contents_factory_; + raw_ptr<content::WebContents> wc1_; + raw_ptr<content::WebContents> wc2_; +}; + +void WebUIReadOnlyOmniboxTest::SetUp() { + profile_ = TestingProfile::Builder().Build(); + + auto omnibox_client = std::make_unique<TestOmniboxClient>(); + omnibox_client_ = omnibox_client.get(); + omnibox_controller_ = + std::make_unique<OmniboxController>(std::move(omnibox_client)); + + omnibox_view_ = std::make_unique<WebUIReadOnlyOmnibox>( + omnibox_controller_.get(), /*location_bar=*/nullptr); + + wc1_ = web_contents_factory_.CreateWebContents(profile_.get()); + wc2_ = web_contents_factory_.CreateWebContents(profile_.get()); +} + +void WebUIReadOnlyOmniboxTest::TearDown() { + web_contents_factory_.DestroyWebContents(wc1_.ExtractAsDangling()); + web_contents_factory_.DestroyWebContents(wc2_.ExtractAsDangling()); +} + +TEST_F(WebUIReadOnlyOmniboxTest, StateManagement) { + std::u16string partial = u"https://uk.wikipe"; + omnibox_view_->SetUserText(partial); + omnibox_view_->SetCaretPos(partial.size()); + EXPECT_FALSE(omnibox_view_->IsSelectAll()); + EXPECT_EQ(partial, omnibox_view_->GetText()); + omnibox_view_->SaveStateToTab(wc1_); + + std::u16string complete = u"https://chromium.org"; + omnibox_view_->SetUserText(complete); + omnibox_view_->SelectAll(/*reversed=*/false); + EXPECT_TRUE(omnibox_view_->IsSelectAll()); + EXPECT_EQ(complete, omnibox_view_->GetText()); + omnibox_view_->SaveStateToTab(wc2_); + + // Emulate switching back to wc1. + omnibox_view_->OnTabChanged(wc1_); + EXPECT_FALSE(omnibox_view_->IsSelectAll()); + EXPECT_EQ(partial, omnibox_view_->GetText()); + EXPECT_EQ(omnibox_view_->GetSelectionBounds(), gfx::Range(partial.size())); + + // Switch back to wc2. + omnibox_view_->OnTabChanged(wc2_); + EXPECT_TRUE(omnibox_view_->IsSelectAll()); + EXPECT_EQ(complete, omnibox_view_->GetText()); + EXPECT_EQ(omnibox_view_->GetSelectionBounds(), + gfx::Range(0, complete.size())); + + // If no saved state, pulls from the location bar model. + std::u16string navigated_to = u"https://developer.mozilla.org/"; + location_bar_model()->set_url_for_display(navigated_to); + omnibox_view_->ResetTabState(wc2_); + omnibox_view_->OnTabChanged(wc2_); + EXPECT_EQ(navigated_to, omnibox_view_->GetText()); + EXPECT_EQ(gfx::Range(), omnibox_view_->GetSelectionBounds()); + + // Update() can pull further changes. + std::u16string navigated_to2 = u"https://developer.mozilla.org/en-US"; + location_bar_model()->set_url_for_display(navigated_to2); + omnibox_view_->Update(); + EXPECT_EQ(navigated_to2, omnibox_view_->GetText()); +} + +TEST_F(WebUIReadOnlyOmniboxTest, GetOmniboxTextLength) { + std::u16string partial = u"https://uk.wikipe"; + omnibox_view_->SetUserText(partial); + EXPECT_EQ(partial.size(), + static_cast<size_t>(omnibox_view_->GetOmniboxTextLength())); +}
diff --git a/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view_browsertest.cc b/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view_browsertest.cc index 451b135..ee4adf0 100644 --- a/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view_browsertest.cc +++ b/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view_browsertest.cc
@@ -1043,24 +1043,6 @@ test_helper()->CheckInterstitialUkmCount(0); } -// Tests that the SafetyTipIgnoredPageLoad histogram triggers correctly. -IN_PROC_BROWSER_TEST_F(SafetyTipPageInfoBubbleViewBrowserTest, - SafetyTipIgnoredPageLoadHistogram) { - base::HistogramTester histograms; - auto kNavigatedUrl = GetURL("accounts-google.com"); - SetEngagementScore(browser(), kNavigatedUrl, kLowEngagement); - NavigateToURL(browser(), kNavigatedUrl, WindowOpenDisposition::CURRENT_TAB); - - CloseWarningIgnore(views::Widget::ClosedReason::kCloseButtonClicked); - NavigateToURL(browser(), kNavigatedUrl, WindowOpenDisposition::CURRENT_TAB); - histograms.ExpectBucketCount( - "Security.SafetyTips.SafetyTipIgnoredPageLoad", - security_state::SafetyTipStatus::kLookalikeIgnored, 1); - // UKM recorded twice because we revisited the same page. - test_helper()->CheckSafetyTipUkmCount(2); - test_helper()->CheckInterstitialUkmCount(0); -} - // Tests that Safety Tip interactions are recorded in a histogram when the user // leaves the site using the safety tip. IN_PROC_BROWSER_TEST_F(SafetyTipPageInfoBubbleViewBrowserTest,
diff --git a/chrome/browser/ui/views/passwords/manage_passwords_icon_view_interactive_uitest.cc b/chrome/browser/ui/views/passwords/manage_passwords_icon_view_interactive_uitest.cc index 0b4726d..c7c1995 100644 --- a/chrome/browser/ui/views/passwords/manage_passwords_icon_view_interactive_uitest.cc +++ b/chrome/browser/ui/views/passwords/manage_passwords_icon_view_interactive_uitest.cc
@@ -122,9 +122,13 @@ PinnedToolbarActionsModel::Get(browser()->profile()) ->UpdatePinnedState(kActionShowPasswordsBubbleOrPage, true); BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser()); + CHECK(!features::IsWebUIPinnedToolbarActionsEnabled()) + << "Test needs modification to support WebUIPinnedToolbarActions"; + PinnedToolbarActionsContainer* container = + static_cast<PinnedToolbarActionsContainer*>( + browser_view->toolbar()->pinned_toolbar_actions()); PinnedActionToolbarButton* button = - browser_view->toolbar()->pinned_toolbar_actions_container()->GetButtonFor( - kActionShowPasswordsBubbleOrPage); + container->GetButtonFor(kActionShowPasswordsBubbleOrPage); ASSERT_NE(button, nullptr); // Underline should not be visible here.
diff --git a/chrome/browser/ui/views/profiles/profile_picker_post_sign_in_adapter.cc b/chrome/browser/ui/views/profiles/profile_picker_post_sign_in_adapter.cc index 384e528..785e545 100644 --- a/chrome/browser/ui/views/profiles/profile_picker_post_sign_in_adapter.cc +++ b/chrome/browser/ui/views/profiles/profile_picker_post_sign_in_adapter.cc
@@ -7,12 +7,14 @@ #include <memory> #include <optional> +#include "base/check_deref.h" #include "base/functional/bind.h" #include "base/functional/callback_helpers.h" #include "base/strings/string_util.h" #include "base/strings/to_string.h" #include "chrome/browser/profiles/keep_alive/profile_keep_alive_types.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/regional_capabilities/regional_capabilities_service_factory.h" #include "chrome/browser/signin/identity_manager_factory.h" #include "chrome/browser/signin/signin_util.h" #include "chrome/browser/themes/theme_service.h" @@ -29,6 +31,7 @@ #include "chrome/browser/ui/webui/signin/turn_sync_on_helper.h" #include "chrome/common/url_constants.h" #include "chrome/common/webui_url_constants.h" +#include "components/regional_capabilities/regional_capabilities_service.h" #include "components/signin/public/base/signin_metrics.h" #include "components/signin/public/base/signin_switches.h" #include "components/signin/public/identity_manager/account_info.h" @@ -243,8 +246,19 @@ if (!step_switch_callback_->is_null()) { std::move(step_switch_callback_.value()).Run(true); } + + const bool is_in_search_engine_choice_region = + CHECK_DEREF(regional_capabilities::RegionalCapabilitiesServiceFactory:: + GetForProfile(profile_)) + .IsInSearchEngineChoiceScreenRegion(); + const bool use_refreshed_ui = + switches::IsFirstRunDesktopRefreshEnabled( + is_in_search_engine_choice_region); + host_->ShowScreen(contents(), - GURL(chrome::kChromeUIManagedUserProfileNoticeUrl), + use_refreshed_ui + ? GURL(chrome::kChromeUIManagedUserProfileNoticeRefreshURL) + : GURL(chrome::kChromeUIManagedUserProfileNoticeUrl), /*navigation_finished_closure=*/ base::BindOnce(&ProfilePickerPostSignInAdapter:: SwitchToManagedUserProfileNoticeFinished,
diff --git a/chrome/browser/ui/views/save_to_drive/account_chooser_controller.cc b/chrome/browser/ui/views/save_to_drive/account_chooser_controller.cc index ba7a270..cf37163 100644 --- a/chrome/browser/ui/views/save_to_drive/account_chooser_controller.cc +++ b/chrome/browser/ui/views/save_to_drive/account_chooser_controller.cc
@@ -10,8 +10,10 @@ #include "chrome/browser/ui/views/chrome_layout_provider.h" #include "chrome/browser/ui/views/save_to_drive/account_chooser_util.h" #include "chrome/browser/ui/views/save_to_drive/account_chooser_view.h" +#include "chrome/grit/generated_resources.h" #include "components/tabs/public/tab_interface.h" #include "content/public/browser/web_contents_delegate.h" +#include "ui/base/l10n/l10n_util.h" #include "ui/display/screen.h" namespace save_to_drive { @@ -290,6 +292,8 @@ DISTANCE_HORIZONTAL_SEPARATOR_PADDING_PAGE_INFO_VIEW); dialog_delegate->set_margins(gfx::Insets::TLBR(dialog_margin, dialog_margin, dialog_margin, dialog_margin)); + dialog_delegate->SetTitle(l10n_util::GetStringUTF16( + IDS_ACCOUNT_CHOOSER_HEADER_ACCESSIBILITY_LABEL)); dialog_delegate->SetShowTitle(false); dialog_delegate->SetShowCloseButton(false); dialog_delegate->SetButtons(static_cast<int>(ui::mojom::DialogButton::kNone));
diff --git a/chrome/browser/ui/views/save_to_drive/account_chooser_view.cc b/chrome/browser/ui/views/save_to_drive/account_chooser_view.cc index b21f4e2..b792a0d 100644 --- a/chrome/browser/ui/views/save_to_drive/account_chooser_view.cc +++ b/chrome/browser/ui/views/save_to_drive/account_chooser_view.cc
@@ -252,8 +252,8 @@ views::style::STYLE_HEADLINE_4); title_label->SetEnabledColor(ui::kColorSysOnSurface); SetLabelProperties(title_label.get()); - title_label->GetViewAccessibility().SetName(l10n_util::GetStringUTF16( - IDS_ACCOUNT_CHOOSER_HEADER_ACCESSIBILITY_LABEL)); + title_label->GetViewAccessibility().SetRole(ax::mojom::Role::kHeading); + title_label->GetViewAccessibility().SetHierarchicalLevel(2); return title_label; } @@ -286,9 +286,6 @@ const std::vector<AccountInfo>& accounts) { auto title_view = std::make_unique<views::FlexLayoutView>(); title_view->SetCrossAxisAlignment(views::LayoutAlignment::kCenter); - title_view->GetViewAccessibility().SetRole(ax::mojom::Role::kRegion); - title_view->GetViewAccessibility().SetName(l10n_util::GetStringUTF16( - IDS_ACCOUNT_CHOOSER_HEADER_ACCESSIBILITY_LABEL)); auto title_container = std::make_unique<views::FlexLayoutView>(); title_container->SetProperty(
diff --git a/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_browsertest.cc b/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_browsertest.cc index 891de04..10096aa 100644 --- a/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_browsertest.cc +++ b/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_browsertest.cc
@@ -11,11 +11,12 @@ #include "chrome/browser/ui/browser_actions.h" #include "chrome/browser/ui/browser_commands.h" #include "chrome/browser/ui/test/test_browser_dialog.h" +#include "chrome/browser/ui/ui_features.h" #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_controller.h" -#include "chrome/browser/ui/views/toolbar/toolbar_view.h" #include "chrome/browser/ui/views/toolbar/pinned_action_toolbar_button.h" #include "chrome/browser/ui/views/toolbar/pinned_toolbar_actions_container.h" +#include "chrome/browser/ui/views/toolbar/toolbar_view.h" #include "components/send_tab_to_self/target_device_info.h" #include "components/signin/public/identity_manager/account_info.h" #include "content/public/test/browser_test.h" @@ -136,8 +137,11 @@ kActionSendTabToSelf, browser_action_item); action_item->SetEnabled(true); action_item->SetVisible(true); + CHECK(!features::IsWebUIPinnedToolbarActionsEnabled()) + << "Test needs modification to support WebUIPinnedToolbarActions"; PinnedToolbarActionsContainer* container = - browser_view->toolbar()->pinned_toolbar_actions_container(); + static_cast<PinnedToolbarActionsContainer*>( + browser_view->toolbar()->pinned_toolbar_actions()); container->UpdateActionState(kActionSendTabToSelf, true); views::test::WaitForAnimatingLayoutManager(container);
diff --git a/chrome/browser/ui/views/side_panel/side_panel_coordinator.cc b/chrome/browser/ui/views/side_panel/side_panel_coordinator.cc index 8c74608..02058446 100644 --- a/chrome/browser/ui/views/side_panel/side_panel_coordinator.cc +++ b/chrome/browser/ui/views/side_panel/side_panel_coordinator.cc
@@ -243,7 +243,7 @@ // hidden. side_panel->ResetSidePanelAnimationContent(); - if (browser_view_->toolbar()->pinned_toolbar_actions_container()) { + if (browser_view_->toolbar()->pinned_toolbar_actions()) { side_panel_toolbar_pinning_controller_->UpdateActiveState( current_key(panel_type)->key, false); } @@ -335,7 +335,7 @@ } side_panel->Open(/*animated=*/!suppress_animations); SetCurrentKey(entry->type(), unique_key); - if (browser_view_->toolbar()->pinned_toolbar_actions_container()) { + if (browser_view_->toolbar()->pinned_toolbar_actions()) { side_panel_toolbar_pinning_controller_->UpdateActiveState( entry->key(), entry->should_show_ephemerally_in_toolbar()); // Notify active state change only if the entry ids for the side panel are
diff --git a/chrome/browser/ui/views/side_panel/side_panel_interactive_uitest.cc b/chrome/browser/ui/views/side_panel/side_panel_interactive_uitest.cc index 7731230..c4d90a30 100644 --- a/chrome/browser/ui/views/side_panel/side_panel_interactive_uitest.cc +++ b/chrome/browser/ui/views/side_panel/side_panel_interactive_uitest.cc
@@ -22,6 +22,7 @@ #include "chrome/browser/ui/toolbar/app_menu_model.h" #include "chrome/browser/ui/toolbar/bookmark_sub_menu_model.h" #include "chrome/browser/ui/toolbar/pinned_toolbar/pinned_toolbar_actions_model.h" +#include "chrome/browser/ui/ui_features.h" #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/side_panel/side_panel.h" #include "chrome/browser/ui/views/side_panel/side_panel_coordinator.h" @@ -286,9 +287,7 @@ actions_model->UpdatePinnedState(kActionTabSearch, false); } views::test::WaitForAnimatingLayoutManager( - BrowserView::GetBrowserViewForBrowser(browser()) - ->toolbar() - ->pinned_toolbar_actions_container()); + GetPinnedToolbarActionsContainer()); } auto OpenBookmarksSidePanel() { @@ -309,9 +308,7 @@ [&]() { PinnedToolbarActionsContainer* const pinned_toolbar_actions_container = - BrowserView::GetBrowserViewForBrowser(browser()) - ->toolbar() - ->pinned_toolbar_actions_container(); + GetPinnedToolbarActionsContainer(); return pinned_toolbar_actions_container->GetPinnedButtonFor(id) != nullptr; }, @@ -325,9 +322,12 @@ } PinnedToolbarActionsContainer* GetPinnedToolbarActionsContainer() { - return BrowserView::GetBrowserViewForBrowser(browser()) - ->toolbar() - ->pinned_toolbar_actions_container(); + CHECK(!features::IsWebUIPinnedToolbarActionsEnabled()) + << "Test needs modification to support WebUIPinnedToolbarActions"; + return static_cast<PinnedToolbarActionsContainer*>( + BrowserView::GetBrowserViewForBrowser(browser()) + ->toolbar() + ->pinned_toolbar_actions()); } auto OpenReadingModeSidePanel() {
diff --git a/chrome/browser/ui/views/side_panel/side_panel_toolbar_pinning_controller.cc b/chrome/browser/ui/views/side_panel/side_panel_toolbar_pinning_controller.cc index 05fbd02..75922ee 100644 --- a/chrome/browser/ui/views/side_panel/side_panel_toolbar_pinning_controller.cc +++ b/chrome/browser/ui/views/side_panel/side_panel_toolbar_pinning_controller.cc
@@ -109,7 +109,7 @@ SidePanelEntryKey key, bool show_active_in_toolbar) { auto* const toolbar_container = - browser_view_->toolbar()->pinned_toolbar_actions_container(); + browser_view_->toolbar()->pinned_toolbar_actions(); CHECK(toolbar_container); // Active extension side-panels have different UI in the toolbar than active
diff --git a/chrome/browser/ui/views/tabs/projects/BUILD.gn b/chrome/browser/ui/views/tabs/projects/BUILD.gn index 51a27f4..03318ac 100644 --- a/chrome/browser/ui/views/tabs/projects/BUILD.gn +++ b/chrome/browser/ui/views/tabs/projects/BUILD.gn
@@ -100,6 +100,8 @@ "//chrome/test:test_support", "//components/contextual_tasks/public", "//components/contextual_tasks/public:test_support", + "//components/omnibox/browser:test_support", + "//components/prefs:test_support", "//components/saved_tab_groups/public", "//components/saved_tab_groups/test_support", "//components/sync/base", @@ -134,6 +136,7 @@ ] deps = [ ":projects", + "//chrome/browser/autocomplete:aim_eligibility_service", "//chrome/browser/tab_group_sync:factories", "//chrome/browser/ui", "//chrome/browser/ui:browser_element_identifiers", @@ -142,6 +145,7 @@ "//chrome/browser/ui/tabs/projects", "//chrome/test:test_support", "//components/contextual_tasks/public:test_support", + "//components/omnibox/browser:test_support", "//components/saved_tab_groups/public", "//components/saved_tab_groups/test_support", "//content/test:test_support",
diff --git a/chrome/browser/ui/views/tabs/projects/projects_panel_controller.cc b/chrome/browser/ui/views/tabs/projects/projects_panel_controller.cc index d3f6aff..268cbfe 100644 --- a/chrome/browser/ui/views/tabs/projects/projects_panel_controller.cc +++ b/chrome/browser/ui/views/tabs/projects/projects_panel_controller.cc
@@ -9,6 +9,7 @@ #include "chrome/browser/contextual_tasks/contextual_tasks_ui_service.h" #include "chrome/browser/ui/browser_window/public/browser_window_interface.h" #include "chrome/browser/ui/browser_window/public/browser_window_interface_iterator.h" +#include "chrome/browser/ui/tabs/projects/projects_panel_state_controller.h" #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "components/saved_tab_groups/public/saved_tab_group.h" @@ -16,10 +17,12 @@ ProjectsPanelController::ProjectsPanelController( BrowserWindowInterface* browser, + ProjectsPanelStateController* state_controller, tab_groups::TabGroupSyncService* tab_group_sync_service, contextual_tasks::ContextualTasksService* contextual_tasks_service, contextual_tasks::ContextualTasksUiService* contextual_tasks_ui_service) : browser_(browser), + state_controller_(state_controller), tab_group_sync_service_(tab_group_sync_service), contextual_tasks_service_(contextual_tasks_service), contextual_tasks_ui_service_(contextual_tasks_ui_service) { @@ -73,9 +76,33 @@ } } -const std::vector<contextual_tasks::Thread>& +const std::vector<contextual_tasks::Thread> ProjectsPanelController::GetThreads() { - return threads_; + std::vector<contextual_tasks::Thread> eligible_threads; + if (!state_controller_) { + return eligible_threads; + } + + for (const auto& thread : threads_) { + switch (thread.type) { + case contextual_tasks::ThreadType::kAiMode: + if (!state_controller_->CanShowAimThreads()) { + continue; + } + eligible_threads.push_back(thread); + break; + case contextual_tasks::ThreadType::kGemini: + if (!state_controller_->CanShowGeminiThreads()) { + continue; + } + eligible_threads.push_back(thread); + break; + case contextual_tasks::ThreadType::kUnknown: + NOTREACHED(); + } + } + + return eligible_threads; } void ProjectsPanelController::OpenThread(const std::string& thread_server_id) { @@ -205,7 +232,7 @@ weak_this->SortThreads(); for (auto& observer : weak_this->observers_) { - observer.OnThreadsInitialized(weak_this->threads_); + observer.OnThreadsInitialized(weak_this->GetThreads()); } }, weak_ptr_factory_.GetWeakPtr()));
diff --git a/chrome/browser/ui/views/tabs/projects/projects_panel_controller.h b/chrome/browser/ui/views/tabs/projects/projects_panel_controller.h index 2e8ed63..c7445994 100644 --- a/chrome/browser/ui/views/tabs/projects/projects_panel_controller.h +++ b/chrome/browser/ui/views/tabs/projects/projects_panel_controller.h
@@ -25,6 +25,7 @@ } class BrowserWindowInterface; +class ProjectsPanelStateController; // Controller for the projects panel view. Handles fetching, resuming, and // activating tab groups and recent chat threads. @@ -49,6 +50,7 @@ ProjectsPanelController( BrowserWindowInterface* browser, + ProjectsPanelStateController* state_controller, tab_groups::TabGroupSyncService* tab_group_sync_service, contextual_tasks::ContextualTasksService* contextual_tasks_service, contextual_tasks::ContextualTasksUiService* contextual_tasks_ui_service); @@ -66,7 +68,7 @@ void MoveTabGroup(const base::Uuid& group_guid, int new_index); // Returns all threads. - const std::vector<contextual_tasks::Thread>& GetThreads(); + const std::vector<contextual_tasks::Thread> GetThreads(); // Opens the thread. void OpenThread(const std::string& thread_server_id); @@ -107,6 +109,7 @@ void OnGotThreadUrlForResumption(GURL thread_url); const raw_ptr<BrowserWindowInterface> browser_; + const raw_ptr<ProjectsPanelStateController> state_controller_; const raw_ptr<tab_groups::TabGroupSyncService> tab_group_sync_service_; const raw_ptr<contextual_tasks::ContextualTasksService> contextual_tasks_service_;
diff --git a/chrome/browser/ui/views/tabs/projects/projects_panel_controller_browsertest.cc b/chrome/browser/ui/views/tabs/projects/projects_panel_controller_browsertest.cc index 9e6da1c..d29c1d9 100644 --- a/chrome/browser/ui/views/tabs/projects/projects_panel_controller_browsertest.cc +++ b/chrome/browser/ui/views/tabs/projects/projects_panel_controller_browsertest.cc
@@ -26,7 +26,7 @@ void SetUpOnMainThread() override { InProcessBrowserTest::SetUpOnMainThread(); controller_ = std::make_unique<ProjectsPanelController>( - browser(), &mock_tab_group_sync_service_, + browser(), /*state_controller=*/nullptr, &mock_tab_group_sync_service_, &mock_contextual_tasks_service_, &mock_contextual_tasks_ui_service_); }
diff --git a/chrome/browser/ui/views/tabs/projects/projects_panel_controller_unittest.cc b/chrome/browser/ui/views/tabs/projects/projects_panel_controller_unittest.cc index 939a36b3..01e1ea9 100644 --- a/chrome/browser/ui/views/tabs/projects/projects_panel_controller_unittest.cc +++ b/chrome/browser/ui/views/tabs/projects/projects_panel_controller_unittest.cc
@@ -12,13 +12,16 @@ #include "base/uuid.h" #include "chrome/browser/contextual_tasks/mock_contextual_tasks_ui_service.h" #include "chrome/browser/ui/browser_window/test/mock_browser_window_interface.h" +#include "chrome/browser/ui/tabs/projects/projects_panel_state_controller.h" #include "chrome/browser/ui/ui_features.h" #include "components/contextual_tasks/public/contextual_task.h" #include "components/contextual_tasks/public/mock_contextual_tasks_service.h" +#include "components/prefs/testing_pref_service.h" #include "components/saved_tab_groups/public/saved_tab_group.h" #include "components/saved_tab_groups/test_support/mock_tab_group_sync_service.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/base/unowned_user_data/unowned_user_data_host.h" namespace { @@ -77,16 +80,17 @@ const base::Uuid& task_id, const std::string& server_id, const std::string& title, - int64_t last_turn_time_ms = 0) { + int64_t last_turn_time_ms = 0, + contextual_tasks::ThreadType thread_type = + contextual_tasks::ThreadType::kAiMode) { contextual_tasks::ContextualTask task(task_id); - contextual_tasks::Thread thread(contextual_tasks::ThreadType::kAiMode, - server_id, title, last_turn_time_ms, - "conversation_turn_id"); + contextual_tasks::Thread thread(thread_type, server_id, title, + last_turn_time_ms, "conversation_turn_id"); task.AddThread(thread); return task; } -const contextual_tasks::ContextualTask& GetTask1() { +const contextual_tasks::ContextualTask& GetAimTask() { static const base::NoDestructor<contextual_tasks::ContextualTask> task( CreateTaskWithThread( base::Uuid::ParseLowercase("00000000-0000-0000-0000-000000000001"), @@ -94,7 +98,7 @@ return *task; } -const contextual_tasks::ContextualTask& GetTask1WithUpdatedTitle() { +const contextual_tasks::ContextualTask& GetAimTaskWithUpdatedTitle() { static const base::NoDestructor<contextual_tasks::ContextualTask> task( CreateTaskWithThread( base::Uuid::ParseLowercase("00000000-0000-0000-0000-000000000001"), @@ -102,7 +106,7 @@ return *task; } -const contextual_tasks::ContextualTask& GetTask1WithUpdatedLastTurnTime() { +const contextual_tasks::ContextualTask& GetAimTaskWithUpdatedLastTurnTime() { static const base::NoDestructor<contextual_tasks::ContextualTask> task( CreateTaskWithThread( base::Uuid::ParseLowercase("00000000-0000-0000-0000-000000000001"), @@ -110,11 +114,11 @@ return *task; } -const contextual_tasks::ContextualTask& GetTask2() { +const contextual_tasks::ContextualTask& GetGeminiTask() { static const base::NoDestructor<contextual_tasks::ContextualTask> task( CreateTaskWithThread( - base::Uuid::ParseLowercase("00000000-0000-0000-0000-000000000002"), - "id2", "Title 2", 2000)); + base::Uuid::ParseLowercase("00000000-0000-0000-0000-000000000003"), + "id3", "Gemini Title", 2000, contextual_tasks::ThreadType::kGemini)); return *task; } @@ -144,6 +148,18 @@ (override)); }; +class MockProjectsPanelStateController : public ProjectsPanelStateController { + public: + explicit MockProjectsPanelStateController( + BrowserWindowInterface* browser_window) + : ProjectsPanelStateController(browser_window, + nullptr, + nullptr, + nullptr) {} + MOCK_METHOD(bool, CanShowAimThreads, (), (override)); + MOCK_METHOD(bool, CanShowGeminiThreads, (), (override)); +}; + MATCHER_P(GroupIs, expected_group, "") { return arg.saved_guid() == expected_group.saved_guid(); } @@ -155,17 +171,33 @@ ProjectsPanelControllerTest() { EXPECT_CALL(mock_browser_window_interface_, GetBrowserForMigrationOnly()) .WillRepeatedly(testing::Return(nullptr)); + EXPECT_CALL(mock_browser_window_interface_, GetUnownedUserDataHost()) + .WillRepeatedly(testing::ReturnRef(unowned_user_data_host_)); + + mock_state_controller_ = + std::make_unique<testing::NiceMock<MockProjectsPanelStateController>>( + &mock_browser_window_interface_); + + ON_CALL(*mock_state_controller_, CanShowAimThreads()) + .WillByDefault(testing::Return(true)); + ON_CALL(*mock_state_controller_, CanShowGeminiThreads()) + .WillByDefault(testing::Return(true)); } std::unique_ptr<ProjectsPanelController> GetInitializedController() { auto controller = std::make_unique<ProjectsPanelController>( - &mock_browser_window_interface_, &mock_tab_group_sync_service_, - &mock_contextual_tasks_service_, &mock_contextual_tasks_ui_service_); + &mock_browser_window_interface_, mock_state_controller_.get(), + &mock_tab_group_sync_service_, &mock_contextual_tasks_service_, + &mock_contextual_tasks_ui_service_); controller->OnInitialized(); return controller; } + TestingPrefServiceSimple pref_service_; + ui::UnownedUserDataHost unowned_user_data_host_; testing::NiceMock<MockBrowserWindowInterface> mock_browser_window_interface_; + std::unique_ptr<testing::NiceMock<MockProjectsPanelStateController>> + mock_state_controller_; testing::NiceMock<tab_groups::MockTabGroupSyncService> mock_tab_group_sync_service_; testing::NiceMock<contextual_tasks::MockContextualTasksService> @@ -328,15 +360,15 @@ auto controller = GetInitializedController(); controller->OnTaskAdded( - GetTask1(), + GetAimTask(), contextual_tasks::ContextualTasksService::TriggerSource::kLocal); EXPECT_CALL( mock_contextual_tasks_ui_service_, - GetThreadUrlFromTaskId(testing::Eq(GetTask1().GetTaskId()), testing::_)) + GetThreadUrlFromTaskId(testing::Eq(GetAimTask().GetTaskId()), testing::_)) .Times(1); - controller->OpenThread(GetTask1().GetThread()->server_id); + controller->OpenThread(GetAimTask().GetThread()->server_id); } TEST_F(ProjectsPanelControllerTest, HandlesTaskAdded) { @@ -344,54 +376,54 @@ // Task 1 has an older last turn time than task 2. controller->OnTaskAdded( - GetTask1(), + GetAimTask(), contextual_tasks::ContextualTasksService::TriggerSource::kLocal); controller->OnTaskAdded( - GetTask2(), + GetGeminiTask(), contextual_tasks::ContextualTasksService::TriggerSource::kLocal); const auto& threads = controller->GetThreads(); ASSERT_EQ(2u, threads.size()); - ASSERT_LT(GetTask1().GetThread()->last_turn_time, - GetTask2().GetThread()->last_turn_time); + ASSERT_LT(GetAimTask().GetThread()->last_turn_time, + GetGeminiTask().GetThread()->last_turn_time); // Should be sorted by most to least recent last turn time. - EXPECT_EQ(GetTask2().GetThread()->server_id, threads[0].server_id); - EXPECT_EQ(GetTask1().GetThread()->server_id, threads[1].server_id); + EXPECT_EQ(GetGeminiTask().GetThread()->server_id, threads[0].server_id); + EXPECT_EQ(GetAimTask().GetThread()->server_id, threads[1].server_id); } TEST_F(ProjectsPanelControllerTest, HandlesTaskUpdates) { auto controller = GetInitializedController(); controller->OnTaskAdded( - GetTask1(), + GetAimTask(), contextual_tasks::ContextualTasksService::TriggerSource::kLocal); controller->OnTaskAdded( - GetTask2(), + GetGeminiTask(), contextual_tasks::ContextualTasksService::TriggerSource::kLocal); // Update task 1. controller->OnTaskUpdated( - GetTask1WithUpdatedTitle(), + GetAimTaskWithUpdatedTitle(), contextual_tasks::ContextualTasksService::TriggerSource::kLocal); const auto& threads = controller->GetThreads(); ASSERT_EQ(2u, threads.size()); - EXPECT_EQ(GetTask2().GetThread()->server_id, threads[0].server_id); - EXPECT_EQ(GetTask1().GetThread()->server_id, threads[1].server_id); - EXPECT_EQ(GetTask1WithUpdatedTitle().GetThread()->title, threads[1].title); + EXPECT_EQ(GetGeminiTask().GetThread()->server_id, threads[0].server_id); + EXPECT_EQ(GetAimTask().GetThread()->server_id, threads[1].server_id); + EXPECT_EQ(GetAimTaskWithUpdatedTitle().GetThread()->title, threads[1].title); } TEST_F(ProjectsPanelControllerTest, HandlesTaskRemoval) { auto controller = GetInitializedController(); controller->OnTaskAdded( - GetTask1(), + GetAimTask(), contextual_tasks::ContextualTasksService::TriggerSource::kLocal); ASSERT_EQ(1u, controller->GetThreads().size()); controller->OnTaskRemoved( - GetTask1().GetTaskId(), + GetAimTask().GetTaskId(), contextual_tasks::ContextualTasksService::TriggerSource::kLocal); EXPECT_TRUE(controller->GetThreads().empty()); @@ -404,49 +436,92 @@ EXPECT_TRUE(controller->GetThreads().empty()); controller->OnTaskUpdated( - GetTask1(), + GetAimTask(), contextual_tasks::ContextualTasksService::TriggerSource::kLocal); const auto& threads = controller->GetThreads(); ASSERT_EQ(1u, threads.size()); - EXPECT_EQ(GetTask1().GetThread()->server_id, threads[0].server_id); + EXPECT_EQ(GetAimTask().GetThread()->server_id, threads[0].server_id); } TEST_F(ProjectsPanelControllerTest, OrdersTasksByLastTurnTimeWhenUpdated) { auto controller = GetInitializedController(); controller->OnTaskAdded( - GetTask1(), + GetAimTask(), contextual_tasks::ContextualTasksService::TriggerSource::kLocal); controller->OnTaskAdded( - GetTask2(), + GetGeminiTask(), contextual_tasks::ContextualTasksService::TriggerSource::kLocal); // Task 2 has a more recent last turn time (2000) than task 1 (1000). - ASSERT_EQ(GetTask2().GetThread()->server_id, + ASSERT_EQ(GetGeminiTask().GetThread()->server_id, controller->GetThreads()[0].server_id); - ASSERT_LT(GetTask1().GetThread()->last_turn_time, - GetTask2().GetThread()->last_turn_time); + ASSERT_LT(GetAimTask().GetThread()->last_turn_time, + GetGeminiTask().GetThread()->last_turn_time); // Update Task 1 with a more recent last turn time (3000). controller->OnTaskUpdated( - GetTask1WithUpdatedLastTurnTime(), + GetAimTaskWithUpdatedLastTurnTime(), contextual_tasks::ContextualTasksService::TriggerSource::kLocal); const auto& threads = controller->GetThreads(); ASSERT_EQ(2u, threads.size()); // Now, Task 1 should be first. - EXPECT_EQ(GetTask1().GetThread()->server_id, threads[0].server_id); - EXPECT_EQ(GetTask2().GetThread()->server_id, threads[1].server_id); + EXPECT_EQ(GetAimTask().GetThread()->server_id, threads[0].server_id); + EXPECT_EQ(GetGeminiTask().GetThread()->server_id, threads[1].server_id); +} + +TEST_F(ProjectsPanelControllerTest, + GetThreadsFiltersThreadsBasedOnEligibility) { + auto controller = GetInitializedController(); + + controller->OnTaskAdded( + GetAimTask(), + contextual_tasks::ContextualTasksService::TriggerSource::kLocal); + controller->OnTaskAdded( + GetGeminiTask(), + contextual_tasks::ContextualTasksService::TriggerSource::kLocal); + + // Set AIM ineligible, so we should only see the Gemini thread. + EXPECT_CALL(*mock_state_controller_, CanShowAimThreads()) + .WillRepeatedly(testing::Return(false)); + { + const auto& threads = controller->GetThreads(); + ASSERT_EQ(1u, threads.size()); + EXPECT_EQ(contextual_tasks::ThreadType::kGemini, threads[0].type); + } + + // Make AIM eligible again, so we should see both threads. + EXPECT_CALL(*mock_state_controller_, CanShowAimThreads()) + .WillRepeatedly(testing::Return(true)); + { + const auto& threads = controller->GetThreads(); + ASSERT_EQ(2u, threads.size()); + ASSERT_LE(GetAimTask().GetThread()->last_turn_time, + GetGeminiTask().GetThread()->last_turn_time); + EXPECT_EQ(GetGeminiTask().GetThread()->server_id, threads[0].server_id); + EXPECT_EQ(GetAimTask().GetThread()->server_id, threads[1].server_id); + } + + // Set Gemini ineligible, so we should only see the AIM thread. + EXPECT_CALL(*mock_state_controller_, CanShowGeminiThreads()) + .WillRepeatedly(testing::Return(false)); + { + const auto& threads = controller->GetThreads(); + ASSERT_EQ(1u, threads.size()); + EXPECT_EQ(contextual_tasks::ThreadType::kAiMode, threads[0].type); + } } class ProjectsPanelControllerObserverTest : public ProjectsPanelControllerTest { public: void SetUp() override { controller_ = std::make_unique<ProjectsPanelController>( - &mock_browser_window_interface_, &mock_tab_group_sync_service_, - &mock_contextual_tasks_service_, &mock_contextual_tasks_ui_service_); + &mock_browser_window_interface_, mock_state_controller_.get(), + &mock_tab_group_sync_service_, &mock_contextual_tasks_service_, + &mock_contextual_tasks_ui_service_); controller_->AddObserver(&observer_); }
diff --git a/chrome/browser/ui/views/tabs/projects/projects_panel_view.cc b/chrome/browser/ui/views/tabs/projects/projects_panel_view.cc index 3f52f484..b515e51 100644 --- a/chrome/browser/ui/views/tabs/projects/projects_panel_view.cc +++ b/chrome/browser/ui/views/tabs/projects/projects_panel_view.cc
@@ -229,11 +229,14 @@ }; } // namespace -ProjectsPanelView::ProjectsPanelView(BrowserWindowInterface* browser, - actions::ActionItem* root_action_item) +ProjectsPanelView::ProjectsPanelView( + BrowserWindowInterface* browser, + actions::ActionItem* root_action_item, + ProjectsPanelStateController* state_controller) : browser_(browser), root_action_item_(root_action_item), action_view_controller_(std::make_unique<views::ActionViewController>()), + state_controller_(state_controller), resize_animation_(this), focus_search_(std::make_unique<views::FocusSearch>(this, /*cycle=*/true, @@ -257,7 +260,7 @@ bool threads_enabled = tab_groups::IsThreadsInProjectsPanelEnabled(); panel_controller_ = std::make_unique<ProjectsPanelController>( - browser_, + browser_, state_controller_, tab_groups::TabGroupSyncServiceFactory::GetForProfile( browser->GetProfile()), threads_enabled @@ -384,31 +387,6 @@ kProjectsPanelRegionHorizontalMargins); threads_activity_menu_model_ = std::make_unique<ui::SimpleMenuModel>(this); - threads_activity_menu_model_->AddItemWithIcon( - kGeminiActivity, - l10n_util::GetStringUTF16(IDS_PROJECTS_PANEL_GEMINI_ACTIVITY), - ui::ImageModel::FromVectorIcon( - projects_panel::GetIconForThreadType( - contextual_tasks::ThreadType::kGemini), - ui::kColorIcon, kThreadsActivityMenuIconSize)); - threads_activity_menu_model_->SetElementIdentifierAt( - threads_activity_menu_model_->GetItemCount() - 1, - kProjectsPanelThreadsActivityGeminiItemElementId); - - threads_activity_menu_model_->AddItemWithIcon( - kAiModeActivity, - l10n_util::GetStringUTF16(IDS_PROJECTS_PANEL_AI_MODE_ACTIVITY), - ui::ImageModel::FromVectorIcon( - projects_panel::GetIconForThreadType( - contextual_tasks::ThreadType::kAiMode), - ui::kColorIcon, kThreadsActivityMenuIconSize)); - threads_activity_menu_model_->SetElementIdentifierAt( - threads_activity_menu_model_->GetItemCount() - 1, - kProjectsPanelThreadsActivityAiModeItemElementId); - - threads_activity_menu_runner_ = std::make_unique<views::MenuRunner>( - threads_activity_menu_model_.get(), - views::MenuRunner::CONTEXT_MENU | views::MenuRunner::IS_NESTED); } content_container_->SetLayoutManager( @@ -802,6 +780,37 @@ } void ProjectsPanelView::OnThreadsActivityMenuButtonPressed() { + threads_activity_menu_model_->Clear(); + + if (state_controller_->CanShowGeminiThreads()) { + threads_activity_menu_model_->AddItemWithIcon( + kGeminiActivity, + l10n_util::GetStringUTF16(IDS_PROJECTS_PANEL_GEMINI_ACTIVITY), + ui::ImageModel::FromVectorIcon( + projects_panel::GetIconForThreadType( + contextual_tasks::ThreadType::kGemini), + ui::kColorIcon, kThreadsActivityMenuIconSize)); + threads_activity_menu_model_->SetElementIdentifierAt( + threads_activity_menu_model_->GetItemCount() - 1, + kProjectsPanelThreadsActivityGeminiItemElementId); + } + + if (state_controller_->CanShowAimThreads()) { + threads_activity_menu_model_->AddItemWithIcon( + kAiModeActivity, + l10n_util::GetStringUTF16(IDS_PROJECTS_PANEL_AI_MODE_ACTIVITY), + ui::ImageModel::FromVectorIcon( + projects_panel::GetIconForThreadType( + contextual_tasks::ThreadType::kAiMode), + ui::kColorIcon, kThreadsActivityMenuIconSize)); + threads_activity_menu_model_->SetElementIdentifierAt( + threads_activity_menu_model_->GetItemCount() - 1, + kProjectsPanelThreadsActivityAiModeItemElementId); + } + + threads_activity_menu_runner_ = std::make_unique<views::MenuRunner>( + threads_activity_menu_model_.get(), + views::MenuRunner::CONTEXT_MENU | views::MenuRunner::IS_NESTED); threads_activity_menu_runner_->RunMenuAt( GetWidget(), threads_activity_menu_button_->button_controller(), threads_activity_menu_button_->GetAnchorBoundsInScreen(),
diff --git a/chrome/browser/ui/views/tabs/projects/projects_panel_view.h b/chrome/browser/ui/views/tabs/projects/projects_panel_view.h index 6d23fc0..3988921 100644 --- a/chrome/browser/ui/views/tabs/projects/projects_panel_view.h +++ b/chrome/browser/ui/views/tabs/projects/projects_panel_view.h
@@ -60,7 +60,8 @@ public: ProjectsPanelView(BrowserWindowInterface* browser, - actions::ActionItem* root_action_item); + actions::ActionItem* root_action_item, + ProjectsPanelStateController* state_controller); ProjectsPanelView(const ProjectsPanelView&) = delete; ProjectsPanelView& operator=(const ProjectsPanelView&) = delete; ~ProjectsPanelView() override; @@ -190,6 +191,7 @@ std::unique_ptr<views::ActionViewController> action_view_controller_; std::unique_ptr<ProjectsPanelController> panel_controller_; + const raw_ptr<ProjectsPanelStateController> state_controller_ = nullptr; // Animation when opening and closing the panel. gfx::SlideAnimation resize_animation_;
diff --git a/chrome/browser/ui/views/tabs/projects/projects_panel_view_interactive_uitest.cc b/chrome/browser/ui/views/tabs/projects/projects_panel_view_interactive_uitest.cc index a9594eb..0e7b0fb 100644 --- a/chrome/browser/ui/views/tabs/projects/projects_panel_view_interactive_uitest.cc +++ b/chrome/browser/ui/views/tabs/projects/projects_panel_view_interactive_uitest.cc
@@ -3,7 +3,13 @@ // found in the LICENSE file. #include "base/test/scoped_feature_list.h" +#include "chrome/browser/autocomplete/aim_eligibility_service_factory.h" +#include "chrome/browser/glic/public/glic_enabling.h" +#include "chrome/browser/glic/public/glic_keyed_service.h" +#include "chrome/browser/glic/public/glic_keyed_service_factory.h" +#include "chrome/browser/signin/identity_manager_factory.h" #include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_actions.h" #include "chrome/browser/ui/browser_element_identifiers.h" #include "chrome/browser/ui/tabs/projects/projects_panel_state_controller.h" #include "chrome/browser/ui/tabs/tab_group_model.h" @@ -16,8 +22,11 @@ #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" #include "chrome/test/interaction/interactive_browser_test.h" +#include "components/keyed_service/content/browser_context_dependency_manager.h" +#include "components/omnibox/browser/mock_aim_eligibility_service.h" #include "components/saved_tab_groups/public/features.h" #include "content/public/test/browser_test.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" #include "ui/base/interaction/element_identifier.h" #include "ui/base/test/ui_controls.h" #include "ui/compositor/layer.h" @@ -25,13 +34,41 @@ #include "ui/views/interaction/interactive_views_test.h" #include "ui/views/view_shadow.h" +namespace { +constexpr int kBrowserWindowWidth = 1400; +constexpr int kBrowserWindowHeight = 800; +} // namespace + namespace base::test { DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kNewTabElementId); +class MockProjectsPanelStateController : public ProjectsPanelStateController { + public: + MockProjectsPanelStateController(BrowserWindowInterface* browser_window, + bool is_aim_eligible, + bool is_gemini_eligible) + : ProjectsPanelStateController(browser_window, + /*root_action_item=*/nullptr, + /*aim_eligibility_service=*/nullptr, + /*glic_enabling=*/nullptr), + is_aim_eligible_(is_aim_eligible), + is_gemini_eligible_(is_gemini_eligible) {} + + bool CanShowAimThreads() override { return is_aim_eligible_; } + bool CanShowGeminiThreads() override { return is_gemini_eligible_; } + + private: + bool is_aim_eligible_ = false; + bool is_gemini_eligible_ = false; +}; + class ProjectsPanelInteractiveUiTest : public InteractiveBrowserTest { public: - ProjectsPanelInteractiveUiTest() { + explicit ProjectsPanelInteractiveUiTest(bool is_aim_eligible = true, + bool is_gemini_eligible = true) + : is_aim_eligible_(is_aim_eligible), + is_gemini_eligible_(is_gemini_eligible) { scoped_feature_list_.InitWithFeaturesAndParameters( {{tabs::kVerticalTabs, {}}, {tab_groups::kProjectsPanel, @@ -40,17 +77,42 @@ ProjectsPanelView::set_threads_visible_for_testing(true); ProjectsPanelView::disable_animations_for_testing(); } - ~ProjectsPanelInteractiveUiTest() override = default; + + void SetUpInProcessBrowserTestFixture() override { + InteractiveBrowserTest::SetUpInProcessBrowserTestFixture(); + projects_panel_state_controller_override_ = + BrowserWindowFeatures::GetUserDataFactoryForTesting() + .AddOverrideForTesting<MockProjectsPanelStateController>( + base::BindRepeating( + [](bool is_aim_eligible, bool is_gemini_eligible, + BrowserWindowInterface& browser) + -> std::unique_ptr<MockProjectsPanelStateController> { + return std::make_unique<MockProjectsPanelStateController>( + &browser, is_aim_eligible, is_gemini_eligible); + }, + is_aim_eligible_, is_gemini_eligible_)); + } void SetUpOnMainThread() override { InteractiveBrowserTest::SetUpOnMainThread(); + // Resize the window to be wide enough to accommodate a wide vertical tab + // strip and the toolbar. + browser()->window()->SetBounds( + gfx::Rect(0, 0, kBrowserWindowWidth, kBrowserWindowHeight)); + // Enter Vertical Tabs mode. tabs::VerticalTabStripStateController::From(browser()) ->SetVerticalTabsEnabled(true); RunScheduledLayouts(); } + void TearDownInProcessBrowserTestFixture() override { + projects_panel_state_controller_override_ = + ui::UserDataFactory::ScopedOverride(); + InteractiveBrowserTest::TearDownInProcessBrowserTestFixture(); + } + auto OpenProjectsPanel() { return Steps(WaitForShow(kVerticalTabStripProjectsButtonElementId), PressButton(kVerticalTabStripProjectsButtonElementId), @@ -98,6 +160,9 @@ } private: + bool is_aim_eligible_ = false; + bool is_gemini_eligible_ = false; + ui::UserDataFactory::ScopedOverride projects_panel_state_controller_override_; base::test::ScopedFeatureList scoped_feature_list_; }; @@ -359,4 +424,40 @@ 1u)); } +class ProjectsPanelAimIneligibleInteractiveUiTest + : public ProjectsPanelInteractiveUiTest { + public: + ProjectsPanelAimIneligibleInteractiveUiTest() + : ProjectsPanelInteractiveUiTest(/*is_aim_eligible=*/false, + /*is_gemini_eligible=*/true) {} +}; + +IN_PROC_BROWSER_TEST_F(ProjectsPanelAimIneligibleInteractiveUiTest, + ThreadsActivityMenu_AiModeActivityHiddenWhenIneligible) { + RunTestSequence( + OpenProjectsPanel(), + // Click the threads activity menu button. + MoveMouseTo(kProjectsPanelThreadsActivityButtonElementId), ClickMouse(), + // Verify that "AI Mode activity" is NOT present in the menu. + EnsureNotPresent(kProjectsPanelThreadsActivityAiModeItemElementId)); +} + +class ProjectsPanelGeminiIneligibleInteractiveUiTest + : public ProjectsPanelInteractiveUiTest { + public: + ProjectsPanelGeminiIneligibleInteractiveUiTest() + : ProjectsPanelInteractiveUiTest(/*is_aim_eligible=*/true, + /*is_gemini_eligible=*/false) {} +}; + +IN_PROC_BROWSER_TEST_F(ProjectsPanelGeminiIneligibleInteractiveUiTest, + ThreadsActivityMenu_GeminiActivityHiddenWhenIneligible) { + RunTestSequence( + OpenProjectsPanel(), + // Click the threads activity menu button. + MoveMouseTo(kProjectsPanelThreadsActivityButtonElementId), ClickMouse(), + // Verify that "Gemini app activity" is NOT present in the menu. + EnsureNotPresent(kProjectsPanelThreadsActivityGeminiItemElementId)); +} + } // namespace base::test
diff --git a/chrome/browser/ui/views/tabs/projects/projects_panel_view_unittest.cc b/chrome/browser/ui/views/tabs/projects/projects_panel_view_unittest.cc index 28f4452..3bfc81b 100644 --- a/chrome/browser/ui/views/tabs/projects/projects_panel_view_unittest.cc +++ b/chrome/browser/ui/views/tabs/projects/projects_panel_view_unittest.cc
@@ -84,7 +84,8 @@ void CreateView() { auto view = std::make_unique<ProjectsPanelView>( - &mock_browser_window_interface_, root_action_item_.get()); + &mock_browser_window_interface_, root_action_item_.get(), + state_controller_.get()); widget_ = CreateTestWidget(views::Widget::InitParams::CLIENT_OWNS_WIDGET); view_ = widget_->SetContentsView(std::move(view)); widget_->SetBounds(gfx::Rect(0, 0, 800, 600));
diff --git a/chrome/browser/ui/views/tabs/tab_strip_action_container.cc b/chrome/browser/ui/views/tabs/tab_strip_action_container.cc index 96ec19d..acb712e 100644 --- a/chrome/browser/ui/views/tabs/tab_strip_action_container.cc +++ b/chrome/browser/ui/views/tabs/tab_strip_action_container.cc
@@ -23,7 +23,6 @@ #include "chrome/browser/glic/public/glic_keyed_service.h" #include "chrome/browser/glic/public/glic_keyed_service_factory.h" #include "chrome/browser/glic/resources/grit/glic_browser_resources.h" -#include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_element_identifiers.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/browser_window/public/browser_window_interface.h" @@ -46,6 +45,7 @@ #include "chrome/grit/generated_resources.h" #include "components/feature_engagement/public/feature_constants.h" #include "components/tabs/public/tab_interface.h" +#include "ui/actions/actions.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/metadata/metadata_impl_macros.h" #include "ui/gfx/animation/tween.h" @@ -64,6 +64,9 @@ #include "chrome/browser/contextual_cueing/contextual_cueing_features.h" #include "chrome/browser/private_ai/private_ai_service.h" #include "chrome/browser/private_ai/private_ai_service_factory.h" +#include "chrome/browser/ui/actions/chrome_action_id.h" +#include "chrome/browser/ui/tabs/public/tab_features.h" +#include "chrome/browser/ui/views/page_action/page_action_controller.h" #include "components/private_ai/client.h" #include "components/private_ai/error_code.h" #include "components/private_ai/features.h" @@ -350,9 +353,84 @@ } } +void TabStripActionContainer::OnTriggerAnchoredMessage( + std::string label, + std::string anchored_message_text, + std::optional<std::string> prompt_suggestion) { + if (GetIsShowingGlicActorTaskIconNudge()) { + return; + } + + CHECK(glic_button_); + + auto* active_tab = browser_window_interface_->GetActiveTabInterface(); + if (!active_tab) { + return; + } + + auto* tab_features = active_tab->GetTabFeatures(); + if (!tab_features) { + return; + } + + auto* controller = tab_features->page_action_controller(); + if (!controller) { + return; + } + + // Find the ActionItem for contextual cueing, registered at browser + // initialization in BrowserActions::InitializeBrowserActions(). + auto* action = + actions::ActionManager::Get().FindAction(kActionGlicContextualCueing); + if (!action) { + return; + } + + // Set the chip text to the cue label. + action->SetText(base::UTF8ToUTF16(label)); + action->SetEnabled(true); + action->SetVisible(true); + action->SetInvokeActionCallback(base::BindRepeating( + [](base::WeakPtr<BrowserWindowInterface> bwi, + std::optional<std::string> prompt, actions::ActionItem* item, + actions::ActionInvocationContext context) { + if (!bwi) { + return; + } + if (auto* glic_service = + glic::GlicKeyedService::Get(bwi->GetProfile())) { + glic_service->ToggleUI( + bwi.get(), /*prevent_close=*/false, + glic::mojom::InvocationSource::kAnchoredContextualCue, prompt); + } + }, + browser_window_interface_->GetWeakPtr(), std::move(prompt_suggestion))); + + anchored_message_subscription_ = + controller->CreateActionItemSubscription(action); + controller->Show(kActionGlicContextualCueing); + // The secondary label becomes the anchored message bubble text. + controller->SetAnchoredMessageText(kActionGlicContextualCueing, + base::UTF8ToUTF16(anchored_message_text)); + controller->ShouldShowAnchoredMessageCloseIcon(kActionGlicContextualCueing, + true); + controller->ShowAnchoredMessage(kActionGlicContextualCueing); +} + void TabStripActionContainer::OnHideGlicNudgeUI() { CHECK(glic_button_); HideTabStripNudge(glic_button_); + + // Also dismiss the anchored message if it was shown via the page action path. + anchored_message_subscription_ = {}; + auto* active_tab = browser_window_interface_->GetActiveTabInterface(); + if (active_tab) { + if (auto* tab_features = active_tab->GetTabFeatures()) { + if (auto* controller = tab_features->page_action_controller()) { + controller->Hide(kActionGlicContextualCueing); + } + } + } } bool TabStripActionContainer::GetIsShowingGlicNudge() {
diff --git a/chrome/browser/ui/views/tabs/tab_strip_action_container.h b/chrome/browser/ui/views/tabs/tab_strip_action_container.h index 94558e94..c1033dc 100644 --- a/chrome/browser/ui/views/tabs/tab_strip_action_container.h +++ b/chrome/browser/ui/views/tabs/tab_strip_action_container.h
@@ -118,6 +118,10 @@ // GlicNudgeDelegate: void OnTriggerGlicNudgeUI(std::string label) override; + void OnTriggerAnchoredMessage( + std::string label, + std::string anchored_message_text, + std::optional<std::string> prompt_suggestion) override; void OnHideGlicNudgeUI() override; bool GetIsShowingGlicNudge() override; @@ -221,6 +225,10 @@ std::list<base::CallbackListSubscription> subscriptions_; + // Tracks the page-action subscription for the anchored contextual cue. + // Reset when the anchored message is hidden or replaced. + base::CallbackListSubscription anchored_message_subscription_; + std::unique_ptr<TabStripNudgeAnimationSession> animation_session_; // Border insets as passed down from the HorizontalTabStripRegionView, used to
diff --git a/chrome/browser/ui/views/tabs/tab_strip_action_container_browsertest.cc b/chrome/browser/ui/views/tabs/tab_strip_action_container_browsertest.cc index 3f90fac..501c799f 100644 --- a/chrome/browser/ui/views/tabs/tab_strip_action_container_browsertest.cc +++ b/chrome/browser/ui/views/tabs/tab_strip_action_container_browsertest.cc
@@ -319,7 +319,8 @@ nudge_controller->UpdateNudgeLabel( browser()->tab_strip_model()->GetActiveWebContents(), "test", - /*prompt_suggestion=*/std::nullopt, /*activity=*/std::nullopt, + /*prompt_suggestion=*/std::nullopt, + /*anchored_message_text=*/std::string(), /*activity=*/std::nullopt, base::DoNothing()); ShowTabStripNudgeButton(GlicNudgeButton());
diff --git a/chrome/browser/ui/views/tabs/tab_strip_action_container_unittest.cc b/chrome/browser/ui/views/tabs/tab_strip_action_container_unittest.cc index d030460d..f35e8f7 100644 --- a/chrome/browser/ui/views/tabs/tab_strip_action_container_unittest.cc +++ b/chrome/browser/ui/views/tabs/tab_strip_action_container_unittest.cc
@@ -300,6 +300,7 @@ BuildGlicContainer(/*use_otr_profile=*/false); glic_nudge_controller_->UpdateNudgeLabel( web_contents(), "TEST", /*prompt_suggestion=*/std::nullopt, + /*anchored_message_text=*/std::string(), /*activity=*/std::nullopt, base::NullCallback()); ASSERT_EQ(tab_strip_action_container_->GetGlicButton()->GetText(), u"TEST"); } @@ -313,6 +314,7 @@ glic_nudge_controller_->UpdateNudgeLabel( web_contents(), "TEST", /*prompt_suggestion=*/std::nullopt, + /*anchored_message_text=*/std::string(), /*activity=*/std::nullopt, base::NullCallback()); ASSERT_TRUE(tab_strip_action_container_->GetIsShowingGlicNudge()); ASSERT_EQ(tab_strip_action_container_->GetGlicButton()->GetText(), u"TEST");
diff --git a/chrome/browser/ui/views/tabs/vertical/vertical_tab_drag_handler.cc b/chrome/browser/ui/views/tabs/vertical/vertical_tab_drag_handler.cc index 9cf72b1..0d61efa 100644 --- a/chrome/browser/ui/views/tabs/vertical/vertical_tab_drag_handler.cc +++ b/chrome/browser/ui/views/tabs/vertical/vertical_tab_drag_handler.cc
@@ -36,6 +36,7 @@ #include "ui/base/metadata/metadata_impl_macros.h" #include "ui/base/models/list_selection_model.h" #include "ui/compositor/layer.h" +#include "ui/events/event.h" #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/vector2d.h" #include "ui/views/view_utils.h" @@ -113,7 +114,7 @@ void VerticalTabDragHandlerImpl::InitializeDrag( TabCollectionNode& node, const ui::ListSelectionModel& original_selection_model, - const ui::MouseEvent& event) { + const ui::LocatedEvent& event) { ResetDragState(); drag_controller_ = std::make_unique<TabDragController>(); @@ -253,7 +254,7 @@ } bool VerticalTabDragHandlerImpl::ContinueDrag(views::View& event_source_view, - const ui::MouseEvent& event) { + const ui::LocatedEvent& event) { if (!drag_controller_) { return false; } @@ -607,6 +608,61 @@ return parent()->CanAcceptEvent(event); } +void VerticalTabDragHandlerImpl::OnGestureEvent(ui::GestureEvent* event) { + if (!drag_controller_) { + return; + } + + bool handler_alive = true; + + switch (event->type()) { + case ui::EventType::kGestureScrollEnd: + case ui::EventType::kScrollFlingStart: + case ui::EventType::kGestureEnd: + EndDrag(EndDragReason::kComplete); + break; + + case ui::EventType::kGestureLongTap: { + const auto& session_data = drag_controller_->GetSessionData(); + TabCollectionNode* source_node = nullptr; + if (session_data.group_header_drag_data_) { + source_node = + GetNodeForTabGroup(session_data.group_header_drag_data_->group); + } else { + source_node = + GetNodeForContents(session_data.source_dragged_contents()); + } + + if (source_node && source_node->view()) { + views::View* source_view = source_node->view(); + ui::GestureEvent converted_event(*event, static_cast<View*>(this), + source_view); + source_view->OnGestureEvent(&converted_event); + } + + EndDrag(EndDragReason::kCancel); + break; + } + + case ui::EventType::kGestureTapDown: + EndDrag(EndDragReason::kCancel); + break; + + case ui::EventType::kGestureScrollUpdate: + handler_alive = ContinueDrag(*this, *event); + break; + + default: + break; + } + + event->SetHandled(); + + if (!handler_alive) { + return; + } +} + bool VerticalTabDragHandlerImpl::OnMouseDragged(const ui::MouseEvent& event) { return ContinueDrag(*this, event); }
diff --git a/chrome/browser/ui/views/tabs/vertical/vertical_tab_drag_handler.h b/chrome/browser/ui/views/tabs/vertical/vertical_tab_drag_handler.h index 2aa0964..589555d 100644 --- a/chrome/browser/ui/views/tabs/vertical/vertical_tab_drag_handler.h +++ b/chrome/browser/ui/views/tabs/vertical/vertical_tab_drag_handler.h
@@ -37,11 +37,11 @@ virtual void InitializeDrag( TabCollectionNode& node, const ui::ListSelectionModel& original_selection_model, - const ui::MouseEvent& event) = 0; + const ui::LocatedEvent& event) = 0; // Triggers updates to tab dragging state based on the latest mouse event. // Returns a bool indicating whether the drag was successfully handled. virtual bool ContinueDrag(views::View& event_source_view, - const ui::MouseEvent& event) = 0; + const ui::LocatedEvent& event) = 0; // Ends the drag, if started. virtual void EndDrag(EndDragReason reason) = 0; @@ -125,9 +125,9 @@ // VerticalTabDragHandler void InitializeDrag(TabCollectionNode& node, const ui::ListSelectionModel& original_selection_model, - const ui::MouseEvent& event) override; + const ui::LocatedEvent& event) override; bool ContinueDrag(views::View& event_source_view, - const ui::MouseEvent& event) override; + const ui::LocatedEvent& event) override; void EndDrag(EndDragReason reason) override; void HandleDraggedTabsOverNode( const TabCollectionNode& node, @@ -153,6 +153,7 @@ // TabDragContext bool CanAcceptEvent(const ui::Event& event) override; + void OnGestureEvent(ui::GestureEvent* event) override; void OnMouseReleased(const ui::MouseEvent& event) override; bool OnMouseDragged(const ui::MouseEvent& event) override; void OnMouseCaptureLost() override;
diff --git a/chrome/browser/ui/views/tabs/vertical/vertical_tab_drag_interactive_uitest.cc b/chrome/browser/ui/views/tabs/vertical/vertical_tab_drag_interactive_uitest.cc index 6702f5c..f69518e 100644 --- a/chrome/browser/ui/views/tabs/vertical/vertical_tab_drag_interactive_uitest.cc +++ b/chrome/browser/ui/views/tabs/vertical/vertical_tab_drag_interactive_uitest.cc
@@ -33,6 +33,7 @@ #include "ui/base/test/ui_controls.h" #include "ui/events/event.h" #include "ui/events/keycodes/keyboard_codes.h" +#include "ui/views/interaction/interaction_test_util_mouse.h" #include "ui/views/interaction/interactive_views_test.h" #include "ui/views/test/views_test_utils.h" #include "ui/views/view.h" @@ -111,6 +112,17 @@ } // namespace +DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kSecondTab); +DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kThirdTab); +DEFINE_LOCAL_STATE_IDENTIFIER_VALUE(ui::test::PollingStateObserver<size_t>, + kBrowserCountPoller); +DEFINE_LOCAL_STATE_IDENTIFIER_VALUE(ui::test::PollingStateObserver<bool>, + kDragStatePoller); +DEFINE_LOCAL_STATE_IDENTIFIER_VALUE(ui::test::PollingStateObserver<URLs>, + kTabOrderPoller); +DEFINE_LOCAL_STATE_IDENTIFIER_VALUE(ui::test::PollingStateObserver<PinnedURLs>, + kPinnedTabOrderPoller); + class VerticalTabDragTest : public VerticalTabsInteractiveTestMixin<InteractiveBrowserTest> { public: @@ -134,12 +146,17 @@ auto StartDragBetweenTabs(int from_tab_index, int to_tab_index) { const char kTabToDragFrom[] = "Tab to drag"; const char kTabToDragTo[] = "Tab to drag to"; - return Steps(Log("Start drag from " + base::NumberToString(from_tab_index) + - " to " + base::NumberToString(to_tab_index)), - NameTabViewAt(kTabToDragFrom, from_tab_index), - NameTabViewAt(kTabToDragTo, to_tab_index), - MoveMouseTo(kTabToDragFrom), - DragMouseTo(kTabToDragTo, CenterPoint(), /*release=*/false)); + return Steps( + Log("Start drag from " + base::NumberToString(from_tab_index) + " to " + + base::NumberToString(to_tab_index)), + NameTabViewAt(kTabToDragFrom, from_tab_index), + NameTabViewAt(kTabToDragTo, to_tab_index), MoveMouseTo(kTabToDragFrom), + ClickMouse(ui_controls::LEFT, /*release=*/false), + // Poll state before moving mouse in touch mode to do a long press. + If([this]() { return mouse_util().GetTouchMode(); }, + Then(Steps(PollState(kDragStatePoller, GetDragActive()), + WaitForState(kDragStatePoller, true)))), + MoveMouseTo(kTabToDragTo)); } auto StartDragFromGroupToTab(int from_group_index, int to_tab_index) { @@ -241,17 +258,6 @@ gfx::Animation::RichAnimationRenderMode::FORCE_DISABLED); }; -DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kSecondTab); -DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kThirdTab); -DEFINE_LOCAL_STATE_IDENTIFIER_VALUE(ui::test::PollingStateObserver<size_t>, - kBrowserCountPoller); -DEFINE_LOCAL_STATE_IDENTIFIER_VALUE(ui::test::PollingStateObserver<bool>, - kDragStatePoller); -DEFINE_LOCAL_STATE_IDENTIFIER_VALUE(ui::test::PollingStateObserver<URLs>, - kTabOrderPoller); -DEFINE_LOCAL_STATE_IDENTIFIER_VALUE(ui::test::PollingStateObserver<PinnedURLs>, - kPinnedTabOrderPoller); - IN_PROC_BROWSER_TEST_F(VerticalTabDragTest, DragWithinUnpinnedContainer) { TabStripModel* tab_strip_model = browser()->GetTabStripModel(); ASSERT_NE(nullptr, tab_strip_model); @@ -288,6 +294,51 @@ })); } +// This test uses an experimental API to replace mouse events with touch events. +// It is currently only supported on Ash Chrome. +#if BUILDFLAG(IS_CHROMEOS) +#define MAYBE_DragWithinUnpinnedContainerTouch DragWithinUnpinnedContainerTouch +#else +#define MAYBE_DragWithinUnpinnedContainerTouch \ + DISABLED_DragWithinUnpinnedContainerTouch +#endif +IN_PROC_BROWSER_TEST_F(VerticalTabDragTest, + MAYBE_DragWithinUnpinnedContainerTouch) { + TabStripModel* tab_strip_model = browser()->GetTabStripModel(); + ASSERT_NE(nullptr, tab_strip_model); + RunTestSequence( + Check([this]() { return mouse_util().SetTouchMode(true); }), + AddInstrumentedTab(kSecondTab, GURL(chrome::kChromeUIBookmarksURL), 1), + AddInstrumentedTab(kThirdTab, GURL(chrome::kChromeUISettingsURL), 2), + + StartDragBetweenTabs(2, 1), + PollState(kTabOrderPoller, GetTabOrder(tab_strip_model)), + WaitForState(kTabOrderPoller, + URLs({url::kAboutBlankURL, chrome::kChromeUISettingsURL, + chrome::kChromeUIBookmarksURL})), + + ContinueDragToTab(2), + WaitForState(kTabOrderPoller, + URLs({url::kAboutBlankURL, chrome::kChromeUIBookmarksURL, + chrome::kChromeUISettingsURL})), + + ContinueDragToTab(0), + WaitForState(kTabOrderPoller, + URLs({chrome::kChromeUISettingsURL, url::kAboutBlankURL, + chrome::kChromeUIBookmarksURL})), + + // Release the drag and ensure tab ordering remains. + ReleaseMouse(), WaitForState(kDragStatePoller, false), Do([&]() { + ASSERT_EQ(3, tab_strip_model->count()); + EXPECT_EQ(GURL(chrome::kChromeUISettingsURL), + tab_strip_model->GetWebContentsAt(0)->GetURL()); + EXPECT_EQ(GURL(url::kAboutBlankURL), + tab_strip_model->GetWebContentsAt(1)->GetURL()); + EXPECT_EQ(GURL(chrome::kChromeUIBookmarksURL), + tab_strip_model->GetWebContentsAt(2)->GetURL()); + })); +} + IN_PROC_BROWSER_TEST_F(VerticalTabDragTest, CancelDragWithinUnpinnedContainer) { TabStripModel* tab_strip_model = browser()->GetTabStripModel(); ASSERT_NE(nullptr, tab_strip_model);
diff --git a/chrome/browser/ui/views/tabs/vertical/vertical_tab_group_header_view.cc b/chrome/browser/ui/views/tabs/vertical/vertical_tab_group_header_view.cc index 2addce2b..d9c5bd55 100644 --- a/chrome/browser/ui/views/tabs/vertical/vertical_tab_group_header_view.cc +++ b/chrome/browser/ui/views/tabs/vertical/vertical_tab_group_header_view.cc
@@ -262,17 +262,31 @@ void VerticalTabGroupHeaderView::OnGestureEvent(ui::GestureEvent* event) { switch (event->type()) { + case ui::EventType::kGestureTapDown: + // Required to allow the touch system to know this is a gesture target + // for subsequent events like LongPress and Scroll. + event->SetHandled(); + break; + case ui::EventType::kGestureTap: delegate_->ToggleCollapsedState( ToggleTabGroupCollapsedStateOrigin::kGesture); + event->SetHandled(); break; + + case ui::EventType::kGestureLongPress: + delegate_->InitHeaderDrag(*event); + event->SetHandled(); + break; + case ui::EventType::kGestureLongTap: ShowEditorBubble(); + event->SetHandled(); break; + default: break; } - event->SetHandled(); } void VerticalTabGroupHeaderView::OnMouseMoved(const ui::MouseEvent& event) {
diff --git a/chrome/browser/ui/views/tabs/vertical/vertical_tab_group_header_view.h b/chrome/browser/ui/views/tabs/vertical/vertical_tab_group_header_view.h index c1d3263..fe54f81 100644 --- a/chrome/browser/ui/views/tabs/vertical/vertical_tab_group_header_view.h +++ b/chrome/browser/ui/views/tabs/vertical/vertical_tab_group_header_view.h
@@ -47,8 +47,8 @@ bool stop_context_menu_propagation) = 0; virtual std::u16string GetGroupContentString() const = 0; - virtual void InitHeaderDrag(const ui::MouseEvent& event) = 0; - virtual bool ContinueHeaderDrag(const ui::MouseEvent& event) = 0; + virtual void InitHeaderDrag(const ui::LocatedEvent& event) = 0; + virtual bool ContinueHeaderDrag(const ui::LocatedEvent& event) = 0; virtual void CancelHeaderDrag() = 0; virtual void HideHoverCard() const = 0;
diff --git a/chrome/browser/ui/views/tabs/vertical/vertical_tab_group_header_view_unittest.cc b/chrome/browser/ui/views/tabs/vertical/vertical_tab_group_header_view_unittest.cc index a595a8ec..4d8e7aaf 100644 --- a/chrome/browser/ui/views/tabs/vertical/vertical_tab_group_header_view_unittest.cc +++ b/chrome/browser/ui/views/tabs/vertical/vertical_tab_group_header_view_unittest.cc
@@ -29,8 +29,8 @@ (override)); MOCK_METHOD(views::Widget*, ShowGroupEditorBubble, (bool), (override)); MOCK_METHOD(std::u16string, GetGroupContentString, (), (const, override)); - MOCK_METHOD(void, InitHeaderDrag, (const ui::MouseEvent&), (override)); - MOCK_METHOD(bool, ContinueHeaderDrag, (const ui::MouseEvent&), (override)); + MOCK_METHOD(void, InitHeaderDrag, (const ui::LocatedEvent&), (override)); + MOCK_METHOD(bool, ContinueHeaderDrag, (const ui::LocatedEvent&), (override)); MOCK_METHOD(void, CancelHeaderDrag, (), (override)); MOCK_METHOD(void, HideHoverCard, (), (const, override)); MOCK_METHOD(void, ShiftGroupUp, (), (override));
diff --git a/chrome/browser/ui/views/tabs/vertical/vertical_tab_group_view.cc b/chrome/browser/ui/views/tabs/vertical/vertical_tab_group_view.cc index ac5e2e71..62b65dd 100644 --- a/chrome/browser/ui/views/tabs/vertical/vertical_tab_group_view.cc +++ b/chrome/browser/ui/views/tabs/vertical/vertical_tab_group_view.cc
@@ -114,6 +114,15 @@ OnDataChanged(); } +void VerticalTabGroupView::OnGestureEvent(ui::GestureEvent* event) { + if (event->type() == ui::EventType::kGestureLongTap) { + ui::GestureEvent converted_event(*event, static_cast<views::View*>(this), + static_cast<views::View*>(group_header_)); + group_header_->OnGestureEvent(&converted_event); + event->SetHandled(); + } +} + views::ProposedLayout VerticalTabGroupView::CalculateProposedLayout( const views::SizeBounds& size_bounds) const { views::ProposedLayout layouts; @@ -489,7 +498,7 @@ DragPositionHint::kAfter); } -void VerticalTabGroupView::InitHeaderDrag(const ui::MouseEvent& event) { +void VerticalTabGroupView::InitHeaderDrag(const ui::LocatedEvent& event) { CHECK(collection_node_); const ui::ListSelectionModel original_selection_model = collection_node_->GetController()->GetSelectionModel(); @@ -497,7 +506,7 @@ event); } -bool VerticalTabGroupView::ContinueHeaderDrag(const ui::MouseEvent& event) { +bool VerticalTabGroupView::ContinueHeaderDrag(const ui::LocatedEvent& event) { return GetDragHandler().ContinueDrag(*group_header_, event); }
diff --git a/chrome/browser/ui/views/tabs/vertical/vertical_tab_group_view.h b/chrome/browser/ui/views/tabs/vertical/vertical_tab_group_view.h index 0a131c7..0427ce7 100644 --- a/chrome/browser/ui/views/tabs/vertical/vertical_tab_group_view.h +++ b/chrome/browser/ui/views/tabs/vertical/vertical_tab_group_view.h
@@ -41,6 +41,7 @@ // views::View: void OnThemeChanged() override; + void OnGestureEvent(ui::GestureEvent* event) override; // views::LayoutDelegate: views::ProposedLayout CalculateProposedLayout( @@ -54,8 +55,8 @@ views::Widget* ShowGroupEditorBubble( bool stop_context_menu_propagation) override; std::u16string GetGroupContentString() const override; - void InitHeaderDrag(const ui::MouseEvent& event) override; - bool ContinueHeaderDrag(const ui::MouseEvent& event) override; + void InitHeaderDrag(const ui::LocatedEvent& event) override; + bool ContinueHeaderDrag(const ui::LocatedEvent& event) override; void CancelHeaderDrag() override; void HideHoverCard() const override; void ShiftGroupUp() override;
diff --git a/chrome/browser/ui/views/tabs/vertical/vertical_tab_strip_controller_interactive_uitest.cc b/chrome/browser/ui/views/tabs/vertical/vertical_tab_strip_controller_interactive_uitest.cc index f1b82401..4289ba8 100644 --- a/chrome/browser/ui/views/tabs/vertical/vertical_tab_strip_controller_interactive_uitest.cc +++ b/chrome/browser/ui/views/tabs/vertical/vertical_tab_strip_controller_interactive_uitest.cc
@@ -307,8 +307,7 @@ 1)); } -// TODO(crbug.com/466391046): Tab Group Accelerators are not defined on -// ChromeOS. +// Tab Group Accelerators are not defined on ChromeOS. #if BUILDFLAG(IS_CHROMEOS) #define MAYBE_KeyboardTabGroupCommands DISABLED_KeyboardTabGroupCommands #else
diff --git a/chrome/browser/ui/views/tabs/vertical/vertical_tab_view.cc b/chrome/browser/ui/views/tabs/vertical/vertical_tab_view.cc index a8f2020..934d1222 100644 --- a/chrome/browser/ui/views/tabs/vertical/vertical_tab_view.cc +++ b/chrome/browser/ui/views/tabs/vertical/vertical_tab_view.cc
@@ -57,6 +57,7 @@ #include "ui/base/models/list_selection_model.h" #include "ui/base/theme_provider.h" #include "ui/events/keycodes/keyboard_codes.h" +#include "ui/events/types/event_type.h" #include "ui/gfx/favicon_size.h" #include "ui/gfx/geometry/insets.h" #include "ui/gfx/geometry/rect.h" @@ -468,12 +469,22 @@ CHECK(collection_node_); UpdateHoverCard(nullptr, TabSlotController::HoverCardUpdateType::kEvent); + auto* controller = collection_node_->GetController(); + CHECK(controller); + + const ui::ListSelectionModel original_selection_model = + collection_node_->GetController()->GetSelectionModel(); + switch (event->type()) { case ui::EventType::kGestureTapDown: { - auto* controller = collection_node_->GetController(); - CHECK(controller); - // TAP_DOWN is only dispatched for the first touch point. - CHECK_EQ(1, event->details().touch_points()); + // Handle TapDown to receive subsequent events like LongPress or Tap. + // We don't call InitializeDrag here to allow scrolling. + event->SetHandled(); + break; + } + + case ui::EventType::kGestureTap: { + // Short press release. Select the tab. if (!selected_) { controller->SelectTab(GetTabInterface(), GetGestureDetail(*event)); } @@ -481,6 +492,27 @@ break; } + case ui::EventType::kGestureLongPress: { + // Long press detected. Initialize dragging. + if (!selected_) { + // Ensure the tab is selected before dragging starts to avoid crashes. + controller->SelectTab(GetTabInterface(), GetGestureDetail(*event)); + } + controller->GetDragHandler().InitializeDrag( + *collection_node_, original_selection_model, *event); + event->SetHandled(); + break; + } + + case ui::EventType::kGestureLongTap: { + // Show context menu on release after long press. + controller->ShowContextMenuForNode(collection_node_, this, + event->location(), + ui::mojom::MenuSourceType::kTouch); + event->SetHandled(); + break; + } + default: break; }
diff --git a/chrome/browser/ui/views/toolbar/BUILD.gn b/chrome/browser/ui/views/toolbar/BUILD.gn index 7fd7b782..fdeb0e2 100644 --- a/chrome/browser/ui/views/toolbar/BUILD.gn +++ b/chrome/browser/ui/views/toolbar/BUILD.gn
@@ -21,6 +21,7 @@ "overflow_button.h", "pinned_action_toolbar_button.h", "pinned_action_toolbar_button_menu_model.h", + "pinned_toolbar_actions.h", "pinned_toolbar_actions_container.h", "pinned_toolbar_actions_container_layout.h", "pinned_toolbar_actions_controller.h", @@ -43,6 +44,7 @@ "toolbar_ink_drop_util.h", "toolbar_view.h", "webui_back_forward_control.h", + "webui_pinned_toolbar_actions.h", "webui_reload_control.h", "webui_split_tabs_control.h", "webui_toolbar_web_view.h", @@ -136,6 +138,7 @@ "toolbar_ink_drop_util.cc", "toolbar_view.cc", "webui_back_forward_control.cc", + "webui_pinned_toolbar_actions.cc", "webui_reload_control.cc", "webui_split_tabs_control.cc", "webui_toolbar_web_view.cc", @@ -206,6 +209,7 @@ "//chrome/browser/ui/views/page_action", "//chrome/browser/ui/views/tabs/glic", "//chrome/browser/ui/waap", + "//chrome/browser/ui/waap:manager", "//chrome/browser/ui/waap:window_metrics_manager", "//chrome/browser/ui/web_applications", "//chrome/browser/ui/webui:webui_util", @@ -386,7 +390,7 @@ "//chrome/browser/ui/tabs:tab_menu", "//chrome/browser/ui/tabs:tab_strip", "//chrome/browser/ui/views/frame", - "//chrome/browser/ui/waap", + "//chrome/browser/ui/waap:manager", "//chrome/browser/user_education", "//chrome/test:test_support", "//chrome/test:test_support_ui",
diff --git a/chrome/browser/ui/views/toolbar/chrome_labs/chrome_labs_browsertest.cc b/chrome/browser/ui/views/toolbar/chrome_labs/chrome_labs_browsertest.cc index 95e7781e..f88cb1f6 100644 --- a/chrome/browser/ui/views/toolbar/chrome_labs/chrome_labs_browsertest.cc +++ b/chrome/browser/ui/views/toolbar/chrome_labs/chrome_labs_browsertest.cc
@@ -13,6 +13,7 @@ #include "chrome/browser/ui/toolbar/chrome_labs/chrome_labs_model.h" #include "chrome/browser/ui/toolbar/chrome_labs/chrome_labs_utils.h" #include "chrome/browser/ui/toolbar/pinned_toolbar/pinned_toolbar_actions_model.h" +#include "chrome/browser/ui/ui_features.h" #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/toolbar/chrome_labs/chrome_labs_bubble_view.h" #include "chrome/browser/ui/views/toolbar/chrome_labs/chrome_labs_coordinator.h" @@ -68,10 +69,13 @@ PinnedToolbarActionsModel* const actions_model = PinnedToolbarActionsModel::Get(browser->profile()); actions_model->UpdatePinnedState(kActionShowChromeLabs, true); + CHECK(!features::IsWebUIPinnedToolbarActionsEnabled()) + << "Test needs modification to support WebUIPinnedToolbarActions"; views::test::WaitForAnimatingLayoutManager( - BrowserView::GetBrowserViewForBrowser(browser) - ->toolbar() - ->pinned_toolbar_actions_container()); + static_cast<PinnedToolbarActionsContainer*>( + BrowserView::GetBrowserViewForBrowser(browser) + ->toolbar() + ->pinned_toolbar_actions())); } // Clicks the Chrome Labs button to show the bubble.
diff --git a/chrome/browser/ui/views/toolbar/pinned_toolbar_actions.h b/chrome/browser/ui/views/toolbar/pinned_toolbar_actions.h new file mode 100644 index 0000000..0533f845 --- /dev/null +++ b/chrome/browser/ui/views/toolbar/pinned_toolbar_actions.h
@@ -0,0 +1,33 @@ +// Copyright 2026 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_VIEWS_TOOLBAR_PINNED_TOOLBAR_ACTIONS_H_ +#define CHROME_BROWSER_UI_VIEWS_TOOLBAR_PINNED_TOOLBAR_ACTIONS_H_ + +#include "chrome/browser/ui/views/toolbar/toolbar_controller.h" +#include "ui/actions/action_id.h" +#include "ui/base/interaction/element_identifier.h" +#include "ui/views/bubble/bubble_dialog_delegate_view.h" + +// The PinnedToolbarActions class is a virtual interface, defining access to the +// window's pinned toolbar actions component. This class exists so that +// cross-platform components like the browser command system can talk to the +// platform specific implementations of the pinned toolbar actions control. It +// also allows the pinned toolbar actions to be mocked for testing. +class PinnedToolbarActions : public ToolbarController::PinnedActionsDelegate { + public: + // TODO(https://crbug.com/363743077): This method is almost but not quite + // identical to ShowActionEphemerallyInToolbar(). This doesn't make sense and + // one should be removed. + virtual void UpdateActionState(actions::ActionId id, bool is_active) = 0; + // Updates whether the button is shown ephemerally in the toolbar (in the + // popped out region unless also pinned) regardless of whether it is active. + virtual void ShowActionEphemerallyInToolbar(actions::ActionId id, + bool show) = 0; + virtual bool IsActionPinned(actions::ActionId id) = 0; + virtual bool IsActionPoppedOut(actions::ActionId id) = 0; + virtual bool IsActionPinnedOrPoppedOut(actions::ActionId id) = 0; +}; + +#endif // CHROME_BROWSER_UI_VIEWS_TOOLBAR_PINNED_TOOLBAR_ACTIONS_H_
diff --git a/chrome/browser/ui/views/toolbar/pinned_toolbar_actions_container.h b/chrome/browser/ui/views/toolbar/pinned_toolbar_actions_container.h index cb2c72f7..93eaa84 100644 --- a/chrome/browser/ui/views/toolbar/pinned_toolbar_actions_container.h +++ b/chrome/browser/ui/views/toolbar/pinned_toolbar_actions_container.h
@@ -13,7 +13,7 @@ #include "base/memory/raw_ptr.h" #include "chrome/browser/ui/toolbar/pinned_toolbar/pinned_toolbar_actions_model.h" #include "chrome/browser/ui/views/toolbar/pinned_action_toolbar_button.h" -#include "chrome/browser/ui/views/toolbar/toolbar_controller.h" +#include "chrome/browser/ui/views/toolbar/pinned_toolbar_actions.h" #include "chrome/browser/ui/views/toolbar/toolbar_icon_container_view.h" #include "ui/actions/action_id.h" #include "ui/actions/actions.h" @@ -41,7 +41,7 @@ : public ToolbarIconContainerView, public PinnedToolbarActionsModel::Observer, public views::DragController, - public ToolbarController::PinnedActionsDelegate { + public PinnedToolbarActions { METADATA_HEADER(PinnedToolbarActionsContainer, ToolbarIconContainerView) public: @@ -53,13 +53,6 @@ const PinnedToolbarActionsContainer&) = delete; ~PinnedToolbarActionsContainer() override; - // TODO(https://crbug.com/363743077): This method is almost but not quite - // identical to ShowActionEphemerallyInToolbar(). This doesn't make sense and - // one should be removed. - void UpdateActionState(actions::ActionId id, bool is_active); - // Updates whether the button is shown ephemerally in the toolbar (in the - // popped out region unless also pinned) regardless of whether it is active. - void ShowActionEphemerallyInToolbar(actions::ActionId id, bool show); void UpdatePinnedStateAndAnnounce(actions::ActionId id, bool pin); void MovePinnedActionBy(actions::ActionId action_id, int delta); @@ -99,9 +92,12 @@ views::View* GetContainerView() override; bool ShouldAnyButtonsOverflow(gfx::Size available_size) const override; - bool IsActionPinned(actions::ActionId id); - bool IsActionPoppedOut(actions::ActionId id); - bool IsActionPinnedOrPoppedOut(actions::ActionId id); + // PinnedToolbarActions: + void UpdateActionState(actions::ActionId id, bool is_active) override; + void ShowActionEphemerallyInToolbar(actions::ActionId id, bool show) override; + bool IsActionPinned(actions::ActionId id) override; + bool IsActionPoppedOut(actions::ActionId id) override; + bool IsActionPinnedOrPoppedOut(actions::ActionId id) override; // Returns the button associated with `id`. This does not return permanent // buttons which are currently invisible, an accessor for these can be
diff --git a/chrome/browser/ui/views/toolbar/pinned_toolbar_actions_container_browsertest.cc b/chrome/browser/ui/views/toolbar/pinned_toolbar_actions_container_browsertest.cc index 54448d91..3f6a5b6 100644 --- a/chrome/browser/ui/views/toolbar/pinned_toolbar_actions_container_browsertest.cc +++ b/chrome/browser/ui/views/toolbar/pinned_toolbar_actions_container_browsertest.cc
@@ -17,6 +17,7 @@ #include "chrome/browser/ui/side_panel/side_panel_ui.h" #include "chrome/browser/ui/tabs/tab_strip_prefs.h" #include "chrome/browser/ui/toolbar/pinned_toolbar/pinned_toolbar_actions_model.h" +#include "chrome/browser/ui/ui_features.h" #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/side_panel/side_panel_coordinator.h" #include "chrome/browser/ui/views/toolbar/pinned_action_toolbar_button.h" @@ -71,7 +72,10 @@ } PinnedToolbarActionsContainer* container() { - return browser_view()->toolbar()->pinned_toolbar_actions_container(); + CHECK(!features::IsWebUIPinnedToolbarActionsEnabled()) + << "Test needs modification to support WebUIPinnedToolbarActions"; + return static_cast<PinnedToolbarActionsContainer*>( + browser_view()->toolbar()->pinned_toolbar_actions()); } void TranslatePage(content::WebContents* web_contents) {
diff --git a/chrome/browser/ui/views/toolbar/pinned_toolbar_actions_container_unittest.cc b/chrome/browser/ui/views/toolbar/pinned_toolbar_actions_container_unittest.cc index 007b0641..11386029 100644 --- a/chrome/browser/ui/views/toolbar/pinned_toolbar_actions_container_unittest.cc +++ b/chrome/browser/ui/views/toolbar/pinned_toolbar_actions_container_unittest.cc
@@ -17,6 +17,7 @@ #include "chrome/browser/ui/toolbar/pinned_toolbar/pinned_toolbar_actions_model.h" #include "chrome/browser/ui/toolbar/pinned_toolbar/pinned_toolbar_actions_model_factory.h" #include "chrome/browser/ui/toolbar/toolbar_pref_names.h" +#include "chrome/browser/ui/ui_features.h" #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/frame/test_with_browser_view.h" #include "chrome/browser/ui/views/toolbar/pinned_action_toolbar_button.h" @@ -104,38 +105,34 @@ } void CheckIsPoppedOut(actions::ActionId id, bool should_be_popped_out) { - auto* container = - browser_view()->toolbar()->pinned_toolbar_actions_container(); if (should_be_popped_out) { - ASSERT_NE(std::ranges::find(container->popped_out_buttons_, id, + ASSERT_NE(std::ranges::find(container()->popped_out_buttons_, id, [](PinnedActionToolbarButton* button) { return button->GetActionId(); }), - container->popped_out_buttons_.end()); + container()->popped_out_buttons_.end()); } else { - ASSERT_EQ(std::ranges::find(container->popped_out_buttons_, id, + ASSERT_EQ(std::ranges::find(container()->popped_out_buttons_, id, [](PinnedActionToolbarButton* button) { return button->GetActionId(); }), - container->popped_out_buttons_.end()); + container()->popped_out_buttons_.end()); } } void CheckIsPinned(actions::ActionId id, bool should_be_pinned) { - auto* container = - browser_view()->toolbar()->pinned_toolbar_actions_container(); if (should_be_pinned) { - ASSERT_NE(std::ranges::find(container->pinned_buttons_, id, + ASSERT_NE(std::ranges::find(container()->pinned_buttons_, id, [](PinnedActionToolbarButton* button) { return button->GetActionId(); }), - container->pinned_buttons_.end()); + container()->pinned_buttons_.end()); } else { - ASSERT_EQ(std::ranges::find(container->pinned_buttons_, id, + ASSERT_EQ(std::ranges::find(container()->pinned_buttons_, id, [](PinnedActionToolbarButton* button) { return button->GetActionId(); }), - container->pinned_buttons_.end()); + container()->pinned_buttons_.end()); } } @@ -177,7 +174,10 @@ } PinnedToolbarActionsContainer* container() { - return browser_view()->toolbar()->pinned_toolbar_actions_container(); + CHECK(!features::IsWebUIPinnedToolbarActionsEnabled()) + << "Test needs modification to support WebUIPinnedToolbarActions"; + return static_cast<PinnedToolbarActionsContainer*>( + browser_view()->toolbar()->pinned_toolbar_actions()); } PinnedToolbarActionsModel* model() { return model_.get(); }
diff --git a/chrome/browser/ui/views/toolbar/toolbar_controller_interactive_uitest.cc b/chrome/browser/ui/views/toolbar/toolbar_controller_interactive_uitest.cc index 1990e8a..b1792b3e 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_controller_interactive_uitest.cc +++ b/chrome/browser/ui/views/toolbar/toolbar_controller_interactive_uitest.cc
@@ -19,6 +19,7 @@ #include "chrome/browser/ui/tabs/tab_strip_prefs.h" #include "chrome/browser/ui/toolbar/pinned_toolbar/pinned_toolbar_actions_model.h" #include "chrome/browser/ui/toolbar_controller_util.h" +#include "chrome/browser/ui/ui_features.h" #include "chrome/browser/ui/views/extensions/extensions_toolbar_desktop.h" #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/frame/layout/browser_view_layout.h" @@ -73,8 +74,11 @@ tabs::TabSearchPosition::kToolbarButton) { actions_model->UpdatePinnedState(kActionTabSearch, false); } + CHECK(!features::IsWebUIPinnedToolbarActionsEnabled()) + << "Test needs modification to support WebUIPinnedToolbarActions"; views::test::WaitForAnimatingLayoutManager( - browser_view_->toolbar()->pinned_toolbar_actions_container()); + static_cast<PinnedToolbarActionsContainer*>( + browser_view_->toolbar()->pinned_toolbar_actions())); toolbar_controller_ = const_cast<ToolbarController*>( browser_view_->toolbar()->toolbar_controller()); toolbar_container_view_ = const_cast<views::View*>(
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.cc b/chrome/browser/ui/views/toolbar/toolbar_view.cc index 9025b75..9cabbb7 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_view.cc +++ b/chrome/browser/ui/views/toolbar/toolbar_view.cc
@@ -18,6 +18,7 @@ #include "base/metrics/histogram_macros.h" #include "base/metrics/user_metrics.h" #include "base/metrics/user_metrics_action.h" +#include "base/notimplemented.h" #include "base/strings/utf_string_conversions.h" #include "base/trace_event/trace_event.h" #include "build/build_config.h" @@ -551,13 +552,22 @@ toolbar_divider_ = AddChildView(std::move(toolbar_divider)); } - pinned_toolbar_actions_container_ = AddChildView( - std::make_unique<PinnedToolbarActionsContainer>(browser_view_, this)); + if (!features::IsWebUIPinnedToolbarActionsEnabled()) { + pinned_toolbar_actions_container_ = AddChildView( + std::make_unique<PinnedToolbarActionsContainer>(browser_view_, this)); + pinned_toolbar_actions_ = pinned_toolbar_actions_container_; + } else { + pinned_toolbar_actions_ = toolbar_webview_->GetPinnedToolbarActions(); + } if (!base::FeatureList::IsEnabled(tabs::kHorizontalTabStripComboButton) && features::HasTabSearchToolbarButton()) { + CHECK(!features::IsWebUIPinnedToolbarActionsEnabled()) + << "WebUIPinnedToolbarActions does not support " + "CreatePermanentButtonFor, consider enabling " + "HorizontalTabStripComboButton"; tab_search_button_ = - pinned_toolbar_actions_container()->CreatePermanentButtonFor( + pinned_toolbar_actions_container_->CreatePermanentButtonFor( kActionTabSearch); tab_search_button_->SetProperty(views::kElementIdentifierKey, kTabSearchButtonElementId); @@ -573,6 +583,8 @@ chrome_labs_prefs::kBrowserLabsEnabledEnterprisePolicy, prefs, base::BindRepeating(&ToolbarView::OnChromeLabsPrefChanged, base::Unretained(this))); + CHECK(!features::IsWebUIPinnedToolbarActionsEnabled()) + << "WebUIPinnedToolbarActions does not support ChromeLabs."; // Set the visibility for the button based on initial enterprise policy // value. Only call OnChromeLabsPrefChanged if there is a change from // the initial value. @@ -607,11 +619,6 @@ if (action_item) { action_item->SetVisible(true); action_item->SetEnabled(true); - ai_overlay_dialog_button_ = - pinned_toolbar_actions_container()->CreatePermanentButtonFor( - kActionShowAiOverlayDialog); - ai_overlay_dialog_button_->SetProperty(views::kCrossAxisAlignmentKey, - views::LayoutAlignment::kCenter); PinnedToolbarActionsModel::Get(browser_->profile()) ->UpdatePinnedState(kActionShowAiOverlayDialog, true); } @@ -900,6 +907,15 @@ } } +void ToolbarView::OnTriggerAnchoredMessage( + std::string label, + std::string anchored_message_text, + std::optional<std::string> prompt_suggestion) { + // ToolbarView does not support the page action framework path used by + // TabStripActionContainer. Fall back to the chip nudge. + OnTriggerGlicNudgeUI(std::move(label)); +} + void ToolbarView::OnHideGlicNudgeUI() { if (glic_button_) { HideToolbarNudge(glic_button_); @@ -1289,8 +1305,11 @@ } ToolbarButton* ToolbarView::GetCastButton() const { - return pinned_toolbar_actions_container() - ? pinned_toolbar_actions_container()->GetButtonFor( + if (features::IsWebUIPinnedToolbarActionsEnabled()) { + NOTIMPLEMENTED(); + } + return pinned_toolbar_actions_container_ + ? pinned_toolbar_actions_container_->GetButtonFor( kActionRouteMedia) : nullptr; } @@ -1567,7 +1586,7 @@ toolbar_controller_ = std::make_unique<ToolbarController>( ToolbarController::GetDefaultResponsiveElements(browser_), ToolbarController::GetDefaultOverflowOrder(), kToolbarFlexOrderStart, - this, overflow_button_, pinned_toolbar_actions_container_, + this, overflow_button_, pinned_toolbar_actions_, PinnedToolbarActionsModel::Get(browser_view_->GetProfile())); overflow_button_->set_toolbar_controller(toolbar_controller_.get()); @@ -1795,7 +1814,7 @@ } IntentChipButton* ToolbarView::GetIntentChipButton() { - return location_bar_view()->intent_chip(); + return location_bar_view() ? location_bar_view()->intent_chip() : nullptr; } ToolbarButton* ToolbarView::GetDownloadButton() {
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.h b/chrome/browser/ui/views/toolbar/toolbar_view.h index f8b4dd5..509c36fa 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_view.h +++ b/chrome/browser/ui/views/toolbar/toolbar_view.h
@@ -26,6 +26,7 @@ #include "chrome/browser/ui/views/profiles/avatar_toolbar_button.h" #include "chrome/browser/ui/views/toolbar/overflow_button.h" #include "chrome/browser/ui/views/toolbar/pinned_action_toolbar_button.h" +#include "chrome/browser/ui/views/toolbar/pinned_toolbar_actions.h" #include "chrome/browser/ui/views/toolbar/split_tabs_button.h" #include "components/prefs/pref_member.h" #include "ui/base/accelerators/accelerator.h" @@ -182,8 +183,8 @@ return performance_intervention_button_; } ToolbarButton* GetCastButton() const; - PinnedToolbarActionsContainer* pinned_toolbar_actions_container() const { - return pinned_toolbar_actions_container_; + PinnedToolbarActions* pinned_toolbar_actions() const { + return pinned_toolbar_actions_; } MediaToolbarButtonView* media_button() const { return media_button_; } BrowserAppMenuButton* app_menu_button() const { return app_menu_button_; } @@ -233,6 +234,11 @@ // Called when the glic nudge UI needs to be triggered. `label' holds the // nudge label. void OnTriggerGlicNudgeUI(std::string label) override; + // Show an anchored message bubble via the page action framework. + void OnTriggerAnchoredMessage( + std::string label, + std::string anchored_message_text, + std::optional<std::string> prompt_suggestion) override; // Called when the glic nudge UI needs to be hidden. void OnHideGlicNudgeUI() override; // Called when we want to check if the UI is currently showing. @@ -381,6 +387,10 @@ nullptr; raw_ptr<PinnedToolbarActionsContainer> pinned_toolbar_actions_container_ = nullptr; + + // An alias for `pinned_toolbar_actions_container_` or + // `toolbar_webview_->GetPinnedActionsContainer()`. + raw_ptr<PinnedToolbarActions> pinned_toolbar_actions_ = nullptr; raw_ptr<AvatarToolbarButton> avatar_ = nullptr; raw_ptr<MediaToolbarButtonView> media_button_ = nullptr; raw_ptr<BrowserAppMenuButton> app_menu_button_ = nullptr;
diff --git a/chrome/browser/ui/views/toolbar/webui_pinned_toolbar_actions.cc b/chrome/browser/ui/views/toolbar/webui_pinned_toolbar_actions.cc new file mode 100644 index 0000000..fe133751 --- /dev/null +++ b/chrome/browser/ui/views/toolbar/webui_pinned_toolbar_actions.cc
@@ -0,0 +1,69 @@ +// Copyright 2026 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/views/toolbar/webui_pinned_toolbar_actions.h" + +#include "base/notimplemented.h" +#include "chrome/browser/ui/browser_actions.h" +#include "chrome/browser/ui/browser_window/public/browser_window_interface.h" +#include "chrome/browser/ui/views/toolbar/webui_toolbar_web_view.h" + +WebUIPinnedToolbarActions::WebUIPinnedToolbarActions( + WebUIToolbarWebView* webui_toolbar_web_view) + : webui_toolbar_web_view_(webui_toolbar_web_view), + model_(PinnedToolbarActionsModel::Get( + webui_toolbar_web_view->browser_->GetProfile())) {} + +const std::vector<actions::ActionId>& +WebUIPinnedToolbarActions::PinnedActionIds() const { + return model_->PinnedActionIds(); +} + +actions::ActionItem* WebUIPinnedToolbarActions::GetActionItemFor( + actions::ActionId id) { + return actions::ActionManager::Get().FindAction( + id, webui_toolbar_web_view_->browser_->GetActions()->root_action_item()); +} + +bool WebUIPinnedToolbarActions::IsOverflowed(actions::ActionId id) { + NOTIMPLEMENTED(); + return false; +} + +views::View* WebUIPinnedToolbarActions::GetContainerView() { + NOTIMPLEMENTED(); + return nullptr; +} + +bool WebUIPinnedToolbarActions::ShouldAnyButtonsOverflow( + gfx::Size available_size) const { + NOTIMPLEMENTED(); + return false; +} + +void WebUIPinnedToolbarActions::UpdateActionState(actions::ActionId id, + bool is_active) { + NOTIMPLEMENTED(); +} + +void WebUIPinnedToolbarActions::ShowActionEphemerallyInToolbar( + actions::ActionId id, + bool show) { + NOTIMPLEMENTED(); +} + +bool WebUIPinnedToolbarActions::IsActionPinned(actions::ActionId id) { + NOTIMPLEMENTED(); + return false; +} + +bool WebUIPinnedToolbarActions::IsActionPoppedOut(actions::ActionId id) { + NOTIMPLEMENTED(); + return false; +} + +bool WebUIPinnedToolbarActions::IsActionPinnedOrPoppedOut( + actions::ActionId id) { + return IsActionPinned(id) || IsActionPoppedOut(id); +}
diff --git a/chrome/browser/ui/views/toolbar/webui_pinned_toolbar_actions.h b/chrome/browser/ui/views/toolbar/webui_pinned_toolbar_actions.h new file mode 100644 index 0000000..60d4b9d4 --- /dev/null +++ b/chrome/browser/ui/views/toolbar/webui_pinned_toolbar_actions.h
@@ -0,0 +1,43 @@ +// Copyright 2026 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_VIEWS_TOOLBAR_WEBUI_PINNED_TOOLBAR_ACTIONS_H_ +#define CHROME_BROWSER_UI_VIEWS_TOOLBAR_WEBUI_PINNED_TOOLBAR_ACTIONS_H_ + +#include "chrome/browser/ui/views/toolbar/pinned_toolbar_actions.h" + +class WebUIToolbarWebView; +class PinnedToolbarActionsModel; + +// The C++ side of a WebUI implementation of pinned toolbar actions. +class WebUIPinnedToolbarActions : public PinnedToolbarActions { + public: + explicit WebUIPinnedToolbarActions( + WebUIToolbarWebView* webui_toolbar_web_view); + WebUIPinnedToolbarActions(const WebUIPinnedToolbarActions&) = delete; + WebUIPinnedToolbarActions& operator=(const WebUIPinnedToolbarActions&) = + delete; + + // ToolbarController::PinnedActionsDelegate: + const std::vector<actions::ActionId>& PinnedActionIds() const override; + actions::ActionItem* GetActionItemFor(actions::ActionId id) override; + bool IsOverflowed(actions::ActionId id) override; + views::View* GetContainerView() override; + bool ShouldAnyButtonsOverflow(gfx::Size available_size) const override; + + // PinnedToolbarActions: + void UpdateActionState(actions::ActionId id, bool is_active) override; + void ShowActionEphemerallyInToolbar(actions::ActionId id, bool show) override; + bool IsActionPinned(actions::ActionId id) override; + bool IsActionPoppedOut(actions::ActionId id) override; + bool IsActionPinnedOrPoppedOut(actions::ActionId id) override; + + private: + // Parent toolbar. + const raw_ptr<WebUIToolbarWebView> webui_toolbar_web_view_; + // The model whose state we use to populate this view. + raw_ptr<PinnedToolbarActionsModel> model_; +}; + +#endif // CHROME_BROWSER_UI_VIEWS_TOOLBAR_WEBUI_PINNED_TOOLBAR_ACTIONS_H_
diff --git a/chrome/browser/ui/views/toolbar/webui_toolbar_web_view.cc b/chrome/browser/ui/views/toolbar/webui_toolbar_web_view.cc index e37ff4f..d88e476 100644 --- a/chrome/browser/ui/views/toolbar/webui_toolbar_web_view.cc +++ b/chrome/browser/ui/views/toolbar/webui_toolbar_web_view.cc
@@ -149,6 +149,7 @@ location_bar_(std::move(location_bar)), back_control_(this, BackForwardButton::Direction::kBack), forward_control_(this, BackForwardButton::Direction::kForward), + pinned_toolbar_actions_(this), clock_(base::DefaultTickClock::GetInstance()), touch_ui_subscription_(ui::TouchUiController::Get()->RegisterCallback( base::BindRepeating(&WebUIToolbarWebView::OnTouchUiChanged,
diff --git a/chrome/browser/ui/views/toolbar/webui_toolbar_web_view.h b/chrome/browser/ui/views/toolbar/webui_toolbar_web_view.h index 2833a1b..83a8a1fb 100644 --- a/chrome/browser/ui/views/toolbar/webui_toolbar_web_view.h +++ b/chrome/browser/ui/views/toolbar/webui_toolbar_web_view.h
@@ -9,7 +9,9 @@ #include "base/memory/weak_ptr.h" #include "base/time/time.h" #include "chrome/browser/ui/browser_command_controller.h" +#include "chrome/browser/ui/views/toolbar/pinned_toolbar_actions.h" #include "chrome/browser/ui/views/toolbar/webui_back_forward_control.h" +#include "chrome/browser/ui/views/toolbar/webui_pinned_toolbar_actions.h" #include "chrome/browser/ui/views/toolbar/webui_reload_control.h" #include "chrome/browser/ui/views/toolbar/webui_split_tabs_control.h" #include "chrome/browser/ui/webui/webui_toolbar/adapters/navigation_controls_state_fetcher.h" @@ -53,6 +55,9 @@ ~WebUIToolbarWebView() override; ReloadControl* GetReloadControl(); + PinnedToolbarActions* GetPinnedToolbarActions() { + return &pinned_toolbar_actions_; + } void SetBackButtonLeadingMargin(int margin); void SetBackForwardEnabled(int command_id, bool enabled); @@ -109,6 +114,7 @@ friend WebUIReloadControl; friend WebUISplitTabsControl; friend WebUIBackForwardControl; + friend WebUIPinnedToolbarActions; toolbar_ui_api::mojom::NavigationControlsStatePtr GetNavigationControlsState(); @@ -158,6 +164,7 @@ std::unique_ptr<WebUILocationBar> location_bar_; WebUIBackForwardControl back_control_; WebUIBackForwardControl forward_control_; + WebUIPinnedToolbarActions pinned_toolbar_actions_; raw_ptr<const base::TickClock> clock_; base::OnceClosure did_first_non_empty_paint_callback_; bool has_finished_first_non_empty_paint_ = false;
diff --git a/chrome/browser/ui/views/toolbar/webui_toolbar_web_view_browsertest.cc b/chrome/browser/ui/views/toolbar/webui_toolbar_web_view_browsertest.cc index 48aa170..2ddc8ef 100644 --- a/chrome/browser/ui/views/toolbar/webui_toolbar_web_view_browsertest.cc +++ b/chrome/browser/ui/views/toolbar/webui_toolbar_web_view_browsertest.cc
@@ -27,6 +27,7 @@ #include "chrome/browser/ui/browser_window/public/desktop_browser_window_capabilities.h" #include "chrome/browser/ui/interaction/browser_elements.h" #include "chrome/browser/ui/layout_constants.h" +#include "chrome/browser/ui/tabs/features.h" #include "chrome/browser/ui/tabs/split_tab_metrics.h" #include "chrome/browser/ui/ui_features.h" #include "chrome/browser/ui/views/frame/browser_view.h" @@ -207,6 +208,8 @@ feature_list_.InitWithFeatures( {features::kInitialWebUI, features::kWebUIReloadButton, features::kWebUISplitTabsButton, features::kWebUIBackForwardButton, + features::kWebUIPinnedToolbarActions, + tabs::kHorizontalTabStripComboButton, features::kSkipIPCChannelPausingForNonGuests, features::kWebUIInProcessResourceLoadingV2, features::kInitialWebUISyncNavStartToCommit}, @@ -481,8 +484,9 @@ })); } +// TODO(crbug.com/493362471): Flaky pixel tests. IN_PROC_BROWSER_TEST_F(WebUIToolbarWebViewPixelBrowserTest, - CheckSplitTabsButtonColor) { + DISABLED_CheckSplitTabsButtonColor) { browser()->profile()->GetPrefs()->SetBoolean(prefs::kPinSplitTabButton, true); ui::TrackedElement* element = nullptr;
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 83faecee..31c5057 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
@@ -1037,8 +1037,8 @@ registry.RegisterFeature(std::move( FeaturePromoSpecification::CreateForToastPromo( feature_engagement::kIPHResumptionRailFeature, - kVerticalTabStripProjectsButtonElementId, - IDS_RESUMPTION_RAIL_IPH_BODY, IDS_RESUMPTION_RAIL_IPH_TITLE, + kVerticalTabStripProjectsButtonElementId, IDS_WILDCARD, + IDS_RESUMPTION_RAIL_IPH_TITLE, FeaturePromoSpecification::AcceleratorInfo()) .SetBubbleTitleText(IDS_RESUMPTION_RAIL_IPH_TITLE) .SetBubbleArrow(HelpBubbleArrow::kTopLeft)
diff --git a/chrome/browser/ui/views/user_education/impl/browser_user_education_interface_impl.cc b/chrome/browser/ui/views/user_education/impl/browser_user_education_interface_impl.cc index cd80b6b..7f85117 100644 --- a/chrome/browser/ui/views/user_education/impl/browser_user_education_interface_impl.cc +++ b/chrome/browser/ui/views/user_education/impl/browser_user_education_interface_impl.cc
@@ -155,7 +155,7 @@ return result && result->is_dismissed; } -void BrowserUserEducationInterfaceImpl::MaybeShowFeaturePromo( +bool BrowserUserEducationInterfaceImpl::MaybeShowFeaturePromo( user_education::FeaturePromoParams params) { // Trying to show a promo before the browser is initialized can result in a // failure to retrieve accelerators, which can cause issues for screen reader @@ -179,24 +179,27 @@ << state_desc << "; IPH will not be shown."; PostShowPromoFailure(std::move(params), user_education::FeaturePromoResult::kError); - return; + return false; } if (auto* const controller = GetFeaturePromoController()) { + const auto& feature = *params.feature; controller->MaybeShowPromo(std::move(params), user_education_context_); - return; + return controller->IsPromoActive( + feature, user_education::FeaturePromoStatus::kQueued); } PostShowPromoFailure(std::move(params), user_education::FeaturePromoResult::kBlockedByContext); + return false; } -void BrowserUserEducationInterfaceImpl::MaybeShowStartupFeaturePromo( +bool BrowserUserEducationInterfaceImpl::MaybeShowStartupFeaturePromo( user_education::FeaturePromoParams params) { if (state_ == State::kUninitialized || state_ == State::kInitializationPending) { queued_params_.push_back(std::move(params)); - return; + return true; } if (state_ == State::kTornDown) { @@ -204,10 +207,10 @@ << " after browser shutdown; IPH will not be shown."; PostShowPromoFailure(std::move(params), user_education::FeaturePromoResult::kError); - return; + return false; } - MaybeShowStartupFeaturePromoImpl(std::move(params)); + return MaybeShowStartupFeaturePromoImpl(std::move(params)); } bool BrowserUserEducationInterfaceImpl::AbortFeaturePromo( @@ -286,14 +289,17 @@ return user_education_context_; } -void BrowserUserEducationInterfaceImpl::MaybeShowStartupFeaturePromoImpl( +bool BrowserUserEducationInterfaceImpl::MaybeShowStartupFeaturePromoImpl( user_education::FeaturePromoParams params) { if (auto* const controller = GetFeaturePromoController()) { + const auto& feature = *params.feature; controller->MaybeShowStartupPromo(std::move(params), user_education_context_); - return; + return controller->IsPromoActive( + feature, user_education::FeaturePromoStatus::kQueued); } PostShowPromoFailure(std::move(params), user_education::FeaturePromoResult::kBlockedByContext); + return false; }
diff --git a/chrome/browser/ui/views/user_education/impl/browser_user_education_interface_impl.h b/chrome/browser/ui/views/user_education/impl/browser_user_education_interface_impl.h index 501da2712..4fdf72f 100644 --- a/chrome/browser/ui/views/user_education/impl/browser_user_education_interface_impl.h +++ b/chrome/browser/ui/views/user_education/impl/browser_user_education_interface_impl.h
@@ -35,9 +35,9 @@ const base::Feature& iph_feature) const override; bool HasFeaturePromoBeenDismissed( const base::Feature& iph_feature) const override; - void MaybeShowFeaturePromo( + bool MaybeShowFeaturePromo( user_education::FeaturePromoParams params) override; - void MaybeShowStartupFeaturePromo( + bool MaybeShowStartupFeaturePromo( user_education::FeaturePromoParams params) override; bool AbortFeaturePromo(const base::Feature& iph_feature) override; user_education::FeaturePromoHandle CloseFeaturePromoAndContinue( @@ -73,7 +73,7 @@ user_education::FeaturePromoResult::Failure::kError); // Implementation for showing a startup promo. - void MaybeShowStartupFeaturePromoImpl( + bool MaybeShowStartupFeaturePromoImpl( user_education::FeaturePromoParams params); enum class State {
diff --git a/chrome/browser/ui/views/web_apps/BUILD.gn b/chrome/browser/ui/views/web_apps/BUILD.gn index 814cbef..16b387c8 100644 --- a/chrome/browser/ui/views/web_apps/BUILD.gn +++ b/chrome/browser/ui/views/web_apps/BUILD.gn
@@ -11,6 +11,7 @@ "sub_apps_install_dialog_controller_browsertest.cc", "web_app_blocked_migration_infobar_delegate_browsertest.cc", "web_app_identity_update_confirmation_view_browsertest.cc", + "web_app_install_flow_browsertest.cc", "web_app_update_review_dialog_browsertest.cc", ] deps = [
diff --git a/chrome/browser/ui/views/web_apps/web_app_install_flow_browsertest.cc b/chrome/browser/ui/views/web_apps/web_app_install_flow_browsertest.cc new file mode 100644 index 0000000..0d82f46 --- /dev/null +++ b/chrome/browser/ui/views/web_apps/web_app_install_flow_browsertest.cc
@@ -0,0 +1,157 @@ +// Copyright 2026 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/scoped_observation.h" +#include "base/test/run_until.h" +#include "base/test/scoped_feature_list.h" +#include "chrome/app/chrome_command_ids.h" +#include "chrome/browser/ui/actions/chrome_action_id.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_commands.h" +#include "chrome/browser/ui/views/frame/browser_view.h" +#include "chrome/browser/ui/views/frame/toolbar_button_provider.h" +#include "chrome/browser/ui/views/location_bar/icon_label_bubble_view.h" +#include "chrome/browser/ui/views/page_action/page_action_icon_view.h" +#include "chrome/browser/ui/views/web_apps/web_app_install_dialog_delegate.h" +#include "chrome/browser/ui/views/web_apps/web_app_install_flow_dialog_delegate.h" +#include "chrome/browser/ui/web_applications/web_app_browsertest_base.h" +#include "chrome/browser/ui/web_applications/web_app_dialog_utils.h" +#include "chrome/browser/web_applications/test/web_app_install_test_utils.h" +#include "chrome/browser/web_applications/test/web_app_test_observers.h" +#include "chrome/common/chrome_features.h" +#include "chrome/test/base/ui_test_utils.h" +#include "content/public/test/browser_test.h" +#include "ui/events/event.h" +#include "ui/events/event_constants.h" +#include "ui/views/controls/button/button.h" +#include "ui/views/interaction/element_tracker_views.h" +#include "ui/views/test/button_test_api.h" +#include "ui/views/test/dialog_test.h" +#include "ui/views/test/widget_test.h" +#include "ui/views/view_observer.h" +#include "ui/views/widget/any_widget_observer.h" +#include "ui/views/widget/widget.h" +#include "ui/views/window/dialog_delegate.h" + +namespace web_app { + +class WebAppInstallFlowBrowserTest : public WebAppBrowserTestBase { + public: + WebAppInstallFlowBrowserTest() { + feature_list_.InitAndEnableFeature(features::kWebAppInstallDialog); + } + + void AdvanceToDoneAndAccept(views::Widget* widget) { + ASSERT_TRUE(widget); + auto* dialog_delegate = widget->widget_delegate()->AsDialogDelegate(); + ASSERT_TRUE(dialog_delegate); + + views::test::WidgetDestroyedWaiter waiter(widget); + while (!widget->IsClosed()) { + dialog_delegate->AcceptDialog(); + } + waiter.Wait(); + } + + IconLabelBubbleView* GetPwaInstallIconView() { + BrowserView* browser_view = + BrowserView::GetBrowserViewForBrowser(browser()); + if (!browser_view || !browser_view->toolbar_button_provider()) { + return nullptr; + } + return browser_view->toolbar_button_provider()->GetPageActionView( + kActionInstallPwa); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +IN_PROC_BROWSER_TEST_F(WebAppInstallFlowBrowserTest, SimpleInstallFlow) { + const GURL app_url = + https_server()->GetURL("/banners/manifest_test_page.html"); + ASSERT_TRUE(NavigateAndAwaitInstallabilityCheck(browser(), app_url)); + + // Wait for the omnibox icon to become visible. + ASSERT_TRUE(base::test::RunUntil([&]() { + auto* icon = GetPwaInstallIconView(); + return icon && icon->GetVisible(); + })); + + views::NamedWidgetShownWaiter waiter(views::test::AnyWidgetTestPasskey{}, + "WebAppInstallFlowDialog"); + + web_app::WebAppTestInstallObserver install_observer(profile()); + install_observer.BeginListening(); + + chrome::ExecuteCommand(browser(), IDC_INSTALL_PWA); + + views::Widget* widget = waiter.WaitIfNeededAndGet(); + ASSERT_NE(widget, nullptr); + + AdvanceToDoneAndAccept(widget); + + const webapps::AppId app_id = install_observer.Wait(); + EXPECT_EQ(FindAppWithUrlInScope(app_url), app_id); +} + +IN_PROC_BROWSER_TEST_F(WebAppInstallFlowBrowserTest, DetailedInstallFlow) { + // Detailed install flow is triggered when screenshots are available. + GURL app_url = https_server()->GetURL( + "/banners/" + "manifest_test_page.html?manifest=manifest_with_screenshots.json"); + ASSERT_TRUE(NavigateAndAwaitInstallabilityCheck(browser(), app_url)); + + ASSERT_TRUE(base::test::RunUntil([&]() { + auto* icon = GetPwaInstallIconView(); + return icon && icon->GetVisible(); + })); + + views::NamedWidgetShownWaiter waiter(views::test::AnyWidgetTestPasskey{}, + "WebAppInstallFlowDialog"); + + web_app::WebAppTestInstallObserver install_observer(profile()); + install_observer.BeginListening(); + + chrome::ExecuteCommand(browser(), IDC_INSTALL_PWA); + + views::Widget* widget = waiter.WaitIfNeededAndGet(); + ASSERT_NE(widget, nullptr); + + AdvanceToDoneAndAccept(widget); + + const webapps::AppId app_id = install_observer.Wait(); + EXPECT_EQ(FindAppWithUrlInScope(app_url), app_id); +} + +IN_PROC_BROWSER_TEST_F(WebAppInstallFlowBrowserTest, DiyInstallFlow) { + GURL app_url = + https_server()->GetURL("/banners/manifest_no_service_worker.html"); + // Navigate to a non-promotable page (has manifest but no service worker). + ASSERT_TRUE(NavigateAndAwaitInstallabilityCheck(browser(), app_url)); + + ASSERT_TRUE(base::test::RunUntil([&]() { + auto* icon = GetPwaInstallIconView(); + return icon && icon->GetVisible(); + })); + + views::NamedWidgetShownWaiter waiter(views::test::AnyWidgetTestPasskey{}, + "WebAppInstallFlowDialog"); + + web_app::WebAppTestInstallObserver install_observer(profile()); + install_observer.BeginListening(); + + // Show the dialog. + chrome::ExecuteCommand(browser(), IDC_INSTALL_PWA); + + views::Widget* widget = waiter.WaitIfNeededAndGet(); + ASSERT_NE(widget, nullptr); + + AdvanceToDoneAndAccept(widget); + + const webapps::AppId app_id = install_observer.Wait(); + EXPECT_EQ(FindAppWithUrlInScope(app_url), app_id); +} + +} // namespace web_app
diff --git a/chrome/browser/ui/waap/BUILD.gn b/chrome/browser/ui/waap/BUILD.gn index c28f5a8a..fe9107c 100644 --- a/chrome/browser/ui/waap/BUILD.gn +++ b/chrome/browser/ui/waap/BUILD.gn
@@ -6,8 +6,6 @@ static_library("waap") { sources = [ - "initial_web_ui_manager.cc", - "initial_web_ui_manager.h", "waap_ui_metrics_recorder.cc", "waap_ui_metrics_recorder.h", "waap_ui_metrics_service.cc", @@ -31,6 +29,24 @@ ] } +source_set("manager") { + public = [ + "initial_web_ui_manager.h", + ] + sources = [ + "initial_web_ui_manager.cc", + ] + deps = [ + ":window_metrics_manager", + "//base", + "//chrome/browser/ui:ui_features", + "//chrome/common:chrome_features", + "//chrome/browser/ui/browser_window", + "//ui/base/unowned_user_data", + "//ui/views", + ] +} + source_set("window_metrics_manager") { sources = [ "initial_webui_window_metrics_manager.cc",
diff --git a/chrome/browser/ui/waap/initial_web_ui_manager.cc b/chrome/browser/ui/waap/initial_web_ui_manager.cc index fa38d18..2ea13e4 100644 --- a/chrome/browser/ui/waap/initial_web_ui_manager.cc +++ b/chrome/browser/ui/waap/initial_web_ui_manager.cc
@@ -6,6 +6,7 @@ #include "chrome/browser/ui/browser_window/public/browser_window_interface.h" #include "chrome/browser/ui/ui_features.h" +#include "chrome/browser/ui/waap/initial_webui_window_metrics_manager.h" #include "chrome/common/chrome_features.h" #include "ui/base/unowned_user_data/scoped_unowned_user_data.h" @@ -13,16 +14,21 @@ InitialWebUIManager::InitialWebUIManager(BrowserWindowInterface* browser) : is_initial_web_ui_pending_(features::IsWebUIToolbarEnabled()), - scoped_data_holder_(browser->GetUnownedUserDataHost(), *this) {} + scoped_data_holder_(browser->GetUnownedUserDataHost(), *this), + metrics_manager_(InitialWebUIWindowMetricsManager::From(browser)) {} InitialWebUIManager::~InitialWebUIManager() = default; +// static InitialWebUIManager* InitialWebUIManager::From( BrowserWindowInterface* browser_window_interface) { return Get(browser_window_interface->GetUnownedUserDataHost()); } bool InitialWebUIManager::RequestDeferShow(base::OnceClosure unsafe_callback) { + if (metrics_manager_) { + metrics_manager_->OnBrowserWindowShowRequested(base::TimeTicks::Now()); + } if (!base::FeatureList::IsEnabled(features::kWebUIReloadButton) && !features::kWebUIReloadButtonDeferBrowserViewShow.Get()) { return false;
diff --git a/chrome/browser/ui/waap/initial_web_ui_manager.h b/chrome/browser/ui/waap/initial_web_ui_manager.h index 721c977..bee6f4a5 100644 --- a/chrome/browser/ui/waap/initial_web_ui_manager.h +++ b/chrome/browser/ui/waap/initial_web_ui_manager.h
@@ -10,6 +10,7 @@ #include "ui/base/unowned_user_data/scoped_unowned_user_data.h" class BrowserWindowInterface; +class InitialWebUIWindowMetricsManager; // Manages the initialization state of WebUI components that must be loaded // before the browser window is shown. @@ -62,6 +63,8 @@ bool is_show_pending_ = false; ui::ScopedUnownedUserData<InitialWebUIManager> scoped_data_holder_; + + raw_ptr<InitialWebUIWindowMetricsManager> metrics_manager_; }; #endif // CHROME_BROWSER_UI_WAAP_INITIAL_WEB_UI_MANAGER_H_
diff --git a/chrome/browser/ui/waap/initial_webui_window_metrics_manager.cc b/chrome/browser/ui/waap/initial_webui_window_metrics_manager.cc index 6df4a5a6..81498e3 100644 --- a/chrome/browser/ui/waap/initial_webui_window_metrics_manager.cc +++ b/chrome/browser/ui/waap/initial_webui_window_metrics_manager.cc
@@ -34,6 +34,13 @@ new_window_start_time_ = creation_time; } +void InitialWebUIWindowMetricsManager::OnBrowserWindowShowRequested( + base::TimeTicks time) { + if (!window_show_first_requested_time_.has_value()) { + window_show_first_requested_time_ = time; + } +} + void InitialWebUIWindowMetricsManager::OnBrowserWindowFirstPresentation( base::TimeTicks timestamp) { // Ensures only one startup window is recorded per browser process. @@ -42,6 +49,19 @@ return; } + if (window_show_first_requested_time_.has_value()) { + // Record ShowRequestedToFirstPaint metric. + if (!is_startup_first_paint_recorded && + !skip_startup_metrics_for_testing_) { + waap_service_->OnStartupBrowserWindowShowRequestedToFirstPaint( + *window_show_first_requested_time_, timestamp); + } else if (!is_new_window_first_paint_recorded_ && + new_window_start_time_.has_value()) { + waap_service_->OnNewWindowBrowserWindowShowRequestedToFirstPaint( + creation_source_, *window_show_first_requested_time_, timestamp); + } + } + if (!browser_window_first_paint_time_.has_value()) { browser_window_first_paint_time_ = timestamp; RecordPaintDeltaIfAvailable();
diff --git a/chrome/browser/ui/waap/initial_webui_window_metrics_manager.h b/chrome/browser/ui/waap/initial_webui_window_metrics_manager.h index 728b07f..564f7eb 100644 --- a/chrome/browser/ui/waap/initial_webui_window_metrics_manager.h +++ b/chrome/browser/ui/waap/initial_webui_window_metrics_manager.h
@@ -26,6 +26,9 @@ // - "New Window" metrics are recorded for *every* window (not including the // first one), if the window was created with a valid // `new_window_start_time`. +// +// This class is a feature of BrowserWindowFeature, meaning an instance is +// created per browser window and is scoped to the window's lifetime. class InitialWebUIWindowMetricsManager { public: DECLARE_USER_DATA(InitialWebUIWindowMetricsManager); @@ -48,6 +51,10 @@ void SetWindowCreationInfo(waap::NewWindowCreationSource source, base::TimeTicks creation_time); + // Notifies the manager that a request to show the browser window has been + // made. + void OnBrowserWindowShowRequested(base::TimeTicks time); + // Called when the browser window is presented first time. // This handles both startup window and new window metrics. void OnBrowserWindowFirstPresentation(base::TimeTicks timestamp); @@ -103,6 +110,9 @@ std::optional<base::TimeTicks> browser_window_first_paint_time_; std::optional<base::TimeTicks> reload_button_first_paint_time_; + // Track the first time a request to show the window was made. + std::optional<base::TimeTicks> window_show_first_requested_time_; + // Helper to emit the delta metric once both timestamps are available. void RecordPaintDeltaIfAvailable();
diff --git a/chrome/browser/ui/waap/initial_webui_window_metrics_manager_unittest.cc b/chrome/browser/ui/waap/initial_webui_window_metrics_manager_unittest.cc index eac081c..dfd49e2 100644 --- a/chrome/browser/ui/waap/initial_webui_window_metrics_manager_unittest.cc +++ b/chrome/browser/ui/waap/initial_webui_window_metrics_manager_unittest.cc
@@ -104,3 +104,78 @@ "FirstPaintGap", webui_delay, 1); } + +TEST_F(InitialWebUIWindowMetricsManagerTest, RecordsShowRequestedToFirstPaint) { + const base::TimeTicks start_time = base::TimeTicks::Now(); + InitialWebUIWindowMetricsManager manager(&browser_window_); + manager.SetWindowCreationInfo( + waap::NewWindowCreationSource::kBrowserInitiated, start_time); + manager.SkipStartupForTesting(); + + base::HistogramTester tester; + + // Simulate show request. + base::TimeDelta show_request_delay = base::Milliseconds(30); + base::TimeTicks show_request_time = start_time + show_request_delay; + manager.OnBrowserWindowShowRequested(show_request_time); + + // Still no metric because first presentation hasn't happened. + tester.ExpectTotalCount( + "InitialWebUI.NewWindow.AllSources.BrowserWindow." + "ShowRequestedToFirstPaint", + 0); + + // Simulate presenting native window. + base::TimeDelta total_delay = base::Milliseconds(100); + base::TimeTicks browser_window_time = start_time + total_delay; + manager.OnBrowserWindowFirstPresentation(browser_window_time); + + // ShowRequestedToFirstPaint should be the time between show request and + // presentation. + base::TimeDelta expected_delta = total_delay - show_request_delay; + + tester.ExpectUniqueTimeSample( + "InitialWebUI.NewWindow.AllSources.BrowserWindow." + "ShowRequestedToFirstPaint.FromConstructor", + expected_delta, 1); + tester.ExpectUniqueTimeSample( + "InitialWebUI.NewWindow.BrowserInitiated.BrowserWindow." + "ShowRequestedToFirstPaint." + "FromConstructor", + expected_delta, 1); +} + +TEST_F(InitialWebUIWindowMetricsManagerTest, + ShowRequestedToFirstPaintIsIdempotent) { + const base::TimeTicks start_time = base::TimeTicks::Now(); + InitialWebUIWindowMetricsManager manager(&browser_window_); + manager.SetWindowCreationInfo( + waap::NewWindowCreationSource::kBrowserInitiated, start_time); + manager.SkipStartupForTesting(); + + base::HistogramTester tester; + + // 1st show request. + base::TimeDelta first_delay = base::Milliseconds(30); + base::TimeTicks first_time = start_time + first_delay; + manager.OnBrowserWindowShowRequested(first_time); + + // 2nd show request, which should be ignored. + base::TimeDelta second_delay = base::Milliseconds(60); + base::TimeTicks second_time = start_time + second_delay; + manager.OnBrowserWindowShowRequested(second_time); + + // Simulate presentation. + base::TimeDelta total_delay = base::Milliseconds(100); + base::TimeTicks browser_window_time = start_time + total_delay; + manager.OnBrowserWindowFirstPresentation(browser_window_time); + + // Baseline should be the 1st show request. + base::TimeDelta expected_delta = total_delay - first_delay; + + tester.ExpectUniqueTimeSample( + "InitialWebUI.NewWindow.AllSources.BrowserWindow." + "ShowRequestedToFirstPaint." + "FromConstructor", + expected_delta, 1); +}
diff --git a/chrome/browser/ui/waap/waap_ui_metrics_service.cc b/chrome/browser/ui/waap/waap_ui_metrics_service.cc index 2f6ece0..e343b3e2 100644 --- a/chrome/browser/ui/waap/waap_ui_metrics_service.cc +++ b/chrome/browser/ui/waap/waap_ui_metrics_service.cc
@@ -327,6 +327,22 @@ browser_window_paint_time, reload_button_paint_time); } +void WaapUIMetricsService::OnStartupBrowserWindowShowRequestedToFirstPaint( + base::TimeTicks request_time, + base::TimeTicks paint_time) { + RecordStartupPaintMetric("BrowserWindow.ShowRequestedToFirstPaint", + request_time, paint_time); +} + +void WaapUIMetricsService::OnNewWindowBrowserWindowShowRequestedToFirstPaint( + waap::NewWindowCreationSource source, + base::TimeTicks request_time, + base::TimeTicks paint_time) { + RecordNewWindowPaintMetric( + "BrowserWindow.ShowRequestedToFirstPaint.FromConstructor", source, + request_time, paint_time); +} + void WaapUIMetricsService::OnReloadButtonMousePressToNextPaint( base::TimeTicks start_ticks, base::TimeTicks end_ticks) {
diff --git a/chrome/browser/ui/waap/waap_ui_metrics_service.h b/chrome/browser/ui/waap/waap_ui_metrics_service.h index 0845e49..813b9e00 100644 --- a/chrome/browser/ui/waap/waap_ui_metrics_service.h +++ b/chrome/browser/ui/waap/waap_ui_metrics_service.h
@@ -126,6 +126,19 @@ base::TimeTicks start_ticks, base::TimeTicks end_ticks, WaapUIMetricsRecorder::ReloadButtonMode new_mode); + + // Called when the first browser window is painted after it's requested to be + // shown during startup. + void OnStartupBrowserWindowShowRequestedToFirstPaint( + base::TimeTicks request_time, + base::TimeTicks paint_time); + + // Called when a new browser window (not the initial one) is first painted + // after it's requested to be shown. + void OnNewWindowBrowserWindowShowRequestedToFirstPaint( + waap::NewWindowCreationSource source, + base::TimeTicks request_time, + base::TimeTicks paint_time); }; #endif // CHROME_BROWSER_UI_WAAP_WAAP_UI_METRICS_SERVICE_H_
diff --git a/chrome/browser/ui/webid/identity_dialog_controller.cc b/chrome/browser/ui/webid/identity_dialog_controller.cc index a71dff3..4547939 100644 --- a/chrome/browser/ui/webid/identity_dialog_controller.cc +++ b/chrome/browser/ui/webid/identity_dialog_controller.cc
@@ -55,6 +55,11 @@ actor_task_state_subscription_ = actor_service->AddTaskStateChangedCallback( base::BindRepeating(&IdentityDialogController::OnActorTaskStateChanged, weak_ptr_factory_.GetWeakPtr())); + const actor::ActorTask* acting_task = + actor_service->GetActingActorTaskForWebContents(rp_web_contents_); + if (acting_task) { + acting_task_id_ = acting_task->id(); + } } if (!base::FeatureList::IsEnabled( @@ -531,6 +536,11 @@ account_view_ = std::move(account_view); } +void IdentityDialogController::SetActingTaskIdForTesting( + actor::TaskId task_id) { + UpdateTaskId(task_id); +} + bool IdentityDialogController::TrySetAccountView() { if (account_view_) { return true;
diff --git a/chrome/browser/ui/webid/identity_dialog_controller.h b/chrome/browser/ui/webid/identity_dialog_controller.h index 512202e..8fd36cd5 100644 --- a/chrome/browser/ui/webid/identity_dialog_controller.h +++ b/chrome/browser/ui/webid/identity_dialog_controller.h
@@ -162,6 +162,9 @@ void SetAccountSelectionViewForTesting( std::unique_ptr<AccountSelectionView> account_view); + // Set acting_task_id for testing purposes. + void SetActingTaskIdForTesting(actor::TaskId task_id); + // Requests a UI volume recommendation from |segmentation_platform_service_|. void RequestUiVolumeRecommendation( segmentation_platform::ClassificationResultCallback callback);
diff --git a/chrome/browser/ui/webid/identity_dialog_controller_unittest.cc b/chrome/browser/ui/webid/identity_dialog_controller_unittest.cc index 61b7b1b..e7cd7d6 100644 --- a/chrome/browser/ui/webid/identity_dialog_controller_unittest.cc +++ b/chrome/browser/ui/webid/identity_dialog_controller_unittest.cc
@@ -128,6 +128,8 @@ MOCK_METHOD(void, CloseModalDialog, (), (override)); MOCK_METHOD(content::WebContents*, GetRpWebContents, (), (override)); + + MOCK_METHOD(void, SetCanShowWidget, (bool), (override)); }; class IdentityDialogControllerTest : public ChromeRenderViewHostTestHarness { @@ -349,6 +351,28 @@ EXPECT_FALSE(prompt_factory->is_visible()); } +TEST_F(IdentityDialogControllerTest, ActorTaskSuppressesUi) { + std::unique_ptr<IdentityDialogController> controller = + std::make_unique<IdentityDialogController>(web_contents()); + auto mock_view = std::make_unique<MockAccountSelectionView>(); + MockAccountSelectionView* view_ptr = mock_view.get(); + + // 1. Simulate an active actor task. This should call SetCanShowWidget(false). + EXPECT_CALL(*view_ptr, SetCanShowWidget(false)); + controller->SetAccountSelectionViewForTesting(std::move(mock_view)); + controller->SetActingTaskIdForTesting(actor::TaskId::FromUnsafeValue(1)); + + // 2. Even if there is an active task, ShowLoadingDialog should be called. + // The visibility control happens inside the real view implementation, + // or via the SetCanShowWidget(false) call we just verified. + EXPECT_CALL(*view_ptr, ShowLoadingDialog).WillOnce(testing::Return(true)); + + EXPECT_TRUE(controller->ShowLoadingDialog( + content::RelyingPartyData(kTopFrameEtldPlusOne, u""), kIdpEtldPlusOne, + blink::mojom::RpContext::kSignIn, blink::mojom::RpMode::kActive, + base::DoNothing())); +} + TEST_F(IdentityDialogControllerTest, Deny) { std::unique_ptr<IdentityDialogController> controller = std::make_unique<IdentityDialogController>(web_contents());
diff --git a/chrome/browser/ui/webui/BUILD.gn b/chrome/browser/ui/webui/BUILD.gn index 0034168b..0cccaa5 100644 --- a/chrome/browser/ui/webui/BUILD.gn +++ b/chrome/browser/ui/webui/BUILD.gn
@@ -46,6 +46,7 @@ deps = [ ":webui", "//chrome/browser/actor/ui:actor_overlay", + "//chrome/browser/contextual_tasks:ui", "//chrome/browser/glic", "//chrome/browser/optimization_guide", "//chrome/browser/ui", @@ -74,7 +75,6 @@ deps += [ "//chrome/browser/actor/ui", "//chrome/browser/actor/ui:actor_overlay_web_view", - "//chrome/browser/contextual_tasks:ui", "//chrome/browser/glic/selection", "//chrome/browser/ui/webui/access_code_cast", "//chrome/browser/ui/webui/app_service_internals",
diff --git a/chrome/browser/ui/webui/ai_overlay_dialog/BUILD.gn b/chrome/browser/ui/webui/ai_overlay_dialog/BUILD.gn index 4b8ee47..e37da80 100644 --- a/chrome/browser/ui/webui/ai_overlay_dialog/BUILD.gn +++ b/chrome/browser/ui/webui/ai_overlay_dialog/BUILD.gn
@@ -13,6 +13,8 @@ source_set("ai_overlay_dialog") { sources = [ + "ai_overlay_dialog_page_handler.cc", + "ai_overlay_dialog_page_handler.h", "ai_overlay_dialog_untrusted_ui.cc", "ai_overlay_dialog_untrusted_ui.h", ]
diff --git a/chrome/browser/ui/webui/ai_overlay_dialog/ai_overlay_dialog.mojom b/chrome/browser/ui/webui/ai_overlay_dialog/ai_overlay_dialog.mojom index f81feede..3ad96b7 100644 --- a/chrome/browser/ui/webui/ai_overlay_dialog/ai_overlay_dialog.mojom +++ b/chrome/browser/ui/webui/ai_overlay_dialog/ai_overlay_dialog.mojom
@@ -5,4 +5,15 @@ module ai_overlay_dialog.mojom; // Factory for creating a PageHandler. -interface PageHandlerFactory {}; \ No newline at end of file +interface PageHandlerFactory { + // The WebUI calls this method when the page is first initialized. + CreatePageHandler(pending_receiver<PageHandler> handler); +}; + +// Implemented by browser C++ code. Called by WebUI. +interface PageHandler { + // Returns the API key for the AI backend. Used only for development/testing, + // without the key being specified on the command line this returns an empty + // string. + GetApiKey() => (string api_key); +}; \ No newline at end of file
diff --git a/chrome/browser/ui/webui/ai_overlay_dialog/ai_overlay_dialog_page_handler.cc b/chrome/browser/ui/webui/ai_overlay_dialog/ai_overlay_dialog_page_handler.cc new file mode 100644 index 0000000..cd3515b8 --- /dev/null +++ b/chrome/browser/ui/webui/ai_overlay_dialog/ai_overlay_dialog_page_handler.cc
@@ -0,0 +1,15 @@ +// Copyright 2026 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/webui/ai_overlay_dialog/ai_overlay_dialog_page_handler.h" + +AiOverlayDialogPageHandler::AiOverlayDialogPageHandler( + mojo::PendingReceiver<ai_overlay_dialog::mojom::PageHandler> receiver) + : receiver_(this, std::move(receiver)) {} + +AiOverlayDialogPageHandler::~AiOverlayDialogPageHandler() = default; + +void AiOverlayDialogPageHandler::GetApiKey(GetApiKeyCallback callback) { + std::move(callback).Run(features::kAiOverlayDialogApiKey.Get()); +}
diff --git a/chrome/browser/ui/webui/ai_overlay_dialog/ai_overlay_dialog_page_handler.h b/chrome/browser/ui/webui/ai_overlay_dialog/ai_overlay_dialog_page_handler.h new file mode 100644 index 0000000..c3f291dd --- /dev/null +++ b/chrome/browser/ui/webui/ai_overlay_dialog/ai_overlay_dialog_page_handler.h
@@ -0,0 +1,27 @@ +// Copyright 2026 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_WEBUI_AI_OVERLAY_DIALOG_AI_OVERLAY_DIALOG_PAGE_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_AI_OVERLAY_DIALOG_AI_OVERLAY_DIALOG_PAGE_HANDLER_H_ + +#include "chrome/browser/ui/ui_features.h" +#include "chrome/browser/ui/webui/ai_overlay_dialog/ai_overlay_dialog.mojom.h" +#include "mojo/public/cpp/bindings/receiver.h" +#include "mojo/public/cpp/bindings/remote.h" + +class AiOverlayDialogPageHandler + : public ai_overlay_dialog::mojom::PageHandler { + public: + explicit AiOverlayDialogPageHandler( + mojo::PendingReceiver<ai_overlay_dialog::mojom::PageHandler> receiver); + ~AiOverlayDialogPageHandler() override; + + // overlay_dialog::mojom::PageHandler interface + void GetApiKey(GetApiKeyCallback callback) override; + + private: + mojo::Receiver<ai_overlay_dialog::mojom::PageHandler> receiver_{this}; +}; + +#endif // CHROME_BROWSER_UI_WEBUI_AI_OVERLAY_DIALOG_AI_OVERLAY_DIALOG_PAGE_HANDLER_H_
diff --git a/chrome/browser/ui/webui/ai_overlay_dialog/ai_overlay_dialog_untrusted_ui.cc b/chrome/browser/ui/webui/ai_overlay_dialog/ai_overlay_dialog_untrusted_ui.cc index baa28094..aeecfdb 100644 --- a/chrome/browser/ui/webui/ai_overlay_dialog/ai_overlay_dialog_untrusted_ui.cc +++ b/chrome/browser/ui/webui/ai_overlay_dialog/ai_overlay_dialog_untrusted_ui.cc
@@ -4,11 +4,14 @@ #include "chrome/browser/ui/webui/ai_overlay_dialog/ai_overlay_dialog_untrusted_ui.h" +#include <memory> + #include "base/containers/span.h" #include "base/feature_list.h" #include "chrome/browser/glic/public/glic_enabling.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/ui_features.h" +#include "chrome/browser/ui/webui/ai_overlay_dialog/ai_overlay_dialog_page_handler.h" #include "chrome/common/webui_url_constants.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_ui.h" @@ -47,4 +50,17 @@ AiOverlayDialogUntrustedUI::~AiOverlayDialogUntrustedUI() = default; +void AiOverlayDialogUntrustedUI::BindInterface( + mojo::PendingReceiver<ai_overlay_dialog::mojom::PageHandlerFactory> + receiver) { + page_handler_factory_receiver_.reset(); + page_handler_factory_receiver_.Bind(std::move(receiver)); +} + WEB_UI_CONTROLLER_TYPE_IMPL(AiOverlayDialogUntrustedUI) + +void AiOverlayDialogUntrustedUI::CreatePageHandler( + mojo::PendingReceiver<ai_overlay_dialog::mojom::PageHandler> receiver) { + page_handler_ = + std::make_unique<AiOverlayDialogPageHandler>(std::move(receiver)); +}
diff --git a/chrome/browser/ui/webui/ai_overlay_dialog/ai_overlay_dialog_untrusted_ui.h b/chrome/browser/ui/webui/ai_overlay_dialog/ai_overlay_dialog_untrusted_ui.h index a192cbc..4da3c6fd 100644 --- a/chrome/browser/ui/webui/ai_overlay_dialog/ai_overlay_dialog_untrusted_ui.h +++ b/chrome/browser/ui/webui/ai_overlay_dialog/ai_overlay_dialog_untrusted_ui.h
@@ -5,11 +5,17 @@ #ifndef CHROME_BROWSER_UI_WEBUI_AI_OVERLAY_DIALOG_AI_OVERLAY_DIALOG_UNTRUSTED_UI_H_ #define CHROME_BROWSER_UI_WEBUI_AI_OVERLAY_DIALOG_AI_OVERLAY_DIALOG_UNTRUSTED_UI_H_ +#include <memory> + #include "chrome/browser/ui/webui/ai_overlay_dialog/ai_overlay_dialog.mojom.h" #include "chrome/browser/ui/webui/top_chrome/untrusted_top_chrome_web_ui_controller.h" #include "content/public/browser/webui_config.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" +#include "mojo/public/cpp/bindings/pending_remote.h" +#include "mojo/public/cpp/bindings/receiver.h" class AiOverlayDialogUntrustedUI; +class AiOverlayDialogPageHandler; class AiOverlayDialogUntrustedUIConfig : public content::DefaultWebUIConfig<AiOverlayDialogUntrustedUI> { @@ -19,7 +25,9 @@ bool IsWebUIEnabled(content::BrowserContext* browser_context) override; }; -class AiOverlayDialogUntrustedUI : public UntrustedTopChromeWebUIController { +class AiOverlayDialogUntrustedUI + : public UntrustedTopChromeWebUIController, + ai_overlay_dialog::mojom::PageHandlerFactory { public: explicit AiOverlayDialogUntrustedUI(content::WebUI* web_ui); AiOverlayDialogUntrustedUI(const AiOverlayDialogUntrustedUI&) = delete; @@ -27,8 +35,22 @@ delete; ~AiOverlayDialogUntrustedUI() override; + void BindInterface( + mojo::PendingReceiver<ai_overlay_dialog::mojom::PageHandlerFactory> + receiver); + + // ai_overlay_dialog::mojom::PageHandlerFactor interface + void CreatePageHandler( + mojo::PendingReceiver<ai_overlay_dialog::mojom::PageHandler> receiver) + override; + private: WEB_UI_CONTROLLER_TYPE_DECL(); + + std::unique_ptr<AiOverlayDialogPageHandler> page_handler_; + + mojo::Receiver<ai_overlay_dialog::mojom::PageHandlerFactory> + page_handler_factory_receiver_{this}; }; #endif // CHROME_BROWSER_UI_WEBUI_AI_OVERLAY_DIALOG_AI_OVERLAY_DIALOG_UNTRUSTED_UI_H_
diff --git a/chrome/browser/ui/webui/ash/login/multidevice_setup_screen_handler.cc b/chrome/browser/ui/webui/ash/login/multidevice_setup_screen_handler.cc index 703116fa..7e4a6f6 100644 --- a/chrome/browser/ui/webui/ash/login/multidevice_setup_screen_handler.cc +++ b/chrome/browser/ui/webui/ash/login/multidevice_setup_screen_handler.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/ui/webui/ash/login/multidevice_setup_screen_handler.h" #include "ash/constants/ash_features.h" +#include "ash/strings/grit/ash_strings.h" #include "base/values.h" #include "chrome/browser/ash/login/screens/multidevice_setup_screen.h" #include "chrome/browser/ui/webui/ash/multidevice_setup/multidevice_setup_localized_strings_provider.h"
diff --git a/chrome/browser/ui/webui/ash/login/oobe_display_chooser.cc b/chrome/browser/ui/webui/ash/login/oobe_display_chooser.cc index 4a65ac2..2569a74 100644 --- a/chrome/browser/ui/webui/ash/login/oobe_display_chooser.cc +++ b/chrome/browser/ui/webui/ash/login/oobe_display_chooser.cc
@@ -89,11 +89,10 @@ device_data_manager->GetTouchscreenDevices()) { if (IsAllowListedVendorId(device.vendor_id) && device.target_display_id != display::kInvalidDisplayId) { - auto config_properties = crosapi::mojom::DisplayConfigProperties::New(); - config_properties->set_primary = true; + DisplayConfigProperties config_properties; + config_properties.set_primary = true; cros_display_config_->SetDisplayProperties( - base::NumberToString(device.target_display_id), - std::move(config_properties), + base::NumberToString(device.target_display_id), config_properties, crosapi::mojom::DisplayConfigSource::kUser); break; }
diff --git a/chrome/browser/ui/webui/ash/login/oobe_display_chooser_unittest.cc b/chrome/browser/ui/webui/ash/login/oobe_display_chooser_unittest.cc index e5389143..d0efe398 100644 --- a/chrome/browser/ui/webui/ash/login/oobe_display_chooser_unittest.cc +++ b/chrome/browser/ui/webui/ash/login/oobe_display_chooser_unittest.cc
@@ -14,11 +14,7 @@ #include "base/run_loop.h" #include "base/strings/string_number_conversions.h" #include "chrome/test/base/chrome_ash_test_base.h" -#include "chromeos/crosapi/mojom/cros_display_config.mojom-shared.h" #include "chromeos/crosapi/mojom/cros_display_config.mojom.h" -#include "mojo/public/cpp/bindings/pending_associated_remote.h" -#include "mojo/public/cpp/bindings/pending_remote.h" -#include "mojo/public/cpp/bindings/receiver.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/display/display.h" #include "ui/display/display_observer.h" @@ -42,39 +38,40 @@ // CrosDisplayConfig: void AddObserver(Observer* observer) override {} void RemoveObserver(Observer* observer) override {} - crosapi::mojom::DisplayLayoutInfoPtr GetDisplayLayoutInfo() override { - NOTREACHED(); - } - crosapi::mojom::DisplayConfigResult SetDisplayLayoutInfo( - crosapi::mojom::DisplayLayoutInfoPtr info) override { + ash::DisplayLayoutInfo GetDisplayLayoutInfo() override { NOTREACHED(); } + DisplayConfigResult SetDisplayLayoutInfo( + const ash::DisplayLayoutInfo& info) override { NOTREACHED(); } std::vector<crosapi::mojom::DisplayUnitInfoPtr> GetDisplayUnitInfoList( bool single_unified) override { NOTREACHED(); } - crosapi::mojom::DisplayConfigResult SetDisplayProperties( + DisplayConfigResult SetDisplayProperties( const std::string& id, - crosapi::mojom::DisplayConfigPropertiesPtr properties, + const DisplayConfigProperties& properties, crosapi::mojom::DisplayConfigSource source) override { - if (properties->set_primary) { + if (properties.set_primary) { int64_t display_id; base::StringToInt64(id, &display_id); Shell::Get()->window_tree_host_manager()->SetPrimaryDisplayId(display_id); } - return crosapi::mojom::DisplayConfigResult::kSuccess; + return DisplayConfigResult::kSuccess; } void SetUnifiedDesktopEnabled(bool enabled) override {} - crosapi::mojom::DisplayConfigResult OverscanCalibration( + DisplayConfigResult OverscanCalibration( const std::string& display_id, crosapi::mojom::DisplayConfigOperation op, const std::optional<gfx::Insets>& delta) override { NOTREACHED(); } - void TouchCalibration(const std::string& display_id, - crosapi::mojom::DisplayConfigOperation op, - crosapi::mojom::TouchCalibrationPtr calibration, - TouchCalibrationCallback callback) override {} + void TouchCalibration( + const std::string& display_id, + crosapi::mojom::DisplayConfigOperation op, + base::optional_ref<const display::TouchCalibrationData> calibration, + TouchCalibrationCallback callback) override { + NOTREACHED(); + } void HighlightDisplay(int64_t id) override {} void DragDisplayDelta(int64_t display_id, int32_t delta_x,
diff --git a/chrome/browser/ui/webui/ash/login/oobe_ui.cc b/chrome/browser/ui/webui/ash/login/oobe_ui.cc index 07099d7b..0b6d2408 100644 --- a/chrome/browser/ui/webui/ash/login/oobe_ui.cc +++ b/chrome/browser/ui/webui/ash/login/oobe_ui.cc
@@ -408,7 +408,7 @@ bool OobeUIConfig::IsWebUIEnabled(content::BrowserContext* browser_context) { base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - bool is_running_test = command_line->HasSwitch(ash::switches::kTestName) || + bool is_running_test = command_line->HasSwitch(::switches::kTestName) || command_line->HasSwitch(::switches::kTestType); return ash::ProfileHelper::IsSigninProfile(
diff --git a/chrome/browser/ui/webui/ash/settings/pages/about/BUILD.gn b/chrome/browser/ui/webui/ash/settings/pages/about/BUILD.gn index 77c0981..2cf0404 100644 --- a/chrome/browser/ui/webui/ash/settings/pages/about/BUILD.gn +++ b/chrome/browser/ui/webui/ash/settings/pages/about/BUILD.gn
@@ -22,6 +22,7 @@ deps = [ "//ash/constants", + "//ash/strings", "//base:i18n", "//chrome/app:branded_strings", "//chrome/app:generated_resources",
diff --git a/chrome/browser/ui/webui/ash/settings/pages/about/about_section.cc b/chrome/browser/ui/webui/ash/settings/pages/about/about_section.cc index ca759fe..15cb893 100644 --- a/chrome/browser/ui/webui/ash/settings/pages/about/about_section.cc +++ b/chrome/browser/ui/webui/ash/settings/pages/about/about_section.cc
@@ -10,6 +10,7 @@ #include "ash/constants/chrome_webui_url_constants.h" #include "ash/constants/url_constants.h" #include "ash/constants/webui_url_constants.h" +#include "ash/strings/grit/ash_strings.h" #include "base/command_line.h" #include "base/containers/span.h" #include "base/feature_list.h"
diff --git a/chrome/browser/ui/webui/ash/settings/pages/device/device_section.cc b/chrome/browser/ui/webui/ash/settings/pages/device/device_section.cc index aed894ee..2ff27e3 100644 --- a/chrome/browser/ui/webui/ash/settings/pages/device/device_section.cc +++ b/chrome/browser/ui/webui/ash/settings/pages/device/device_section.cc
@@ -1243,14 +1243,14 @@ cros_display_config_->GetDisplayUnitInfoList( /*single_unified=*/true); - crosapi::mojom::DisplayLayoutInfoPtr display_layout_info = + ash::DisplayLayoutInfo display_layout_info = cros_display_config_->GetDisplayLayoutInfo(); bool has_multiple_displays = display_unit_info_list.size() > 1u; // Mirroring mode is active if there's at least one display and if there's a // mirror source ID. bool is_mirrored = !display_unit_info_list.empty() && - display_layout_info->mirror_source_id.has_value(); + display_layout_info.mirror_source_id.has_value(); bool has_internal_display = false; bool has_external_display = false; @@ -1258,10 +1258,9 @@ for (const auto& display_unit_info : display_unit_info_list) { has_internal_display |= display_unit_info->is_internal; has_external_display |= !display_unit_info->is_internal; - - unified_desktop_mode |= display_unit_info->is_primary && - display_layout_info->layout_mode == - crosapi::mojom::DisplayLayoutMode::kUnified; + unified_desktop_mode |= + display_unit_info->is_primary && + display_layout_info.layout_mode == ash::DisplayLayoutMode::kUnified; } SearchTagRegistry::ScopedTagUpdater updater = registry()->StartUpdate();
diff --git a/chrome/browser/ui/webui/ash/settings/pages/device/display_settings/display_settings_provider.cc b/chrome/browser/ui/webui/ash/settings/pages/device/display_settings/display_settings_provider.cc index a8d037f..b91ca22 100644 --- a/chrome/browser/ui/webui/ash/settings/pages/device/display_settings/display_settings_provider.cc +++ b/chrome/browser/ui/webui/ash/settings/pages/device/display_settings/display_settings_provider.cc
@@ -469,7 +469,7 @@ &CrosDisplayConfig::TouchCalibration, base::Unretained(Shell::Get()->cros_display_config()), "", crosapi::mojom::DisplayConfigOperation::kShowNativeMappingDisplays, - nullptr, base::DoNothing())); + std::nullopt, base::DoNothing())); } } // namespace ash::settings
diff --git a/chrome/browser/ui/webui/chrome_finds_internals/BUILD.gn b/chrome/browser/ui/webui/chrome_finds_internals/BUILD.gn index 8d115aa..c16f8c3 100644 --- a/chrome/browser/ui/webui/chrome_finds_internals/BUILD.gn +++ b/chrome/browser/ui/webui/chrome_finds_internals/BUILD.gn
@@ -25,6 +25,8 @@ ] deps = [ + "//chrome/browser/finds", + "//chrome/browser/finds/core", "//chrome/browser/optimization_guide", "//chrome/common", "//chrome/common:constants",
diff --git a/chrome/browser/ui/webui/chrome_finds_internals/chrome_finds_agent.cc b/chrome/browser/ui/webui/chrome_finds_internals/chrome_finds_agent.cc index 1e75002e..86192fd 100644 --- a/chrome/browser/ui/webui/chrome_finds_internals/chrome_finds_agent.cc +++ b/chrome/browser/ui/webui/chrome_finds_internals/chrome_finds_agent.cc
@@ -9,6 +9,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/task/cancelable_task_tracker.h" #include "base/values.h" +#include "chrome/browser/finds/core/finds_service.h" #include "chrome/browser/optimization_guide/optimization_guide_keyed_service.h" #include "components/history/core/browser/history_service.h" #include "components/history/core/browser/history_types.h" @@ -25,9 +26,11 @@ ChromeFindsAgent::ChromeFindsAgent( OptimizationGuideKeyedService* opt_guide_service, - history::HistoryService* history_service) + history::HistoryService* history_service, + finds::FindsService* finds_service) : opt_guide_service_(opt_guide_service), - history_service_(history_service) {} + history_service_(history_service), + finds_service_(finds_service) {} ChromeFindsAgent::~ChromeFindsAgent() = default; @@ -62,6 +65,21 @@ &history_task_tracker_); } +void ChromeFindsAgent::GetFindsServiceModelResponse() { + AddLogMessage("ChromeFindsAgent::GetFindsServiceModelResponse() called."); + + if (!finds_service_) { + AddLogMessage("Error: FindsService not available."); + return; + } + + AddLogMessage("Executing model via FindsService..."); + + finds_service_->GetModelResponse( + base::BindOnce(&ChromeFindsAgent::OnModelResponseComplete, + weak_ptr_factory_.GetWeakPtr())); +} + void ChromeFindsAgent::GetHistoryJson( int32_t history_count, base::OnceCallback<void(const std::string&)> callback) { @@ -156,6 +174,19 @@ } } +void ChromeFindsAgent::OnModelResponseComplete( + finds::FindsService::Result result) { + AddLogMessage( + base::StringPrintf("Result status: %d", static_cast<int>(result.status))); + if (result.status != finds::FindsService::Result::Status::kSuccess) { + AddLogMessage(result.message); + return; + } + if (!result.message.empty()) { + AddLogMessage(result.message); + } +} + void ChromeFindsAgent::AddObserver(Observer* observer) { observers_.AddObserver(observer); }
diff --git a/chrome/browser/ui/webui/chrome_finds_internals/chrome_finds_agent.h b/chrome/browser/ui/webui/chrome_finds_internals/chrome_finds_agent.h index f214e4f62..0fa48fb 100644 --- a/chrome/browser/ui/webui/chrome_finds_internals/chrome_finds_agent.h +++ b/chrome/browser/ui/webui/chrome_finds_internals/chrome_finds_agent.h
@@ -21,6 +21,8 @@ class HistoryService; } +#include "chrome/browser/finds/core/finds_service.h" + namespace chrome_finds_internals { // A profile-keyed agent for Chrome Finds that manages events and notifies @@ -33,7 +35,8 @@ }; ChromeFindsAgent(OptimizationGuideKeyedService* opt_guide_service, - history::HistoryService* history_service); + history::HistoryService* history_service, + finds::FindsService* finds_service); ~ChromeFindsAgent() override; ChromeFindsAgent(const ChromeFindsAgent&) = delete; @@ -45,6 +48,9 @@ // Starts the AI notification process. void Start(const std::string& prompt, int32_t history_count); + // Sends a notification with the prompt via FindsService. + void GetFindsServiceModelResponse(); + // Retrieves history and returns it as a JSON string via callback. void GetHistoryJson(int32_t history_count, base::OnceCallback<void(const std::string&)> callback); @@ -60,9 +66,11 @@ void OnModelExecutionComplete( optimization_guide::OptimizationGuideModelExecutionResult result, std::unique_ptr<optimization_guide::ModelQualityLogEntry> log_entry); + void OnModelResponseComplete(finds::FindsService::Result result); raw_ptr<OptimizationGuideKeyedService> opt_guide_service_; raw_ptr<history::HistoryService> history_service_; + raw_ptr<finds::FindsService> finds_service_; std::vector<std::string> logs_; base::ObserverList<Observer> observers_; base::CancelableTaskTracker history_task_tracker_;
diff --git a/chrome/browser/ui/webui/chrome_finds_internals/chrome_finds_agent_factory.cc b/chrome/browser/ui/webui/chrome_finds_internals/chrome_finds_agent_factory.cc index 1eb04d1..8f7b90b 100644 --- a/chrome/browser/ui/webui/chrome_finds_internals/chrome_finds_agent_factory.cc +++ b/chrome/browser/ui/webui/chrome_finds_internals/chrome_finds_agent_factory.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/ui/webui/chrome_finds_internals/chrome_finds_agent_factory.h" +#include "chrome/browser/finds/finds_service_factory.h" #include "chrome/browser/history/history_service_factory.h" #include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h" #include "chrome/browser/profiles/profile.h" @@ -32,6 +33,7 @@ .Build()) { DependsOn(OptimizationGuideKeyedServiceFactory::GetInstance()); DependsOn(HistoryServiceFactory::GetInstance()); + DependsOn(finds::FindsServiceFactory::GetInstance()); } ChromeFindsAgentFactory::~ChromeFindsAgentFactory() = default; @@ -43,7 +45,8 @@ return std::make_unique<ChromeFindsAgent>( OptimizationGuideKeyedServiceFactory::GetForProfile(profile), HistoryServiceFactory::GetForProfile(profile, - ServiceAccessType::EXPLICIT_ACCESS)); + ServiceAccessType::EXPLICIT_ACCESS), + finds::FindsServiceFactory::GetForProfile(profile)); } } // namespace chrome_finds_internals
diff --git a/chrome/browser/ui/webui/chrome_finds_internals/chrome_finds_internals.mojom b/chrome/browser/ui/webui/chrome_finds_internals/chrome_finds_internals.mojom index 635dfe58..25ecc09 100644 --- a/chrome/browser/ui/webui/chrome_finds_internals/chrome_finds_internals.mojom +++ b/chrome/browser/ui/webui/chrome_finds_internals/chrome_finds_internals.mojom
@@ -16,6 +16,10 @@ // Use 0 for all history. Start(string prompt, int32 history_count); + // Starts an AI notification process that fetches history internally through + // FindsService. + GetFindsServiceModelResponse(); + // Returns a JSON string of the user's browsing history. GetHistoryJson(int32 history_count) => (string json); };
diff --git a/chrome/browser/ui/webui/chrome_finds_internals/chrome_finds_internals_ui.cc b/chrome/browser/ui/webui/chrome_finds_internals/chrome_finds_internals_ui.cc index fc8e47a9..eeff3ad9 100644 --- a/chrome/browser/ui/webui/chrome_finds_internals/chrome_finds_internals_ui.cc +++ b/chrome/browser/ui/webui/chrome_finds_internals/chrome_finds_internals_ui.cc
@@ -45,6 +45,10 @@ agent_->Start(prompt, history_count); } + void GetFindsServiceModelResponse() override { + agent_->GetFindsServiceModelResponse(); + } + void GetHistoryJson(int32_t history_count, GetHistoryJsonCallback callback) override { agent_->GetHistoryJson(history_count, std::move(callback));
diff --git a/chrome/browser/ui/webui/chrome_web_ui_configs.cc b/chrome/browser/ui/webui/chrome_web_ui_configs.cc index c1d2e75..78c6fb74 100644 --- a/chrome/browser/ui/webui/chrome_web_ui_configs.cc +++ b/chrome/browser/ui/webui/chrome_web_ui_configs.cc
@@ -7,6 +7,7 @@ #include "build/android_buildflags.h" #include "build/branding_buildflags.h" #include "build/build_config.h" +#include "chrome/browser/contextual_tasks/contextual_tasks_ui.h" #include "chrome/browser/glic/host/glic_ui.h" #include "chrome/browser/optimization_guide/optimization_guide_internals_ui.h" #include "chrome/browser/ui/webui/about/about_ui.h" @@ -74,7 +75,6 @@ #if !BUILDFLAG(IS_ANDROID) #include "chrome/browser/actor/ui/actor_overlay_ui.h" -#include "chrome/browser/contextual_tasks/contextual_tasks_ui.h" #include "chrome/browser/ui/tabs/tab_group_home/tab_group_home_ui.h" #include "chrome/browser/ui/webui/content_annotator_internals/content_annotator_internals_ui.h" #include "chrome/browser/ui/webui/webui_toolbar/webui_toolbar_ui.h" @@ -249,6 +249,7 @@ map.AddWebUIConfig(std::make_unique<commerce::CommerceInternalsUIConfig>()); map.AddWebUIConfig(std::make_unique<ActorInternalsUIConfig>()); map.AddWebUIConfig(std::make_unique<ComponentsUIConfig>()); + map.AddWebUIConfig(std::make_unique<ContextualTasksUIConfig>()); map.AddWebUIConfig( std::make_unique<security_interstitials::ConnectionHelpUIConfig>()); map.AddWebUIConfig( @@ -318,7 +319,9 @@ #if BUILDFLAG(GOOGLE_CHROME_BRANDING) map.AddWebUIConfig(std::make_unique<media_router::CastFeedbackUIConfig>()); #endif // BUILDFLAG(GOOGLE_CHROME_BRANDING) - map.AddWebUIConfig(std::make_unique<ContentAnnotatorInternalsUIConfig>()); + map.AddWebUIConfig( + std::make_unique< + content_annotator_internals::ContentAnnotatorInternalsUIConfig>()); map.AddWebUIConfig(std::make_unique<actor::ui::ActorOverlayUIConfig>()); map.AddWebUIConfig(std::make_unique<AppServiceInternalsUIConfig>()); map.AddWebUIConfig(std::make_unique<AutofillMlInternalsUIConfig>()); @@ -327,7 +330,6 @@ map.AddWebUIConfig(std::make_unique<BookmarksUIConfig>()); map.AddWebUIConfig(std::make_unique<ColorPipelineInternalsUIConfig>()); map.AddWebUIConfig(std::make_unique<CommentsSidePanelUIConfig>()); - map.AddWebUIConfig(std::make_unique<ContextualTasksUIConfig>()); map.AddWebUIConfig(std::make_unique<CustomizeChromeUIConfig>()); map.AddWebUIConfig(std::make_unique<DownloadsUIConfig>()); map.AddWebUIConfig(std::make_unique<FeedbackUIConfig>());
diff --git a/chrome/browser/ui/webui/content_annotator_internals/BUILD.gn b/chrome/browser/ui/webui/content_annotator_internals/BUILD.gn index 8eb0da0..a62a7123 100644 --- a/chrome/browser/ui/webui/content_annotator_internals/BUILD.gn +++ b/chrome/browser/ui/webui/content_annotator_internals/BUILD.gn
@@ -5,18 +5,45 @@ assert(!is_android) source_set("content_annotator_internals") { sources = [ + "content_annotator_internals_page_handler.cc", + "content_annotator_internals_page_handler.h", "content_annotator_internals_ui.cc", "content_annotator_internals_ui.h", ] public_deps = [ + "//base", + "//components/accessibility_annotator/core/logging:mojo_bindings", "//content/public/browser", + "//mojo/public/cpp/bindings", "//ui/webui", ] deps = [ + "//chrome/browser/accessibility_annotator", "//chrome/browser/profiles:profile", "//chrome/browser/resources/content_annotator_internals:resources", "//chrome/common", + "//components/accessibility_annotator/core/storage", + ] +} + +source_set("unit_tests") { + testonly = true + sources = [ "content_annotator_internals_page_handler_unittest.cc" ] + deps = [ + ":content_annotator_internals", + "//base", + "//base/test:test_support", + "//chrome/browser/accessibility_annotator", + "//chrome/test:test_support", + "//components/accessibility_annotator/core/logging:mojo_bindings", + "//components/accessibility_annotator/core/storage", + "//components/sync:test_support", + "//components/version_info", + "//content/test:test_support", + "//mojo/public/cpp/bindings", + "//testing/gmock", + "//testing/gtest", ] }
diff --git a/chrome/browser/ui/webui/content_annotator_internals/content_annotator_internals_page_handler.cc b/chrome/browser/ui/webui/content_annotator_internals/content_annotator_internals_page_handler.cc new file mode 100644 index 0000000..829c235 --- /dev/null +++ b/chrome/browser/ui/webui/content_annotator_internals/content_annotator_internals_page_handler.cc
@@ -0,0 +1,40 @@ +// Copyright 2026 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/webui/content_annotator_internals/content_annotator_internals_page_handler.h" + +#include <string> +#include <utility> + +#include "chrome/browser/accessibility_annotator/accessibility_annotator_backend_factory.h" +#include "chrome/browser/profiles/profile.h" +#include "components/accessibility_annotator/core/logging/accessibility_annotator_internals.mojom.h" +#include "components/accessibility_annotator/core/storage/accessibility_annotator_backend.h" + +namespace content_annotator_internals { + +ContentAnnotatorInternalsPageHandler::ContentAnnotatorInternalsPageHandler( + mojo::PendingReceiver<accessibility_annotator_internals::mojom::PageHandler> + receiver, + mojo::PendingRemote<accessibility_annotator_internals::mojom::Page> page, + Profile* profile) + : receiver_(this, std::move(receiver)), + page_(std::move(page)), + profile_(profile) {} + +ContentAnnotatorInternalsPageHandler::~ContentAnnotatorInternalsPageHandler() = + default; + +void ContentAnnotatorInternalsPageHandler::GetAnnotatedContent( + GetAnnotatedContentCallback callback) { + accessibility_annotator::AccessibilityAnnotatorBackend* backend = + AccessibilityAnnotatorBackendFactory::GetForProfile(profile_); + if (!backend) { + std::move(callback).Run(std::nullopt); + return; + } + std::move(callback).Run(backend->GetDebugUIFormattedCacheData()); +} + +} // namespace content_annotator_internals
diff --git a/chrome/browser/ui/webui/content_annotator_internals/content_annotator_internals_page_handler.h b/chrome/browser/ui/webui/content_annotator_internals/content_annotator_internals_page_handler.h new file mode 100644 index 0000000..6b957b3e --- /dev/null +++ b/chrome/browser/ui/webui/content_annotator_internals/content_annotator_internals_page_handler.h
@@ -0,0 +1,49 @@ +// Copyright 2026 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_WEBUI_CONTENT_ANNOTATOR_INTERNALS_CONTENT_ANNOTATOR_INTERNALS_PAGE_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_CONTENT_ANNOTATOR_INTERNALS_CONTENT_ANNOTATOR_INTERNALS_PAGE_HANDLER_H_ + +#include "base/memory/raw_ptr.h" +#include "components/accessibility_annotator/core/logging/accessibility_annotator_internals.mojom.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/remote.h" + +class Profile; + +namespace content_annotator_internals { + +class ContentAnnotatorInternalsPageHandler + : public accessibility_annotator_internals::mojom::PageHandler { + public: + explicit ContentAnnotatorInternalsPageHandler( + mojo::PendingReceiver< + accessibility_annotator_internals::mojom::PageHandler> receiver, + mojo::PendingRemote<accessibility_annotator_internals::mojom::Page> page, + Profile* profile); + ContentAnnotatorInternalsPageHandler( + const ContentAnnotatorInternalsPageHandler&) = delete; + ContentAnnotatorInternalsPageHandler& operator=( + const ContentAnnotatorInternalsPageHandler&) = delete; + ~ContentAnnotatorInternalsPageHandler() override; + + // accessibility_annotator_internals::mojom::PageHandler: + void GetAnnotatedContent(GetAnnotatedContentCallback callback) override; + + private: + mojo::Receiver<accessibility_annotator_internals::mojom::PageHandler> + receiver_; + mojo::Remote<accessibility_annotator_internals::mojom::Page> page_; + + // The WebUI interacts with the AccessibilityAnnotatorBackend, which is a + // KeyedService tied to the lifetime of the Profile. As a result, the Profile + // will always outlive this page handler. + raw_ptr<Profile> profile_ = nullptr; +}; + +} // namespace content_annotator_internals + +#endif // CHROME_BROWSER_UI_WEBUI_CONTENT_ANNOTATOR_INTERNALS_CONTENT_ANNOTATOR_INTERNALS_PAGE_HANDLER_H_
diff --git a/chrome/browser/ui/webui/content_annotator_internals/content_annotator_internals_page_handler_unittest.cc b/chrome/browser/ui/webui/content_annotator_internals/content_annotator_internals_page_handler_unittest.cc new file mode 100644 index 0000000..57e1020 --- /dev/null +++ b/chrome/browser/ui/webui/content_annotator_internals/content_annotator_internals_page_handler_unittest.cc
@@ -0,0 +1,92 @@ +// Copyright 2026 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/webui/content_annotator_internals/content_annotator_internals_page_handler.h" + +#include <memory> +#include <optional> +#include <string> + +#include "base/files/scoped_temp_dir.h" +#include "base/test/bind.h" +#include "chrome/browser/accessibility_annotator/accessibility_annotator_backend_factory.h" +#include "chrome/test/base/testing_profile.h" +#include "components/accessibility_annotator/core/logging/accessibility_annotator_internals.mojom.h" +#include "components/accessibility_annotator/core/storage/accessibility_annotator_backend.h" +#include "components/sync/test/data_type_store_test_util.h" +#include "components/version_info/channel.h" +#include "content/public/test/browser_task_environment.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 "testing/gtest/include/gtest/gtest.h" + +namespace content_annotator_internals { + +namespace { + +class MockPage : public accessibility_annotator_internals::mojom::Page { + public: + mojo::PendingRemote<accessibility_annotator_internals::mojom::Page> + BindAndGetRemote() { + return receiver_.BindNewPipeAndPassRemote(); + } + + private: + mojo::Receiver<accessibility_annotator_internals::mojom::Page> receiver_{ + this}; +}; + +class ContentAnnotatorInternalsPageHandlerTest : public testing::Test { + public: + void SetUp() override { + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); + + // Set up the AccessibilityAnnotatorBackendFactory to use a real backend + // with an in-memory store. + AccessibilityAnnotatorBackendFactory::GetInstance() + ->SetTestingFactoryAndUse( + &profile_, + base::BindRepeating( + [](base::FilePath path, content::BrowserContext* context) + -> std::unique_ptr<KeyedService> { + return std::make_unique< + accessibility_annotator::AccessibilityAnnotatorBackend>( + version_info::Channel::UNKNOWN, + syncer::DataTypeStoreTestUtil:: + FactoryForInMemoryStoreForTest(), + path.Append( + FILE_PATH_LITERAL("AccessibilityAnnotatorDatabase"))); + }, + temp_dir_.GetPath())); + + handler_ = std::make_unique<ContentAnnotatorInternalsPageHandler>( + mojo::PendingReceiver< + accessibility_annotator_internals::mojom::PageHandler>(), + mock_page_.BindAndGetRemote(), &profile_); + } + + ContentAnnotatorInternalsPageHandler* GetHandler() { return handler_.get(); } + + private: + content::BrowserTaskEnvironment task_environment_; + base::ScopedTempDir temp_dir_; + TestingProfile profile_; + MockPage mock_page_; + std::unique_ptr<ContentAnnotatorInternalsPageHandler> handler_; +}; + +TEST_F(ContentAnnotatorInternalsPageHandlerTest, GetAnnotatedContent) { + base::RunLoop run_loop; + GetHandler()->GetAnnotatedContent(base::BindLambdaForTesting( + [&](const std::optional<std::string>& content) { + EXPECT_TRUE(content.has_value()); + EXPECT_EQ(*content, "Cache data not yet available for the debug UI."); + run_loop.Quit(); + })); + run_loop.Run(); +} + +} // namespace +} // namespace content_annotator_internals
diff --git a/chrome/browser/ui/webui/content_annotator_internals/content_annotator_internals_ui.cc b/chrome/browser/ui/webui/content_annotator_internals/content_annotator_internals_ui.cc index b7a2d14..083baf9 100644 --- a/chrome/browser/ui/webui/content_annotator_internals/content_annotator_internals_ui.cc +++ b/chrome/browser/ui/webui/content_annotator_internals/content_annotator_internals_ui.cc
@@ -4,16 +4,22 @@ #include "chrome/browser/ui/webui/content_annotator_internals/content_annotator_internals_ui.h" +#include <memory> + #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/webui/content_annotator_internals/content_annotator_internals_page_handler.h" #include "chrome/common/webui_url_constants.h" #include "chrome/grit/content_annotator_internals_resources.h" #include "chrome/grit/content_annotator_internals_resources_map.h" +#include "components/accessibility_annotator/core/logging/accessibility_annotator_internals.mojom.h" #include "content/public/browser/web_ui.h" #include "content/public/browser/web_ui_data_source.h" #include "ui/webui/webui_util.h" +namespace content_annotator_internals { + ContentAnnotatorInternalsUI::ContentAnnotatorInternalsUI(content::WebUI* web_ui) - : content::WebUIController(web_ui) { + : ui::MojoWebUIController(web_ui) { // Set up the chrome://content-annotator-internals source. content::WebUIDataSource* source = content::WebUIDataSource::CreateAndAdd( Profile::FromWebUI(web_ui), @@ -28,4 +34,23 @@ source->AddString("message", "Hello from the C++ backend!"); } +void ContentAnnotatorInternalsUI::BindInterface( + mojo::PendingReceiver< + accessibility_annotator_internals::mojom::PageHandlerFactory> + receiver) { + page_factory_receiver_.reset(); + page_factory_receiver_.Bind(std::move(receiver)); +} + +void ContentAnnotatorInternalsUI::CreatePageHandler( + mojo::PendingRemote<accessibility_annotator_internals::mojom::Page> page, + mojo::PendingReceiver<accessibility_annotator_internals::mojom::PageHandler> + receiver) { + page_handler_ = std::make_unique<ContentAnnotatorInternalsPageHandler>( + std::move(receiver), std::move(page), Profile::FromWebUI(web_ui())); +} + +WEB_UI_CONTROLLER_TYPE_IMPL(ContentAnnotatorInternalsUI) ContentAnnotatorInternalsUI::~ContentAnnotatorInternalsUI() = default; + +} // namespace content_annotator_internals
diff --git a/chrome/browser/ui/webui/content_annotator_internals/content_annotator_internals_ui.h b/chrome/browser/ui/webui/content_annotator_internals/content_annotator_internals_ui.h index be445c1..0d70eaa 100644 --- a/chrome/browser/ui/webui/content_annotator_internals/content_annotator_internals_ui.h +++ b/chrome/browser/ui/webui/content_annotator_internals/content_annotator_internals_ui.h
@@ -5,30 +5,62 @@ #ifndef CHROME_BROWSER_UI_WEBUI_CONTENT_ANNOTATOR_INTERNALS_CONTENT_ANNOTATOR_INTERNALS_UI_H_ #define CHROME_BROWSER_UI_WEBUI_CONTENT_ANNOTATOR_INTERNALS_CONTENT_ANNOTATOR_INTERNALS_UI_H_ +#include <memory> + #include "chrome/common/webui_url_constants.h" +#include "components/accessibility_annotator/core/logging/accessibility_annotator_internals.mojom.h" #include "content/public/browser/internal_webui_config.h" #include "content/public/browser/web_ui_controller.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 "ui/webui/mojo_web_ui_controller.h" +namespace content_annotator_internals { + class ContentAnnotatorInternalsUI; +class ContentAnnotatorInternalsPageHandler; // The WebUIConfig for chrome://content-annotator-internals class ContentAnnotatorInternalsUIConfig : public content::DefaultInternalWebUIConfig<ContentAnnotatorInternalsUI> { public: ContentAnnotatorInternalsUIConfig() - : content::DefaultInternalWebUIConfig<ContentAnnotatorInternalsUI>( + : DefaultInternalWebUIConfig( chrome::kChromeUIContentAnnotatorInternalsHost) {} }; // The WebUIController for chrome://content-annotator-internals -class ContentAnnotatorInternalsUI : public content::WebUIController { +class ContentAnnotatorInternalsUI + : public ui::MojoWebUIController, + public accessibility_annotator_internals::mojom::PageHandlerFactory { public: explicit ContentAnnotatorInternalsUI(content::WebUI* web_ui); ContentAnnotatorInternalsUI(const ContentAnnotatorInternalsUI&) = delete; ContentAnnotatorInternalsUI& operator=(const ContentAnnotatorInternalsUI&) = delete; ~ContentAnnotatorInternalsUI() override; + + void BindInterface( + mojo::PendingReceiver< + accessibility_annotator_internals::mojom::PageHandlerFactory> + receiver); + + // accessibility_annotator_internals::mojom::PageHandlerFactory: + void CreatePageHandler( + mojo::PendingRemote<accessibility_annotator_internals::mojom::Page> page, + mojo::PendingReceiver< + accessibility_annotator_internals::mojom::PageHandler> receiver) + override; + + private: + WEB_UI_CONTROLLER_TYPE_DECL(); + + std::unique_ptr<ContentAnnotatorInternalsPageHandler> page_handler_; + mojo::Receiver<accessibility_annotator_internals::mojom::PageHandlerFactory> + page_factory_receiver_{this}; }; +} // namespace content_annotator_internals + #endif // CHROME_BROWSER_UI_WEBUI_CONTENT_ANNOTATOR_INTERNALS_CONTENT_ANNOTATOR_INTERNALS_UI_H_
diff --git a/chrome/browser/ui/webui/cr_components/composebox/composebox_handler_unittest.cc b/chrome/browser/ui/webui/cr_components/composebox/composebox_handler_unittest.cc index a2fd0e9..23ee770 100644 --- a/chrome/browser/ui/webui/cr_components/composebox/composebox_handler_unittest.cc +++ b/chrome/browser/ui/webui/cr_components/composebox/composebox_handler_unittest.cc
@@ -231,7 +231,11 @@ // Submitting with deep search and Gemini regular model enabled. handler().SetActiveToolMode(omnibox::ToolMode::TOOL_MODE_DEEP_SEARCH); + handler().SetActiveToolMode(omnibox::ToolMode::TOOL_MODE_DEEP_SEARCH); + handler().RecordToolSelectionAction(omnibox::ToolMode::TOOL_MODE_DEEP_SEARCH); handler().SetActiveModelMode(omnibox::ModelMode::MODEL_MODE_GEMINI_REGULAR); + handler().RecordModelSelectionAction( + omnibox::ModelMode::MODEL_MODE_GEMINI_REGULAR); SubmitQueryAndWaitForNavigation(); histogram_tester().ExpectBucketCount( "ContextualSearch.Tools.ModeOnSubmission.NewTabPage", @@ -242,7 +246,10 @@ // Submitting with create image and Gemini Pro model enabled. handler().SetActiveToolMode(omnibox::ToolMode::TOOL_MODE_IMAGE_GEN); + handler().RecordToolSelectionAction(omnibox::ToolMode::TOOL_MODE_IMAGE_GEN); handler().SetActiveModelMode(omnibox::ModelMode::MODEL_MODE_GEMINI_PRO); + handler().RecordModelSelectionAction( + omnibox::ModelMode::MODEL_MODE_GEMINI_PRO); SubmitQueryAndWaitForNavigation(); histogram_tester().ExpectBucketCount( "ContextualSearch.Tools.ModeOnSubmission.NewTabPage",
diff --git a/chrome/browser/ui/webui/cr_components/history_embeddings/history_embeddings_handler_unittest.cc b/chrome/browser/ui/webui/cr_components/history_embeddings/history_embeddings_handler_unittest.cc index 603c220..973875ca 100644 --- a/chrome/browser/ui/webui/cr_components/history_embeddings/history_embeddings_handler_unittest.cc +++ b/chrome/browser/ui/webui/cr_components/history_embeddings/history_embeddings_handler_unittest.cc
@@ -322,7 +322,7 @@ *user_education(), MaybeShowFeaturePromo(user_education::test::MatchFeaturePromoParams( feature_engagement::kIPHHistorySearchFeature))) - .Times(1); + .WillOnce(testing::Return(true)); handler_->MaybeShowFeaturePromo(); }
diff --git a/chrome/browser/ui/webui/cr_components/searchbox/contextual_searchbox_handler.cc b/chrome/browser/ui/webui/cr_components/searchbox/contextual_searchbox_handler.cc index 448da57..f48f116 100644 --- a/chrome/browser/ui/webui/cr_components/searchbox/contextual_searchbox_handler.cc +++ b/chrome/browser/ui/webui/cr_components/searchbox/contextual_searchbox_handler.cc
@@ -487,25 +487,33 @@ if (!input_state_model_) { return; } + input_state_model_->setActiveTool(tool); +} + +void ContextualSearchboxHandler::RecordToolSelectionAction( + omnibox::ToolMode tool) { if (auto* metrics_recorder = GetMetricsRecorder()) { composebox_query::mojom::ToolMode mojom_tool_mode = mojo::EnumTraits<composebox_query::mojom::ToolMode, omnibox::ToolMode>::ToMojom(tool); metrics_recorder->RecordToolMode(mojom_tool_mode); } - input_state_model_->setActiveTool(tool); } -void ContextualSearchboxHandler::SetActiveModelMode(omnibox::ModelMode model) { - if (!input_state_model_) { - return; - } +void ContextualSearchboxHandler::RecordModelSelectionAction( + omnibox::ModelMode model) { if (auto* metrics_recorder = GetMetricsRecorder()) { composebox_query::mojom::ModelMode mojom_model_mode = mojo::EnumTraits<composebox_query::mojom::ModelMode, omnibox::ModelMode>::ToMojom(model); metrics_recorder->RecordModelMode(mojom_model_mode); } +} + +void ContextualSearchboxHandler::SetActiveModelMode(omnibox::ModelMode model) { + if (!input_state_model_) { + return; + } input_state_model_->setActiveModel(model); } @@ -694,17 +702,20 @@ bool shift_key) { const AutocompleteMatch* match = GetMatchWithUrl(line, url); - // Record zero suggest clicks for composebox matches. - bool record_zero_suggest = - autocomplete_controller()->input().IsZeroSuggest() && + // Record match navigations for composebox matches. + bool is_zero_suggest = autocomplete_controller()->input().IsZeroSuggest(); + auto* recorder = GetMetricsRecorder(); + bool record_composebox_metric = omnibox::IsComposebox( omnibox_controller()->client()->GetPageClassification( /*is_prefetch=*/false)) && - match; + match && recorder; - if (record_zero_suggest) { - if (auto* recorder = GetMetricsRecorder()) { + if (record_composebox_metric) { + if (is_zero_suggest) { recorder->RecordZeroSuggestClick(match->IsContextualSearchSuggestion()); + } else { + recorder->RecordTypedSuggestNavigation(match->IsVerbatimType()); } }
diff --git a/chrome/browser/ui/webui/cr_components/searchbox/contextual_searchbox_handler.h b/chrome/browser/ui/webui/cr_components/searchbox/contextual_searchbox_handler.h index 820b0f5..3386d42 100644 --- a/chrome/browser/ui/webui/cr_components/searchbox/contextual_searchbox_handler.h +++ b/chrome/browser/ui/webui/cr_components/searchbox/contextual_searchbox_handler.h
@@ -182,7 +182,9 @@ // Resets `input_state_model_`. void ResetInputStateModel(); void SetActiveToolMode(omnibox::ToolMode tool) override; + void RecordToolSelectionAction(omnibox::ToolMode tool) override; void SetActiveModelMode(omnibox::ModelMode model) override; + void RecordModelSelectionAction(omnibox::ModelMode model) override; void ActivateMetricsFunnel(const std::string& funnel_name) override; void OnInputStateChangedForTesting( @@ -216,6 +218,8 @@ DeleteContext_DelayUpload); FRIEND_TEST_ALL_PREFIXES(ContextualSearchboxHandlerTest, OpenAutocompleteMatch_ZeroSuggestClick); + FRIEND_TEST_ALL_PREFIXES(ContextualSearchboxHandlerTest, + OpenAutocompleteMatch_TypedSuggestNavigation); std::optional<lens::ImageEncodingOptions> CreateTabPreviewEncodingOptions( content::WebContents* web_contents);
diff --git a/chrome/browser/ui/webui/cr_components/searchbox/searchbox_handler.cc b/chrome/browser/ui/webui/cr_components/searchbox/searchbox_handler.cc index c99a747..eab01470 100644 --- a/chrome/browser/ui/webui/cr_components/searchbox/searchbox_handler.cc +++ b/chrome/browser/ui/webui/cr_components/searchbox/searchbox_handler.cc
@@ -6,6 +6,7 @@ #include "base/base64.h" #include "base/base64url.h" +#include "base/containers/fixed_flat_map.h" #include "base/feature_list.h" #include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" @@ -436,15 +437,13 @@ source->AddBoolean("searchboxCr23SteadyStateShadow", ntp_features::kNtpRealboxCr23SteadyStateShadow.Get()); - auto composebox_config = ntp_composebox::FeatureConfig::Get().config; - int max_images = 0; - int max_pdfs = 0; - int max_files = 0; + int max_files = 10; + int max_images = max_files; + int max_pdfs = max_files; AimEligibilityService* service = AimEligibilityServiceFactory::GetForProfile(profile); const omnibox::SearchboxConfig* config = service ? service->GetSearchboxConfig() : nullptr; - if (config && config->has_rule_set()) { max_files = config->rule_set().max_total_inputs(); for (const auto& rule : config->rule_set().input_type_rules()) { @@ -456,30 +455,22 @@ } } - source->AddString( - "composeboxDragAndDropHint", - l10n_util::GetPluralStringFUTF16( - IDS_NTP_COMPOSE_DRAG_AND_DROP_HINT, - max_files > 0 ? max_files - : composebox_config.composebox().max_num_files())); - source->AddString( - "maxFilesReachedError", - l10n_util::GetPluralStringFUTF16( - IDS_NTP_COMPOSE_MAX_FILES_REACHED_ERROR, - max_files > 0 ? max_files - : composebox_config.composebox().max_num_files())); - source->AddString( - "maxImagesReachedError", - l10n_util::GetPluralStringFUTF16( - IDS_NTP_COMPOSE_MAX_IMAGES_REACHED_ERROR, - max_images > 0 ? max_images - : composebox_config.composebox().max_num_files())); - source->AddString( - "maxPdfsReachedError", - l10n_util::GetPluralStringFUTF16( - IDS_NTP_COMPOSE_MAX_PDFS_REACHED_ERROR, - max_pdfs > 0 ? max_pdfs - : composebox_config.composebox().max_num_files())); + source->AddInteger("composeboxFileMaxCount", max_files); + source->AddString("composeboxDragAndDropHint", + l10n_util::GetPluralStringFUTF16( + IDS_NTP_COMPOSE_DRAG_AND_DROP_HINT, max_files)); + source->AddString("maxFilesReachedError", + l10n_util::GetPluralStringFUTF16( + IDS_NTP_COMPOSE_MAX_FILES_REACHED_ERROR, max_files)); + source->AddString("maxImagesReachedError", + l10n_util::GetPluralStringFUTF16( + IDS_NTP_COMPOSE_MAX_IMAGES_REACHED_ERROR, max_images)); + source->AddString("maxPdfsReachedError", + l10n_util::GetPluralStringFUTF16( + IDS_NTP_COMPOSE_MAX_PDFS_REACHED_ERROR, max_pdfs)); + + // TODO(b/481663895): Remove "ConfigParam" from Next studies. + auto composebox_config = ntp_composebox::FeatureConfig::Get().config; source->AddBoolean( "searchboxShowComposeAnimation", profile->GetPrefs()->GetInteger( @@ -1145,49 +1136,41 @@ void SearchboxHandler::GetPlaceholderConfig( GetPlaceholderConfigCallback callback) { - const auto placeholder_config = ntp_composebox::FeatureConfig::Get() - .config.composebox() - .placeholder_config(); - std::vector<std::u16string> placeholders = {}; - for (auto& text : placeholder_config.placeholders()) { - switch (text) { - case omnibox::NTPComposeboxConfig_PlaceholderConfig_Placeholder_ASK: - placeholders.emplace_back(l10n_util::GetStringUTF16( - IDS_NTP_SEARCH_BOX_DYNAMIC_PLACEHOLDER_ASK_GOOGLE)); - break; - case omnibox::NTPComposeboxConfig_PlaceholderConfig_Placeholder_PLAN: - placeholders.emplace_back(l10n_util::GetStringUTF16( - IDS_NTP_SEARCH_BOX_DYNAMIC_PLACEHOLDER_PLAN)); - break; - case omnibox::NTPComposeboxConfig_PlaceholderConfig_Placeholder_COMPARE: - placeholders.emplace_back(l10n_util::GetStringUTF16( - IDS_NTP_SEARCH_BOX_DYNAMIC_PLACEHOLDER_COMPARE)); - break; - case omnibox::NTPComposeboxConfig_PlaceholderConfig_Placeholder_RESEARCH: - placeholders.emplace_back(l10n_util::GetStringUTF16( - IDS_NTP_SEARCH_BOX_DYNAMIC_PLACEHOLDER_RESEARCH)); - break; - case omnibox::NTPComposeboxConfig_PlaceholderConfig_Placeholder_TEACH: - placeholders.emplace_back(l10n_util::GetStringUTF16( - IDS_NTP_SEARCH_BOX_DYNAMIC_PLACEHOLDER_TEACH)); - break; - case omnibox::NTPComposeboxConfig_PlaceholderConfig_Placeholder_WRITE: - placeholders.emplace_back(l10n_util::GetStringUTF16( - IDS_NTP_SEARCH_BOX_DYNAMIC_PLACEHOLDER_WRITE)); - break; - case omnibox::NTPComposeboxConfig_PlaceholderConfig_Placeholder_IMAGE: - placeholders.emplace_back(l10n_util::GetStringUTF16( - IDS_NTP_SEARCH_BOX_DYNAMIC_PLACEHOLDER_IMAGE)); - break; - case omnibox::NTPComposeboxConfig_PlaceholderConfig_Placeholder_ASK_TAB: - placeholders.emplace_back(l10n_util::GetStringUTF16( - IDS_NTP_SEARCH_BOX_DYNAMIC_PLACEHOLDER_TAB)); - break; - default: - NOTREACHED(); + std::vector<std::u16string> placeholders; + + // Try PEC API first to get the dynamic placeholder text. + AimEligibilityService* service = + AimEligibilityServiceFactory::GetForProfile(profile_); + + const omnibox::SearchboxConfig* searchbox_config = + service ? service->GetSearchboxConfig() : nullptr; + + if (searchbox_config) { + // Non-tool-dependent: always first per UX spec. + placeholders.emplace_back(l10n_util::GetStringUTF16( + IDS_NTP_SEARCH_BOX_DYNAMIC_PLACEHOLDER_ASK_GOOGLE)); + + static constexpr auto kToolPlaceholderMap = + base::MakeFixedFlatMap<omnibox::ToolMode, int>({ + {omnibox::TOOL_MODE_IMAGE_GEN, + IDS_NTP_SEARCH_BOX_DYNAMIC_PLACEHOLDER_IMAGE}, + {omnibox::TOOL_MODE_DEEP_SEARCH, + IDS_NTP_SEARCH_BOX_DYNAMIC_PLACEHOLDER_RESEARCH}, + {omnibox::TOOL_MODE_CANVAS, + IDS_NTP_SEARCH_BOX_DYNAMIC_PLACEHOLDER_CANVAS}, + }); + + for (const auto& tool_config : searchbox_config->tool_configs()) { + auto it = kToolPlaceholderMap.find(tool_config.tool()); + if (it != kToolPlaceholderMap.end()) { + placeholders.emplace_back(l10n_util::GetStringUTF16(it->second)); + } } } + const auto placeholder_config = ntp_composebox::FeatureConfig::Get() + .config.composebox() + .placeholder_config(); searchbox::mojom::PlaceholderConfigPtr config = searchbox::mojom::PlaceholderConfig::New(); config->texts = std::move(placeholders);
diff --git a/chrome/browser/ui/webui/cr_components/searchbox/searchbox_handler.h b/chrome/browser/ui/webui/cr_components/searchbox/searchbox_handler.h index 78b1fed..72aa94e 100644 --- a/chrome/browser/ui/webui/cr_components/searchbox/searchbox_handler.h +++ b/chrome/browser/ui/webui/cr_components/searchbox/searchbox_handler.h
@@ -137,7 +137,9 @@ bool shift_key) override {} void OpenLensSearch() override {} void SetActiveToolMode(omnibox::ToolMode tool) override {} + void RecordToolSelectionAction(omnibox::ToolMode tool) override {} void SetActiveModelMode(omnibox::ModelMode model) override {} + void RecordModelSelectionAction(omnibox::ModelMode model) override {} void ActivateMetricsFunnel(const std::string& funnel_name) override {} // Stores `callback` to be run when the page remote is bound and ready to
diff --git a/chrome/browser/ui/webui/new_tab_page/composebox/variations/composebox_fieldtrial.cc b/chrome/browser/ui/webui/new_tab_page/composebox/variations/composebox_fieldtrial.cc index 7cdec284..ccba5dc 100644 --- a/chrome/browser/ui/webui/new_tab_page/composebox/variations/composebox_fieldtrial.cc +++ b/chrome/browser/ui/webui/new_tab_page/composebox/variations/composebox_fieldtrial.cc
@@ -50,8 +50,6 @@ default_config.mutable_entry_point()->set_num_page_load_animations(3); auto* composebox = default_config.mutable_composebox(); - composebox->set_close_by_escape(kCloseComposeboxByEscape.Get()); - composebox->set_close_by_click_outside(kCloseComposeboxByClickOutside.Get()); auto* image_upload = composebox->mutable_image_upload(); image_upload->set_enable_webp_encoding(false); @@ -67,7 +65,6 @@ attachment_upload->set_max_size_bytes(200000000); attachment_upload->set_mime_types_allowed(".pdf,application/pdf"); - composebox->set_max_num_files(kMaxNumFiles.Get()); composebox->set_input_placeholder_text( l10n_util::GetStringUTF8(IDS_NTP_COMPOSE_PLACEHOLDER_TEXT)); composebox->set_is_pdf_upload_enabled(true);
diff --git a/chrome/browser/ui/webui/new_tab_page/composebox/variations/composebox_fieldtrial_config_unittest.cc b/chrome/browser/ui/webui/new_tab_page/composebox/variations/composebox_fieldtrial_config_unittest.cc index 55e33c6..9303d8c 100644 --- a/chrome/browser/ui/webui/new_tab_page/composebox/variations/composebox_fieldtrial_config_unittest.cc +++ b/chrome/browser/ui/webui/new_tab_page/composebox/variations/composebox_fieldtrial_config_unittest.cc
@@ -63,8 +63,6 @@ EXPECT_EQ(config.entry_point().num_page_load_animations(), 3); auto composebox = config.composebox(); - EXPECT_FALSE(composebox.close_by_escape()); - EXPECT_FALSE(composebox.close_by_click_outside()); auto image_upload = config.composebox().image_upload(); EXPECT_EQ(image_upload.enable_webp_encoding(), false); @@ -80,7 +78,6 @@ EXPECT_EQ(attachment_upload.max_size_bytes(), 200000000); EXPECT_THAT(attachment_upload.mime_types_allowed(), ".pdf,application/pdf"); - EXPECT_EQ(composebox.max_num_files(), 10); EXPECT_EQ(composebox.input_placeholder_text(), l10n_util::GetStringUTF8(IDS_NTP_COMPOSE_PLACEHOLDER_TEXT)); EXPECT_EQ(composebox.is_pdf_upload_enabled(), true);
diff --git a/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc b/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc index 93a96ca..862c0b8 100644 --- a/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc +++ b/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc
@@ -250,6 +250,12 @@ source->AddBoolean("logoEnabled", base::FeatureList::IsEnabled(ntp_features::kNtpLogo)); source->AddBoolean( + "animatedDoodlesEnabled", + base::FeatureList::IsEnabled(ntp_features::kNtpAnimatedDoodles)); + source->AddBoolean( + "doodleMuralsEnabled", + base::FeatureList::IsEnabled(ntp_features::kNtpDoodleMurals)); + source->AddBoolean( "middleSlotPromoEnabled", base::FeatureList::IsEnabled(ntp_features::kNtpMiddleSlotPromo) && profile->GetPrefs()->GetBoolean(prefs::kNtpPromoVisible)); @@ -618,8 +624,6 @@ source->AddString("composeboxAttachmentFileTypes", attachment_mime_types); source->AddInteger("composeboxFileMaxSize", composebox_config.attachment_upload().max_size_bytes()); - source->AddInteger("composeboxFileMaxCount", - composebox_config.max_num_files()); source->AddString( "composeboxSource", contextual_search::ContextualSearchMetricsRecorder::
diff --git a/chrome/browser/ui/webui/omnibox_popup/omnibox_popup_ui.cc b/chrome/browser/ui/webui/omnibox_popup/omnibox_popup_ui.cc index e596e62d..cd95931 100644 --- a/chrome/browser/ui/webui/omnibox_popup/omnibox_popup_ui.cc +++ b/chrome/browser/ui/webui/omnibox_popup/omnibox_popup_ui.cc
@@ -104,18 +104,8 @@ const std::string attachment_mime_types = composebox_config.attachment_upload().mime_types_allowed(); source->AddString("composeboxAttachmentFileTypes", attachment_mime_types); - source->AddInteger("composeboxFileMaxCount", - composebox_config.max_num_files()); source->AddInteger("composeboxFileMaxSize", composebox_config.attachment_upload().max_size_bytes()); - source->AddString( - "composeboxDragAndDropHint", - l10n_util::GetPluralStringFUTF16(IDS_NTP_COMPOSE_DRAG_AND_DROP_HINT, - composebox_config.max_num_files())); - source->AddString( - "maxFilesReachedError", - l10n_util::GetPluralStringFUTF16(IDS_NTP_COMPOSE_MAX_FILES_REACHED_ERROR, - composebox_config.max_num_files())); const std::string image_mime_types = composebox_config.image_upload().mime_types_allowed(); source->AddString("composeboxImageFileTypes", image_mime_types);
diff --git a/chrome/browser/ui/webui/searchbox/contextual_searchbox_handler_unittest.cc b/chrome/browser/ui/webui/searchbox/contextual_searchbox_handler_unittest.cc index 297ad4d..462e2b4 100644 --- a/chrome/browser/ui/webui/searchbox/contextual_searchbox_handler_unittest.cc +++ b/chrome/browser/ui/webui/searchbox/contextual_searchbox_handler_unittest.cc
@@ -693,7 +693,8 @@ GetMetricsRecorderPtr(), &MockContextualSearchMetricsRecorder::RecordToolModeBase)); - handler().SetActiveToolMode(omnibox::ToolMode::TOOL_MODE_CANVAS); + handler_->SetActiveToolMode(omnibox::ToolMode::TOOL_MODE_CANVAS); + handler_->RecordToolSelectionAction(omnibox::ToolMode::TOOL_MODE_CANVAS); mock_searchbox_page_.FlushForTesting(); EXPECT_EQ(received_state_1.active_tool, omnibox::ToolMode::TOOL_MODE_CANVAS); histogram_tester().ExpectUniqueSample( @@ -708,6 +709,8 @@ &MockContextualSearchMetricsRecorder::RecordModelModeBase)); handler().SetActiveModelMode(omnibox::ModelMode::MODEL_MODE_GEMINI_REGULAR); + handler().RecordModelSelectionAction( + omnibox::ModelMode::MODEL_MODE_GEMINI_REGULAR); mock_searchbox_page_.FlushForTesting(); EXPECT_EQ(received_state_2.active_tool, omnibox::ToolMode::TOOL_MODE_CANVAS); EXPECT_EQ(received_state_2.active_model, @@ -798,6 +801,95 @@ } } +TEST_F(ContextualSearchboxHandlerTest, + OpenAutocompleteMatch_TypedSuggestNavigation) { + base::UserActionTester user_action_tester; + + // Set up a typed input (non-zero suggest). + AutocompleteInput input(u"test", + metrics::OmniboxEventProto::NTP_OMNIBOX_COMPOSEBOX, + ChromeAutocompleteSchemeClassifier(profile())); + + // Set the page classification on the client's location bar model. + static_cast<TestOmniboxClient*>(handler().omnibox_controller()->client()) + ->location_bar_model() + ->set_page_classification( + metrics::OmniboxEventProto::NTP_OMNIBOX_COMPOSEBOX); + + // 1. Test verbatim typed click (line == 0). + { + auto fake_controller = + std::make_unique<FakeAutocompleteController>(nullptr); + fake_controller->input_ = input; + + AutocompleteMatch match; + match.provider = &fake_controller->GetFakeProvider(); + match.destination_url = GURL("https://www.google.com"); + match.type = AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED; + + fake_controller->published_result_.AppendMatches({match}); + + handler().omnibox_controller()->SetAutocompleteControllerForTesting( + std::move(fake_controller)); + + EXPECT_CALL(*GetMetricsRecorderPtr(), RecordTypedSuggestNavigation(true)) + .WillOnce(testing::Invoke(GetMetricsRecorderPtr(), + &MockContextualSearchMetricsRecorder:: + RecordTypedSuggestNavigationBase)); + + handler().OpenAutocompleteMatch(0, GURL("https://www.google.com"), + /*are_matches_showing=*/true, 0, false, + false, false, false); + + histogram_tester().ExpectBucketCount( + "ContextualSearch.TypedSuggestNavigation.IsVerbatim.NewTabPage", true, + 1); + EXPECT_EQ( + user_action_tester.GetActionCount( + "ContextualSearch.TypedSuggestNavigation.Verbatim.NewTabPage"), + 1); + } + + // 2. Test non-verbatim typed click (line != 0). + { + auto fake_controller = + std::make_unique<FakeAutocompleteController>(nullptr); + fake_controller->input_ = input; + + AutocompleteMatch match0; + match0.provider = &fake_controller->GetFakeProvider(); + match0.destination_url = GURL("https://www.google.com"); + match0.type = AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED; + + AutocompleteMatch match1; + match1.provider = &fake_controller->GetFakeProvider(); + match1.destination_url = GURL("https://www.google.com/search?q=suggestion"); + match1.type = AutocompleteMatchType::SEARCH_SUGGEST; + + fake_controller->published_result_.AppendMatches({match0, match1}); + + handler().omnibox_controller()->SetAutocompleteControllerForTesting( + std::move(fake_controller)); + + EXPECT_CALL(*GetMetricsRecorderPtr(), RecordTypedSuggestNavigation(false)) + .WillOnce(testing::Invoke(GetMetricsRecorderPtr(), + &MockContextualSearchMetricsRecorder:: + RecordTypedSuggestNavigationBase)); + + handler().OpenAutocompleteMatch( + 1, GURL("https://www.google.com/search?q=suggestion"), + /*are_matches_showing=*/true, 0, false, false, false, false); + + histogram_tester().ExpectBucketCount( + "ContextualSearch.TypedSuggestNavigation.IsVerbatim.NewTabPage", false, + 1); + EXPECT_EQ( + user_action_tester.GetActionCount( + "ContextualSearch.TypedSuggestNavigation.SearchSuggest.NewTabPage"), + 1); + } +} + TEST_F(ContextualSearchboxHandlerTest, SubmitQueryWithAdditionalParams) { // Ensure udm param is always set as an additional param. SubmitQueryAndWaitForNavigation();
diff --git a/chrome/browser/ui/webui/searchbox/contextual_searchbox_test_utils.h b/chrome/browser/ui/webui/searchbox/contextual_searchbox_test_utils.h index f157aa9e..efcc98d6 100644 --- a/chrome/browser/ui/webui/searchbox/contextual_searchbox_test_utils.h +++ b/chrome/browser/ui/webui/searchbox/contextual_searchbox_test_utils.h
@@ -154,6 +154,10 @@ composebox_query::mojom::ModelMode model_mode), (override)); MOCK_METHOD(void, RecordZeroSuggestClick, (bool is_contextual), (override)); + MOCK_METHOD(void, + RecordTypedSuggestNavigation, + (bool is_verbatim), + (override)); void NotifySessionStateChangedBase( contextual_search::SessionState session_state) { @@ -186,6 +190,10 @@ void RecordZeroSuggestClickBase(bool is_contextual) { ContextualSearchMetricsRecorder::RecordZeroSuggestClick(is_contextual); } + + void RecordTypedSuggestNavigationBase(bool is_verbatim) { + ContextualSearchMetricsRecorder::RecordTypedSuggestNavigation(is_verbatim); + } }; class ContextualSearchboxHandlerTestHarness
diff --git a/chrome/browser/ui/webui/searchbox/searchbox_handler_unittest.cc b/chrome/browser/ui/webui/searchbox/searchbox_handler_unittest.cc index 83011765..4a9aa55 100644 --- a/chrome/browser/ui/webui/searchbox/searchbox_handler_unittest.cc +++ b/chrome/browser/ui/webui/searchbox/searchbox_handler_unittest.cc
@@ -9,6 +9,7 @@ #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" #include "base/test/test_future.h" +#include "chrome/browser/autocomplete/aim_eligibility_service_factory.h" #include "chrome/browser/ui/browser_window/test/mock_browser_window_interface.h" #include "chrome/browser/ui/contextual_search/tab_contextualization_controller.h" #include "chrome/browser/ui/omnibox/omnibox_controller.h" @@ -24,6 +25,7 @@ #include "chrome/browser/ui/webui/webui_embedding_context.h" #include "chrome/test/base/testing_profile.h" #include "components/omnibox/browser/autocomplete_controller.h" +#include "components/omnibox/browser/mock_aim_eligibility_service.h" #include "components/omnibox/browser/mock_autocomplete_provider_client.h" #include "components/omnibox/browser/omnibox_prefs.h" #include "components/omnibox/browser/test_omnibox_client.h" @@ -42,6 +44,11 @@ #include "testing/gtest/include/gtest/gtest.h" #include "third_party/metrics_proto/omnibox_event.pb.h" #include "third_party/metrics_proto/omnibox_focus_type.pb.h" +#include "third_party/omnibox_proto/model_config.pb.h" +#include "third_party/omnibox_proto/model_mode.pb.h" +#include "third_party/omnibox_proto/searchbox_config.pb.h" +#include "third_party/omnibox_proto/tool_config.pb.h" +#include "third_party/omnibox_proto/tool_mode.pb.h" #include "ui/base/webui/web_ui_util.h" class SearchboxHandlerTest : public ::testing::Test { @@ -201,16 +208,115 @@ } } -TEST_F(RealboxHandlerTest, GetPlaceholderConfig) { +TEST_F(RealboxHandlerTest, GetPlaceholderConfig_NoPecApiReturnsEmpty) { base::test::TestFuture<searchbox::mojom::PlaceholderConfigPtr> future; handler_->GetPlaceholderConfig(future.GetCallback()); auto config = future.Take(); - ASSERT_GT(config->texts.size(), 0u); + ASSERT_EQ(config->texts.size(), 0u); ASSERT_EQ(config->change_text_animation_interval.InMilliseconds(), 2000u); ASSERT_EQ(config->fade_text_animation_duration.InMilliseconds(), 250u); } +namespace { +std::unique_ptr<KeyedService> BuildMockAimEligibilityService( + content::BrowserContext* context) { + auto* profile = Profile::FromBrowserContext(context); + auto service = std::make_unique<testing::NiceMock<MockAimEligibilityService>>( + *profile->GetPrefs(), + /*template_url_service=*/nullptr, + /*url_loader_factory=*/nullptr, + /*identity_manager=*/nullptr, AimEligibilityService::Configuration{}); + return service; +} +} // namespace + +class SearchboxHandlerPecApiTest : public RealboxHandlerTest { + public: + SearchboxHandlerPecApiTest() = default; + ~SearchboxHandlerPecApiTest() override = default; + + protected: + raw_ptr<testing::NiceMock<MockAimEligibilityService>> + mock_aim_eligibility_service_ = nullptr; + + void SetUp() override { + SearchboxHandlerTest::SetUp(); + + AimEligibilityServiceFactory::GetInstance()->SetTestingFactory( + profile(), base::BindRepeating(&BuildMockAimEligibilityService)); + + mock_aim_eligibility_service_ = + static_cast<testing::NiceMock<MockAimEligibilityService>*>( + AimEligibilityServiceFactory::GetForProfile(profile())); + + web_contents_ = + content::WebContentsTester::CreateTestWebContents(profile(), nullptr); + handler_ = std::make_unique<RealboxHandler>( + mojo::PendingReceiver<searchbox::mojom::PageHandler>(), profile(), + web_contents_.get(), + base::BindLambdaForTesting( + []() -> contextual_search::ContextualSearchSessionHandle* { + return nullptr; + })); + handler_->SetPage(page_.BindAndGetRemote()); + } + + void TearDown() override { + mock_aim_eligibility_service_ = nullptr; + RealboxHandlerTest::TearDown(); + } +}; + +TEST_F(SearchboxHandlerPecApiTest, GetPlaceholderConfig_WithToolConfigs) { + omnibox::SearchboxConfig& config = mock_aim_eligibility_service_->config(); + + auto* tool = config.add_tool_configs(); + tool->set_tool(omnibox::TOOL_MODE_IMAGE_GEN); + + auto* tool2 = config.add_tool_configs(); + tool2->set_tool(omnibox::TOOL_MODE_CANVAS); + + ON_CALL(*mock_aim_eligibility_service_, GetSearchboxConfig()) + .WillByDefault(testing::Return(&config)); + + base::test::TestFuture<searchbox::mojom::PlaceholderConfigPtr> future; + handler_->GetPlaceholderConfig(future.GetCallback()); + auto result = future.Take(); + + ASSERT_EQ(result->texts.size(), 3u); + EXPECT_EQ(result->texts[0], u"Ask Google"); + EXPECT_EQ(result->texts[1], u"Describe your image"); + EXPECT_EQ(result->texts[2], u"Create anything"); +} + +TEST_F(SearchboxHandlerPecApiTest, + GetPlaceholderConfig_EmptySearchboxConfigReturnsAskGoogleOnly) { + omnibox::SearchboxConfig& config = mock_aim_eligibility_service_->config(); + + ON_CALL(*mock_aim_eligibility_service_, GetSearchboxConfig()) + .WillByDefault(testing::Return(&config)); + + base::test::TestFuture<searchbox::mojom::PlaceholderConfigPtr> future; + handler_->GetPlaceholderConfig(future.GetCallback()); + auto result = future.Take(); + + ASSERT_EQ(result->texts.size(), 1u); + EXPECT_EQ(result->texts[0], u"Ask Google"); +} + +TEST_F(SearchboxHandlerPecApiTest, + GetPlaceholderConfig_NullSearchboxConfigReturnsEmpty) { + ON_CALL(*mock_aim_eligibility_service_, GetSearchboxConfig()) + .WillByDefault(testing::Return(nullptr)); + + base::test::TestFuture<searchbox::mojom::PlaceholderConfigPtr> future; + handler_->GetPlaceholderConfig(future.GetCallback()); + auto result = future.Take(); + + ASSERT_EQ(result->texts.size(), 0u); +} + TEST_F(RealboxHandlerTest, AddFileContext) { const auto token = base::UnguessableToken::Create(); const std::string image_data_url = "data:image/png;base64,sometestdata";
diff --git a/chrome/browser/ui/webui/settings/settings_interactive_uitest.cc b/chrome/browser/ui/webui/settings/settings_interactive_uitest.cc index 0e4dfb39..64fb8d6c 100644 --- a/chrome/browser/ui/webui/settings/settings_interactive_uitest.cc +++ b/chrome/browser/ui/webui/settings/settings_interactive_uitest.cc
@@ -4,10 +4,12 @@ #include "base/feature_list.h" #include "base/test/bind.h" +#include "base/test/run_until.h" #include "chrome/browser/themes/theme_service.h" #include "chrome/browser/themes/theme_service_factory.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/interaction/browser_elements.h" +#include "chrome/browser/ui/ui_features.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/url_constants.h" #include "chrome/test/base/in_process_browser_test.h" @@ -24,6 +26,12 @@ #include "ui/base/interaction/interaction_test_util_mac.h" #endif +#if BUILDFLAG(IS_WIN) +#include "base/test/test_reg_util_win.h" +#include "chrome/browser/win/isolated_browser_support.h" +#include "chrome/install_static/test/scoped_install_details.h" +#endif // BUILDFLAG(IS_WIN) + namespace { DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kWebContentsInteractionTestUtilTestId); DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kWebContentsInteractionTestUtilTestId2); @@ -220,3 +228,55 @@ EXPECT_CALL_IN_SCOPE(completed, Run, sequence->RunSynchronouslyForTesting()); } + +#if BUILDFLAG(IS_WIN) +class SystemSettingsInteractiveUiTest : public SettingsInteractiveUiTest { + protected: + void SetUpInProcessBrowserTestFixture() override { + ASSERT_NO_FATAL_FAILURE( + registry_override_manager_.OverrideRegistry(HKEY_CURRENT_USER)); + scoped_feature_list_.InitAndEnableFeature( + features::kProcessIsolationSettings); + SettingsInteractiveUiTest::SetUpInProcessBrowserTestFixture(); + } + + install_static::ScopedInstallDetails scoped_install_details_{ + /*system_level=*/true}; + registry_util::RegistryOverrideManager registry_override_manager_; + base::test::ScopedFeatureList scoped_feature_list_; +}; + +IN_PROC_BROWSER_TEST_F(SystemSettingsInteractiveUiTest, + TogglesProcessIsolation) { + UNCALLED_MOCK_CALLBACK(ui::InteractionSequence::CompletedCallback, completed); + UNCALLED_MOCK_CALLBACK(ui::InteractionSequence::AbortedCallback, aborted); + + // Check initial state. + EXPECT_FALSE(chrome::IsIsolationEnabled()); + + const GURL system_settings_url("chrome://settings/system"); + const WebContentsInteractionTestUtil::DeepQuery toggle = { + "settings-ui", "settings-main", "settings-system-page", "#isolationState", + "#control"}; + + auto util = WebContentsInteractionTestUtil::ForExistingTabInBrowser( + browser(), kWebContentsInteractionTestUtilTestId); + util->LoadPage(system_settings_url); + + auto sequence = + ui::InteractionSequence::Builder() + .SetCompletedCallback(completed.Get()) + .SetAbortedCallback(aborted.Get()) + .SetContext(BrowserElements::From(browser())->GetContext()) + .AddStep(WaitFor(toggle)) + .AddStep(Click(toggle)) + .Build(); + + EXPECT_CALL_IN_SCOPE(completed, Run, sequence->RunSynchronouslyForTesting()); + + // Wait until it actually takes effect via the asynchronous SetIsolationState. + EXPECT_TRUE( + base::test::RunUntil([]() { return chrome::IsIsolationEnabled(); })); +} + +#endif // BUILDFLAG(IS_WIN)
diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc index 2d7d6b0..5b1d1b2 100644 --- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc +++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
@@ -4037,6 +4037,9 @@ #endif {"hardwareAccelerationLabel", IDS_SETTINGS_SYSTEM_HARDWARE_ACCELERATION_LABEL}, +#if BUILDFLAG(IS_WIN) + {"isolationStateLabel", IDS_SETTINGS_SYSTEM_ISOLATION_STATE_LABEL}, +#endif // BUILDFLAG(IS_WIN) {"proxySettingsLabel", IDS_SETTINGS_SYSTEM_PROXY_SETTINGS_LABEL}, #if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) {"featureNotificationsLabel", @@ -4049,6 +4052,11 @@ }; html_source->AddLocalizedStrings(kLocalizedStrings); +#if BUILDFLAG(IS_WIN) + html_source->AddString("isolationStateLearnMoreUrl", + chrome::kProcessIsolationLearnMoreUrl); +#endif // BUILDFLAG(IS_WIN) + html_source->AddString( "proxySettingsExtensionLabel", l10n_util::GetStringFUTF16( @@ -4072,6 +4080,14 @@ l10n_util::GetStringUTF16( IDS_SETTINGS_SYSTEM_PROXY_SETTINGS_YOUR_DEVICE_LABEL)); +#if BUILDFLAG(IS_WIN) + html_source->AddString( + "isolationStateSubLabel", + l10n_util::GetStringFUTF16( + IDS_SETTINGS_SYSTEM_ISOLATION_STATE_SUBLABEL, + l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME))); +#endif // BUILDFLAG(IS_WIN) + #if BUILDFLAG(GOOGLE_CHROME_BRANDING) html_source->AddString("onDeviceAiLearnMoreUrl", chrome::kOnDeviceAiLearnMoreUrl);
diff --git a/chrome/browser/ui/webui/settings/settings_ui.cc b/chrome/browser/ui/webui/settings/settings_ui.cc index 2a92b6a2..fd1df58 100644 --- a/chrome/browser/ui/webui/settings/settings_ui.cc +++ b/chrome/browser/ui/webui/settings/settings_ui.cc
@@ -193,6 +193,10 @@ #include "chrome/browser/ui/webui/settings/mac_system_settings_handler.h" #endif +#if BUILDFLAG(IS_WIN) +#include "chrome/install_static/install_util.h" +#endif // BUILDFLAG(IS_WIN) + #if BUILDFLAG(ENABLE_VR) #include "device/vr/public/cpp/features.h" #endif @@ -542,6 +546,13 @@ base::FeatureList::IsEnabled(features::kRegisterOsUpdateHandlerWin)); #endif // BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) +#if BUILDFLAG(IS_WIN) + html_source->AddBoolean( + "showProcessIsolationSetting", + base::FeatureList::IsEnabled(features::kProcessIsolationSettings) && + install_static::IsSystemInstall()); +#endif // BUILDFLAG(IS_WIN) + html_source->AddBoolean( "enableWebAppInstallation", base::FeatureList::IsEnabled(blink::features::kWebAppInstallation));
diff --git a/chrome/browser/ui/webui/side_panel/read_anything/read_anything_untrusted_page_handler.cc b/chrome/browser/ui/webui/side_panel/read_anything/read_anything_untrusted_page_handler.cc index 1938b87..41f45cb 100644 --- a/chrome/browser/ui/webui/side_panel/read_anything/read_anything_untrusted_page_handler.cc +++ b/chrome/browser/ui/webui/side_panel/read_anything/read_anything_untrusted_page_handler.cc
@@ -60,6 +60,7 @@ #include "content/public/browser/web_ui.h" #include "content/public/common/content_switches.h" #include "content/public/common/url_constants.h" +#include "extensions/browser/extension_registrar.h" #include "extensions/browser/extension_registry.h" #include "net/http/http_status_code.h" #include "pdf/buildflags.h" @@ -1016,6 +1017,18 @@ } } +void ReadAnythingUntrustedPageHandler::OnSpeechEngineStalled() { +#if !BUILDFLAG(IS_CHROMEOS) + extensions::ExtensionRegistrar* extension_registrar = + extensions::ExtensionRegistrar::Get(profile_); + + if (extension_registrar) { + extension_registrar->ReloadExtension( + extension_misc::kComponentUpdaterTTSEngineExtensionId); + } +#endif +} + void ReadAnythingUntrustedPageHandler::PerformActionInTargetTree( const ui::AXActionData& data) { ui::AXActionHandlerBase* handler =
diff --git a/chrome/browser/ui/webui/side_panel/read_anything/read_anything_untrusted_page_handler.h b/chrome/browser/ui/webui/side_panel/read_anything/read_anything_untrusted_page_handler.h index 9aeb5d4..bc58576 100644 --- a/chrome/browser/ui/webui/side_panel/read_anything/read_anything_untrusted_page_handler.h +++ b/chrome/browser/ui/webui/side_panel/read_anything/read_anything_untrusted_page_handler.h
@@ -221,6 +221,7 @@ } void OnDistillationStateChanged( read_anything::mojom::ReadAnythingDistillationState new_state) override; + void OnSpeechEngineStalled() override; // PinnedToolbarModel::Observer void OnActionsChanged() override;
diff --git a/chrome/browser/ui/webui/signin/managed_user_profile_notice_ui.cc b/chrome/browser/ui/webui/signin/managed_user_profile_notice_ui.cc index 7a94776..2c3eaa3 100644 --- a/chrome/browser/ui/webui/signin/managed_user_profile_notice_ui.cc +++ b/chrome/browser/ui/webui/signin/managed_user_profile_notice_ui.cc
@@ -57,18 +57,32 @@ static constexpr webui::ResourcePath kResources[] = { {"icons.html.js", IDR_SIGNIN_ICONS_HTML_JS}, + {"managed_user_profile_notice_refresh.html", + IDR_SIGNIN_MANAGED_USER_PROFILE_NOTICE_MANAGED_USER_PROFILE_NOTICE_REFRESH_HTML}, {"managed_user_profile_notice_app.js", IDR_SIGNIN_MANAGED_USER_PROFILE_NOTICE_MANAGED_USER_PROFILE_NOTICE_APP_JS}, + {"managed_user_profile_notice_app_refresh.js", + IDR_SIGNIN_MANAGED_USER_PROFILE_NOTICE_MANAGED_USER_PROFILE_NOTICE_APP_REFRESH_JS}, {"managed_user_profile_notice_app.css.js", IDR_SIGNIN_MANAGED_USER_PROFILE_NOTICE_MANAGED_USER_PROFILE_NOTICE_APP_CSS_JS}, + {"managed_user_profile_notice_app_refresh.css.js", + IDR_SIGNIN_MANAGED_USER_PROFILE_NOTICE_MANAGED_USER_PROFILE_NOTICE_APP_REFRESH_CSS_JS}, {"managed_user_profile_notice_app.html.js", IDR_SIGNIN_MANAGED_USER_PROFILE_NOTICE_MANAGED_USER_PROFILE_NOTICE_APP_HTML_JS}, + {"managed_user_profile_notice_app_refresh.html.js", + IDR_SIGNIN_MANAGED_USER_PROFILE_NOTICE_MANAGED_USER_PROFILE_NOTICE_APP_REFRESH_HTML_JS}, {"managed_user_profile_notice_disclosure.css.js", IDR_SIGNIN_MANAGED_USER_PROFILE_NOTICE_MANAGED_USER_PROFILE_NOTICE_DISCLOSURE_CSS_JS}, + {"managed_user_profile_notice_disclosure_refresh.css.js", + IDR_SIGNIN_MANAGED_USER_PROFILE_NOTICE_MANAGED_USER_PROFILE_NOTICE_DISCLOSURE_REFRESH_CSS_JS}, {"managed_user_profile_notice_disclosure.html.js", IDR_SIGNIN_MANAGED_USER_PROFILE_NOTICE_MANAGED_USER_PROFILE_NOTICE_DISCLOSURE_HTML_JS}, + {"managed_user_profile_notice_disclosure_refresh.html.js", + IDR_SIGNIN_MANAGED_USER_PROFILE_NOTICE_MANAGED_USER_PROFILE_NOTICE_DISCLOSURE_REFRESH_HTML_JS}, {"managed_user_profile_notice_disclosure.js", IDR_SIGNIN_MANAGED_USER_PROFILE_NOTICE_MANAGED_USER_PROFILE_NOTICE_DISCLOSURE_JS}, + {"managed_user_profile_notice_disclosure_refresh.js", + IDR_SIGNIN_MANAGED_USER_PROFILE_NOTICE_MANAGED_USER_PROFILE_NOTICE_DISCLOSURE_REFRESH_JS}, {"managed_user_profile_notice_state.css.js", IDR_SIGNIN_MANAGED_USER_PROFILE_NOTICE_MANAGED_USER_PROFILE_NOTICE_STATE_CSS_JS}, {"managed_user_profile_notice_value_prop.css.js", @@ -160,6 +174,11 @@ source->AddLocalizedString("deviceInformationDetails", IDS_ENTERPRISE_WELCOME_DEVICE_INFORMATION_DETAILS); + source->AddLocalizedString("avatarAccessibilityLabel", + IDS_ACCNAME_YOUR_AVATAR); + source->AddLocalizedString("enterpriseIconAccessibilityLabel", + IDS_ACCNAME_ENTERPRISE_ORGANIZATION_ICON); + source->AddLocalizedString("processingSubtitle", IDS_ENTERPRISE_OIDC_WELCOME_PROCESSING_SUBTITLE); source->AddLocalizedString(
diff --git a/chrome/browser/ui/webui/version/DEPS b/chrome/browser/ui/webui/version/DEPS new file mode 100644 index 0000000..52d6835 --- /dev/null +++ b/chrome/browser/ui/webui/version/DEPS
@@ -0,0 +1,5 @@ +specific_include_rules = { + "version_handler_chromeos\.cc": [ + "+ash/strings", + ], +}
diff --git a/chrome/browser/ui/webui/version/version_handler_chromeos.cc b/chrome/browser/ui/webui/version/version_handler_chromeos.cc index a3ac320..84965cd 100644 --- a/chrome/browser/ui/webui/version/version_handler_chromeos.cc +++ b/chrome/browser/ui/webui/version/version_handler_chromeos.cc
@@ -4,13 +4,13 @@ #include "chrome/browser/ui/webui/version/version_handler_chromeos.h" +#include "ash/strings/grit/ash_strings.h" #include "base/functional/bind.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "base/task/thread_pool.h" #include "chrome/common/channel_info.h" #include "chrome/common/webui_url_constants.h" -#include "chromeos/strings/grit/chromeos_strings.h" #include "chromeos/version/version_loader.h" #include "components/version_info/channel.h" #include "content/public/browser/web_ui.h"
diff --git a/chrome/browser/ui/webui/whats_new/BUILD.gn b/chrome/browser/ui/webui/whats_new/BUILD.gn index 28be281..4872469b 100644 --- a/chrome/browser/ui/webui/whats_new/BUILD.gn +++ b/chrome/browser/ui/webui/whats_new/BUILD.gn
@@ -154,3 +154,32 @@ ] } } + +source_set("interactive_ui_tests") { + testonly = true + defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ] + if (!is_android && !is_chromeos) { + sources = [ "whats_new_fetcher_interactive_uitest.cc" ] + deps = [ + ":whats_new", + "//base", + "//base/test:test_support", + "//chrome/browser:browser_process", + "//chrome/browser:global_features", + "//chrome/browser/ui", + "//chrome/browser/ui:ui_features", + "//chrome/common:version_header", + "//chrome/test:test_support_ui", + "//components/user_education/common", + "//components/user_education/webui", + "//content/test:test_support", + "//testing/gtest", + ] + if (use_ozone) { + deps += [ "//ui//ozone" ] + } + if (is_linux) { + deps += [ "//ui/views:test_support" ] + } + } +}
diff --git a/chrome/browser/ui/webui/whats_new/whats_new_fetcher.cc b/chrome/browser/ui/webui/whats_new/whats_new_fetcher.cc index f1e7f12..30dda40 100644 --- a/chrome/browser/ui/webui/whats_new/whats_new_fetcher.cc +++ b/chrome/browser/ui/webui/whats_new/whats_new_fetcher.cc
@@ -114,7 +114,7 @@ base::BindRepeating(&WhatsNewFetcher::OnBrowserDidBecomeActive, base::Unretained(this))); browser_did_become_inactive_subscription_ = - browser_->RegisterDidBecomeActive( + browser_->RegisterDidBecomeInactive( base::BindRepeating(&WhatsNewFetcher::OnBrowserDidBecomeInactive, base::Unretained(this)));
diff --git a/chrome/browser/ui/webui/whats_new/whats_new_fetcher_browsertest.cc b/chrome/browser/ui/webui/whats_new/whats_new_fetcher_browsertest.cc index 518c51d4..2a166d9 100644 --- a/chrome/browser/ui/webui/whats_new/whats_new_fetcher_browsertest.cc +++ b/chrome/browser/ui/webui/whats_new/whats_new_fetcher_browsertest.cc
@@ -77,11 +77,8 @@ } virtual void InitFeatures() { // Enabled/disable test data. - // Additionally, the refresh feature is disabled to simplify the tests. - // Eventually, the refresh URL will be the default, so this is fine for now. - feature_list_.InitWithFeatures( - {kTestModuleEnabled, kTestModule2Enabled}, - {features::kWhatsNewDesktopRefresh, kTestModuleDisabled}); + feature_list_.InitWithFeatures({kTestModuleEnabled, kTestModule2Enabled}, + {kTestModuleDisabled}); } ~WhatsNewFetcherBrowserTest() override { GlobalFeatures::ReplaceGlobalFeaturesForTesting(base::NullCallback()); @@ -96,9 +93,9 @@ }; IN_PROC_BROWSER_TEST_F(WhatsNewFetcherBrowserTest, GetServerURL) { - const std::string expected = - base::StringPrintf("https://www.google.com/chrome/whats-new/?version=%d", - CHROME_VERSION_MAJOR); + const std::string expected = base::StringPrintf( + "https://www.google.com/chrome/wn-2025/whats-new/?version=%d", + CHROME_VERSION_MAJOR); EXPECT_EQ(expected, whats_new::GetServerURL(*GetRegistry()).possibly_invalid_spec()); @@ -107,7 +104,8 @@ IN_PROC_BROWSER_TEST_F(WhatsNewFetcherBrowserTest, GetServerURLForRenderNoFeatures) { std::string expected = base::StringPrintf( - "https://www.google.com/chrome/whats-new/?version=%d&internal=true", + "https://www.google.com/chrome/wn-2025/whats-new/" + "?version=%d&internal=true", CHROME_VERSION_MAJOR); EXPECT_EQ( @@ -118,7 +116,7 @@ IN_PROC_BROWSER_TEST_F(WhatsNewFetcherBrowserTest, GetServerStagingURLForRenderNoFeatures) { std::string expected = base::StringPrintf( - "https://chrome-staging.corp.google.com/chrome/whats-new/" + "https://chrome-staging.corp.google.com/chrome/wn-2025/whats-new/" "?version=%d&internal=true", CHROME_VERSION_MAJOR); @@ -133,9 +131,9 @@ registry->RegisterModule( whats_new::WhatsNewModule("", "", BrowserCommand::kNoOpCommand)); - std::string expected = - base::StringPrintf("https://www.google.com/chrome/whats-new/?version=%d", - CHROME_VERSION_MAJOR); + std::string expected = base::StringPrintf( + "https://www.google.com/chrome/wn-2025/whats-new/?version=%d", + CHROME_VERSION_MAJOR); // Enabled modules will be sent with `enabled` parameter. expected.append(base::StringPrintf("&enabled=%s", kTestModuleEnabled.name)); @@ -155,9 +153,9 @@ registry->RegisterModule( whats_new::WhatsNewModule("", "", BrowserCommand::kNoOpCommand)); - std::string expected = - base::StringPrintf("https://www.google.com/chrome/whats-new/?version=%d", - CHROME_VERSION_MAJOR); + std::string expected = base::StringPrintf( + "https://www.google.com/chrome/wn-2025/whats-new/?version=%d", + CHROME_VERSION_MAJOR); // Multiple enabled features will be comma-separated (url-encoded). expected.append(base::StringPrintf( @@ -185,9 +183,9 @@ registry->RegisterModule( whats_new::WhatsNewModule("", "", BrowserCommand::kNoOpCommand)); - std::string expected = - base::StringPrintf("https://www.google.com/chrome/whats-new/?version=%d", - CHROME_VERSION_MAJOR); + std::string expected = base::StringPrintf( + "https://www.google.com/chrome/wn-2025/whats-new/?version=%d", + CHROME_VERSION_MAJOR); // Enabled modules will be sent with `enabled` parameter. expected.append(base::StringPrintf("&enabled=%s", kTestModuleEnabled.name)); @@ -208,12 +206,10 @@ public: void InitFeatures() override { // Enabled/disable test data. - // Additionally, the refresh feature is disabled to simplify the tests. - // Eventually, the refresh URL will be the default, so this is fine for now. feature_list_.InitWithFeaturesAndParameters( {{kTestModuleEnabled, {{whats_new::kCustomizationParam, "abc"}}}, {kTestModule2Enabled, {{}}}}, - {features::kWhatsNewDesktopRefresh, kTestModuleDisabled}); + {kTestModuleDisabled}); } }; @@ -232,9 +228,9 @@ registry->RegisterModule( whats_new::WhatsNewModule("", "", BrowserCommand::kNoOpCommand)); - std::string expected = - base::StringPrintf("https://www.google.com/chrome/whats-new/?version=%d", - CHROME_VERSION_MAJOR); + std::string expected = base::StringPrintf( + "https://www.google.com/chrome/wn-2025/whats-new/?version=%d", + CHROME_VERSION_MAJOR); // Enabled modules will be sent with `enabled` parameter. expected.append(base::StringPrintf("&enabled=%s", kTestModuleEnabled.name)); @@ -258,13 +254,11 @@ public: void InitFeatures() override { // Enabled/disable test data. - // Additionally, the refresh feature is disabled to simplify the tests. - // Eventually, the refresh URL will be the default, so this is fine for now. feature_list_.InitWithFeaturesAndParameters( {{kTestModuleEnabled, {{whats_new::kCustomizationParam, "abc"}}}, {kTestModule2Enabled, {{whats_new::kCustomizationParam, "def"}}}, {kTestEditionEnabled, {{whats_new::kCustomizationParam, "hij"}}}}, - {features::kWhatsNewDesktopRefresh}); + {}); } }; @@ -279,9 +273,9 @@ registry->RegisterModule( whats_new::WhatsNewModule("", "", BrowserCommand::kNoOpCommand)); - std::string expected = - base::StringPrintf("https://www.google.com/chrome/whats-new/?version=%d", - CHROME_VERSION_MAJOR); + std::string expected = base::StringPrintf( + "https://www.google.com/chrome/wn-2025/whats-new/?version=%d", + CHROME_VERSION_MAJOR); // Enabled modules will be sent with `enabled` parameter. auto enabled = @@ -313,7 +307,7 @@ IN_PROC_BROWSER_TEST_F(WhatsNewFetcherStagingBrowserTest, GetServerURLForRenderNoFeatures) { std::string expected = base::StringPrintf( - "https://chrome-staging.corp.google.com/chrome/whats-new/" + "https://chrome-staging.corp.google.com/chrome/wn-2025/whats-new/" "?version=%d&internal=true", CHROME_VERSION_MAJOR); @@ -325,7 +319,7 @@ IN_PROC_BROWSER_TEST_F(WhatsNewFetcherStagingBrowserTest, GetServerStagingURLForRenderNoFeatures) { std::string expected = base::StringPrintf( - "https://chrome-staging.corp.google.com/chrome/whats-new/" + "https://chrome-staging.corp.google.com/chrome/wn-2025/whats-new/" "?version=%d&internal=true", CHROME_VERSION_MAJOR);
diff --git a/chrome/browser/ui/webui/whats_new/whats_new_fetcher_interactive_uitest.cc b/chrome/browser/ui/webui/whats_new/whats_new_fetcher_interactive_uitest.cc new file mode 100644 index 0000000..5e1a18bb --- /dev/null +++ b/chrome/browser/ui/webui/whats_new/whats_new_fetcher_interactive_uitest.cc
@@ -0,0 +1,70 @@ +// Copyright 2026 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/run_loop.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/webui/whats_new/whats_new_fetcher.h" +#include "chrome/browser/ui/webui/whats_new/whats_new_util.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "chrome/test/base/interactive_test_utils.h" +#include "content/public/test/browser_test.h" + +#if BUILDFLAG(IS_OZONE) +#include "ui/ozone/public/ozone_platform.h" +#endif + +#if BUILDFLAG(IS_LINUX) +#include "ui/views/test/mock_activation_controller.h" // nogncheck +#endif + +class WhatsNewFetcherActiveStateTest : public InProcessBrowserTest { + public: + void SetUpOnMainThread() override { + whats_new::DisableRemoteContentForTests(); + } + +#if BUILDFLAG(IS_LINUX) + // On linux, the activation is asynchronous, which makes it impossible to + // reliably wait for the posted task after activation change. Use mocked + // activation logic which is synchronous. + views::test::MockActivationController activation_controller_; +#endif +}; + +IN_PROC_BROWSER_TEST_F(WhatsNewFetcherActiveStateTest, + DoesNotOpenWhenInactive) { +#if BUILDFLAG(IS_OZONE) + // Ozone/wayland doesn't support window activaation from apps. + if (ui::OzonePlatform::RunningOnWaylandForTest()) { + GTEST_SKIP(); + } +#endif + + Browser* new_browser = CreateBrowser(browser()->profile()); + ui_test_utils::BrowserActivationWaiter(new_browser).WaitForActivation(); + EXPECT_TRUE(new_browser->IsActive()); + + int initial_tab_count = new_browser->tab_strip_model()->count(); + + // Start the fetch. It posts a task to open the tab. + whats_new::StartWhatsNewFetch(new_browser); + + // Immediately change the activation so that it will not show the what's new + // tab. + ui_test_utils::BrowserActivationWaiter waiter(browser()); + browser()->window()->Activate(); + waiter.WaitForActivation(); + + // There is no events to wait, so just use RunUntilIdle to give the posted + // task a chance to run. + base::RunLoop().RunUntilIdle(); + + EXPECT_TRUE(browser()->IsActive()); + EXPECT_FALSE(new_browser->IsActive()); + + // Because the new browser was made inactive, the fetcher should NOT + // open the What's New tab. + EXPECT_EQ(initial_tab_count, new_browser->tab_strip_model()->count()); +}
diff --git a/chrome/browser/ui/webui/whats_new/whats_new_handler.cc b/chrome/browser/ui/webui/whats_new/whats_new_handler.cc index 8661b1d..c6eac8b8d 100644 --- a/chrome/browser/ui/webui/whats_new/whats_new_handler.cc +++ b/chrome/browser/ui/webui/whats_new/whats_new_handler.cc
@@ -37,9 +37,6 @@ namespace { -// The trigger ID for the HaTS survey for the What's New refresh page. -constexpr char kHatsSurveyEnSiteID[] = "en_site_id"; - } // namespace WhatsNewHandler::WhatsNewHandler( @@ -280,14 +277,6 @@ /*navigation_behavior=*/HatsService::REQUIRE_SAME_ORIGIN, base::DoNothing(), base::DoNothing(), survey_override.value()); } else { - // Temporary survey for the refresh experiment. - const std::optional<std::string> survey_trigger_override = - base::FeatureList::IsEnabled(features::kWhatsNewDesktopRefresh) - ? std::make_optional(base::FeatureParam<std::string>( - &features::kWhatsNewDesktopRefresh, - kHatsSurveyEnSiteID, "") - .Get()) - : std::nullopt; hats_service->LaunchDelayedSurveyForWebContents( kHatsSurveyTriggerWhatsNew, web_contents_, features::kHappinessTrackingSurveysForDesktopWhatsNewTime.Get() @@ -295,6 +284,6 @@ /*product_specific_bits_data=*/{}, /*product_specific_string_data=*/{}, /*navigation_behavior=*/HatsService::REQUIRE_SAME_ORIGIN, - base::DoNothing(), base::DoNothing(), survey_trigger_override); + base::DoNothing(), base::DoNothing(), std::nullopt); } }
diff --git a/chrome/browser/ui/webui/whats_new/whats_new_handler_unittest.cc b/chrome/browser/ui/webui/whats_new/whats_new_handler_unittest.cc index 35dca9c3..45ab8d1a 100644 --- a/chrome/browser/ui/webui/whats_new/whats_new_handler_unittest.cc +++ b/chrome/browser/ui/webui/whats_new/whats_new_handler_unittest.cc
@@ -114,9 +114,10 @@ TEST_F(WhatsNewHandlerTest, GetServerUrl) { base::MockCallback<WhatsNewHandler::GetServerUrlCallback> callback; - const GURL expected_url = GURL(base::StringPrintf( - "https://www.google.com/chrome/whats-new/?version=%d&internal=true", - CHROME_VERSION_MAJOR)); + const GURL expected_url = + GURL(base::StringPrintf("https://www.google.com/chrome/wn-2025/whats-new/" + "?version=%d&internal=true", + CHROME_VERSION_MAJOR)); EXPECT_CALL(callback, Run).Times(1).WillOnce([&](GURL actual_url) { EXPECT_EQ(actual_url, expected_url); @@ -288,52 +289,3 @@ mock_page_.FlushForTesting(); } -class WhatsNewRefreshHandlerTest : public WhatsNewHandlerTest { - public: - WhatsNewRefreshHandlerTest() = default; - ~WhatsNewRefreshHandlerTest() override = default; - - void SetUp() override { - WhatsNewHandlerTest::SetUp(); - features_.InitWithFeaturesAndParameters( - {base::test::FeatureRefAndParams( - features::kHappinessTrackingSurveysForDesktopWhatsNew, - {{"whats-new-time", "20s"}}), - {features::kWhatsNewDesktopRefresh, - {{"en_site_id", survey_override_id_}}}}, - {}); - } - - protected: - const std::string survey_override_id_ = "my-survey-id"; - base::test::ScopedFeatureList features_; -}; - -TEST_F(WhatsNewRefreshHandlerTest, GetServerUrl) { - base::MockCallback<WhatsNewHandler::GetServerUrlCallback> callback; - - const GURL expected_url = - GURL(base::StringPrintf("https://www.google.com/chrome/wn-2025/whats-new/" - "?version=%d&internal=true", - CHROME_VERSION_MAJOR)); - - EXPECT_CALL(callback, Run).Times(1).WillOnce([&](GURL actual_url) { - EXPECT_EQ(actual_url, expected_url); - }); - - handler_->GetServerUrl(false, callback.Get()); - mock_page_.FlushForTesting(); -} - -TEST_F(WhatsNewRefreshHandlerTest, SurveyIsTriggered) { - base::MockCallback<WhatsNewHandler::GetServerUrlCallback> callback; - EXPECT_CALL(callback, Run).Times(1); - EXPECT_CALL(*mock_hats_service(), - LaunchDelayedSurveyForWebContents( - kHatsSurveyTriggerWhatsNew, _, _, _, _, _, _, _, - std::optional<std::string>(survey_override_id_), _)) - .Times(1); - - handler_->GetServerUrl(false, callback.Get()); - mock_page_.FlushForTesting(); -}
diff --git a/chrome/browser/ui/webui/whats_new/whats_new_ui.cc b/chrome/browser/ui/webui/whats_new/whats_new_ui.cc index b34b51e3..5776cdd 100644 --- a/chrome/browser/ui/webui/whats_new/whats_new_ui.cc +++ b/chrome/browser/ui/webui/whats_new/whats_new_ui.cc
@@ -50,7 +50,7 @@ // Allow embedding of iframe from chrome.com source->OverrideContentSecurityPolicy( - network::mojom::CSPDirectiveName::ChildSrc, + network::mojom::CSPDirectiveName::FrameSrc, enable_staging ? "frame-src chrome://webui-test https://www.google.com/ " "https://chrome-staging.corp.google.com/;"
diff --git a/chrome/browser/wallet/BUILD.gn b/chrome/browser/wallet/BUILD.gn index bc46ddfe..1966835d 100644 --- a/chrome/browser/wallet/BUILD.gn +++ b/chrome/browser/wallet/BUILD.gn
@@ -2,35 +2,48 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -static_library("wallet") { - sources = [ - "chrome_walletable_pass_client.cc", - "chrome_walletable_pass_client.h", +source_set("wallet") { + public = [ "chrome_walletable_pass_client.h" ] + + sources = [ "chrome_walletable_pass_client.cc" ] + + public_deps = [ + "//base", + "//components/wallet/content/browser", + "//components/wallet/core/browser", ] deps = [ "//base", "//chrome/browser:browser_process", "//chrome/browser/optimization_guide", - "//chrome/browser/profiles", + "//chrome/browser/profiles:profile", "//chrome/browser/signin", "//chrome/browser/strike_database", "//chrome/browser/ui/wallet", "//components/optimization_guide/core", + "//components/signin/public/identity_manager", + "//components/strike_database", + "//components/tabs:public", "//components/variations/service", - "//components/wallet/content/browser", - "//components/wallet/core/browser", - "//services/network/public/cpp", + "//content/public/browser", ] } -source_set("browser_tests") { - testonly = true - defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ] - sources = [ "walletable_pass_barcode_detector_browsertest.cc" ] - deps = [ - "//chrome/test:test_support", - "//components/wallet/content/browser", - "//components/wallet/content/common/mojom", - ] +if (!is_android) { + source_set("browser_tests") { + testonly = true + defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ] + sources = [ "walletable_pass_barcode_detector_browsertest.cc" ] + deps = [ + "//base/test:test_support", + "//chrome/browser/ui", + "//chrome/test:test_support", + "//components/wallet/content/browser", + "//content/public/browser", + "//testing/gmock", + "//testing/gtest", + "//url", + ] + } }
diff --git a/chrome/browser/wallet/android/BUILD.gn b/chrome/browser/wallet/android/BUILD.gn index 40ca0f0..7897d0e9 100644 --- a/chrome/browser/wallet/android/BUILD.gn +++ b/chrome/browser/wallet/android/BUILD.gn
@@ -3,9 +3,49 @@ # found in the LICENSE file. # This whole package is android only +assert(is_android) + import("//build/config/android/config.gni") import("//build/config/android/rules.gni") import("//third_party/jni_zero/jni_zero.gni") + +source_set("wallet_android") { + public = [ "boarding_pass_detector.h" ] + + sources = [ + "boarding_pass_bridge.cc", + "boarding_pass_detector.cc", + ] + + public_deps = [ + "//base", + "//chrome/common/wallet:mojo_bindings", + "//mojo/public/cpp/bindings", + ] + + deps = [ + ":jni_headers", + "//base", + "//chrome/common:chrome_features", + "//content/public/browser", + "//services/service_manager/public/cpp", + ] +} + +source_set("unit_tests") { + testonly = true + sources = [ "boarding_pass_detector_unittest.cc" ] + + deps = [ + ":wallet_android", + "//base/test:test_support", + "//chrome/common:chrome_features", + "//chrome/common/wallet:mojo_bindings", + "//mojo/public/cpp/bindings", + "//testing/gtest", + ] +} + android_library("java") { sources = [ "java/src/org/chromium/chrome/browser/wallet/BoardingPassBridge.java",
diff --git a/chrome/browser/wallet/android/boarding_pass_detector.cc b/chrome/browser/wallet/android/boarding_pass_detector.cc index ed78058..04cc4c0d 100644 --- a/chrome/browser/wallet/android/boarding_pass_detector.cc +++ b/chrome/browser/wallet/android/boarding_pass_detector.cc
@@ -9,6 +9,7 @@ #include "base/strings/string_split.h" #include "chrome/common/chrome_features.h" #include "content/public/browser/render_frame_host.h" +#include "content/public/browser/web_contents.h" #include "services/service_manager/public/cpp/interface_provider.h" namespace wallet {
diff --git a/chrome/browser/wallet/android/boarding_pass_detector.h b/chrome/browser/wallet/android/boarding_pass_detector.h index 644d952..de07616 100644 --- a/chrome/browser/wallet/android/boarding_pass_detector.h +++ b/chrome/browser/wallet/android/boarding_pass_detector.h
@@ -6,10 +6,16 @@ #define CHROME_BROWSER_WALLET_ANDROID_BOARDING_PASS_DETECTOR_H_ #include <string> +#include <vector> + +#include "base/functional/callback.h" #include "chrome/common/wallet/boarding_pass_extractor.mojom.h" -#include "content/public/browser/web_contents.h" #include "mojo/public/cpp/bindings/remote.h" +namespace content { +class WebContents; +} // namespace content + namespace wallet { // Detects boarding passes on a web page. This class is self-owned and will
diff --git a/chrome/browser/wallet/chrome_walletable_pass_client.cc b/chrome/browser/wallet/chrome_walletable_pass_client.cc index 2a90eda86..df9df2d2 100644 --- a/chrome/browser/wallet/chrome_walletable_pass_client.cc +++ b/chrome/browser/wallet/chrome_walletable_pass_client.cc
@@ -20,7 +20,6 @@ #include "components/tabs/public/tab_interface.h" #include "components/variations/service/variations_service.h" #include "content/public/browser/web_contents.h" -#include "services/network/public/cpp/shared_url_loader_factory.h" namespace wallet {
diff --git a/chrome/browser/wallet/chrome_walletable_pass_client.h b/chrome/browser/wallet/chrome_walletable_pass_client.h index d69cb57..63623a1 100644 --- a/chrome/browser/wallet/chrome_walletable_pass_client.h +++ b/chrome/browser/wallet/chrome_walletable_pass_client.h
@@ -5,6 +5,8 @@ #ifndef CHROME_BROWSER_WALLET_CHROME_WALLETABLE_PASS_CLIENT_H_ #define CHROME_BROWSER_WALLET_CHROME_WALLETABLE_PASS_CLIENT_H_ +#include <memory> + #include "base/memory/raw_ref.h" #include "components/wallet/content/browser/content_walletable_pass_ingestion_controller.h" #include "components/wallet/core/browser/data_models/wallet_pass.h" @@ -30,7 +32,6 @@ namespace wallet { -class ContentWalletablePassIngestionController; class WalletablePassConsentBubbleController; class WalletablePassSaveBubbleController;
diff --git a/chrome/browser/wallet/walletable_pass_barcode_detector_browsertest.cc b/chrome/browser/wallet/walletable_pass_barcode_detector_browsertest.cc index d2389e8..1df86d3 100644 --- a/chrome/browser/wallet/walletable_pass_barcode_detector_browsertest.cc +++ b/chrome/browser/wallet/walletable_pass_barcode_detector_browsertest.cc
@@ -5,9 +5,8 @@ #include "components/wallet/content/browser/walletable_pass_barcode_detector.h" #include <memory> -#include <optional> +#include <string> -#include "base/base64.h" #include "base/test/test_future.h" #include "chrome/browser/ui/browser.h" #include "chrome/test/base/in_process_browser_test.h" @@ -15,8 +14,6 @@ #include "components/wallet/content/browser/walletable_pass_barcode_detector_impl.h" #include "content/public/browser/web_contents.h" #include "content/public/test/browser_test.h" -#include "mojo/public/cpp/bindings/pending_receiver.h" -#include "mojo/public/cpp/bindings/receiver.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h"
diff --git a/chrome/browser/web_applications/BUILD.gn b/chrome/browser/web_applications/BUILD.gn index b29789f..874721f 100644 --- a/chrome/browser/web_applications/BUILD.gn +++ b/chrome/browser/web_applications/BUILD.gn
@@ -1,5 +1,5 @@ -# Use of this source code is governed by a BSD-style license that can be # 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. import("//chrome/browser/buildflags.gni") @@ -968,6 +968,7 @@ "commands/fetch_installability_for_chrome_management_unittest.cc", "commands/fetch_manifest_and_install_command_unittest.cc", "commands/fetch_manifest_and_update_command_unittest.cc", + "commands/generated_icon_fix_command_unittest.cc", "commands/install_app_locally_command_unittest.cc", "commands/install_from_sync_command_unittest.cc", "commands/install_migrate_to_app_command_unittest.cc",
diff --git a/chrome/browser/web_applications/README.md b/chrome/browser/web_applications/README.md index bae88b1..5a92296 100644 --- a/chrome/browser/web_applications/README.md +++ b/chrome/browser/web_applications/README.md
@@ -1,4 +1,137 @@ -# Web Apps +# Web Apps on Desktop -Moved to [/docs/webapps/README.md](/docs/webapps/README.md) - \ No newline at end of file +See [presentation slides](https://tinyurl.com/dpwa-architecture-public) about the WebAppProvider system architecture. + +## Debugging + +Use `chrome://web-app-internals` (generated [here](https://source.chromium.org/search?q=WebAppInternalsHandler::BuildDebugInfo)) to inspect internal web app state. +Test failures will print this information out automatically to help with debugging. + +The codebase has a number of useful DVLOGs (like in `web_app_command_manager.cc` and `web_app_lock_manager.cc`). Use the normal vmodule command line args to see these (e.g. `--vmodule=web_app*=1`). + +For developers wanting to test the behavior of the web app itself, Chrome DevTools Protocol can be used. See [Instruction of using PWA via CDP](docs/cdp-integration.md). + +## Documentation Guidelines + +- Markdown documentation (files like this): + - Contains information that can't be documented in class-level documentation. + - Answers questions like: What is the goal of a group of classes together? How does a group of classes work together? + - Explains concepts that are used across different files. + - Should be unlikely to become out-of-date. + - Any source links should link to a codesearch 'search' page and not the specific line number. + - Avoid implementation details. +- Class-level documentation (documentation in header files): + - Answers questions like: Why does this class exist? What is the responsibility of this class? If this class involves a process with stages, what are those stages / steps? + - Should be updated actively when that given file is changed. +- Documentation inside of methods should only be used to explain the "why" of code if it is not obvious. + +## What makes up Chromium's implementation? + +The task of turning websites into "apps" in the user's OS environment has many parts to it. Before going into the parts, here is where they live: + + + +See the drawing source [here](https://docs.google.com/drawings/d/1TqUF2Pqh2S5qPGyA6njQWxOgSgKQBPePKPIH_srGeRk/edit?usp=sharing). + +- The `WebAppProvider` core system lives on the `Profile` object. +- The `WebAppUiManagerImpl` also lives on the `Profile` object (to avoid deps issues). +- The `AppBrowserController` (typically `WebAppBrowserController` for our interests) lives on the `Browser` object. +- The `WebAppTabHelper` lives on the `WebContents` object. + +While most on-disk storage is done in the [`WebAppSyncBridge`](#webappsyncbridge), the system also sometimes uses the `PrefService`. Most of these prefs live on the `Profile` (`profile->GetPrefs()`), but some prefs are in the global browser prefs (`g_browser_process->local_state()`). + +Presentation: [https://tinyurl.com/dpwa-architecture-public](https://tinyurl.com/dpwa-architecture-public) + +Older presentation: [https://tinyurl.com/bmo-public](https://tinyurl.com/bmo-public) + +## Architecture Philosophy + +- Tests (especially browser tests / integration tests) should generally operate on the [public interface](#public-interface) as much as possible. Unit tests can touch internals where convenient to set up initial state, but generally still test the operations via the public interface. +- [External dependencies](#external-dependencies) should be behind fake-able interfaces, allowing unit & browser tests to swap these out. However, internal parts of our system should not be mocked out or faked - this tightly couples the internal implementation to our tests. If it is impossible to trigger a condition with the public interface, then that condition should be removed (or the public interface improved). + - See [this presentation](https://www.youtube.com/watch?v=EZ05e7EMOLM) about testing that might clarify our approach. + +## Usage + +The safest way to use the WebAppProvider system is using the `WebAppCommandScheduler` (via `WebAppProvider::scheduler()`), which serves as an entry point for operations on the system for safely reading or writing state. Unsafe state access is available via `WebAppProvider::registrar_unsafe()`, but this in not guaranteed to be consistent as an async operation could be occurring at any time (install, uninstall, update, etc). + +For information about creating safe read/write operations on the system, see the [commands README.md](/chrome/browser/web_applications/commands/README.md). + +## External Dependencies + +The goal is to have all of these behind an abstraction that has a fake to allow easy unit testing of our system. Some of these dependencies are behind a nice fake-able interface, and some are not (yet). + +- **Extensions** - Some of our code still talks to the extensions system, + specifically the `PreinstalledWebAppManager`. +- **`content::WebContents`**: The WebAppProvider system interacts with + `content::WebContents` for various tasks like loading URLs (via + `WebAppUrlLoader`), retrieving web app manifest data and icons (via + `WebAppDataRetriever` and `WebAppIconDownloader` respectively), and observing + navigations and destruction. The `WebContentsManager` serves as a centralized + point of dependency for these interactions and acts as a factory for these + components, allowing for easier management and faking in tests via the `FakeWebContentsManager`. +- **OS Integration**: Each OS integration has fairly custom code on each OS to + do the operation. The `OsIntegrationManger` and the respective sub-managers own this. +- **Sync system**: There is a tight coupling between our system and the sync + system through the WebAppSyncBridge. Faking this is easy and is handled by + the `FakeWebAppProvider`. +- **UI**: There are parts of the system that are coupled to UI, like showing + dialogs, determining information about app windows, etc. These are put behind + the `WebAppUiManager`, and faked by the `FakeWebAppUiManager`. +- **Policy**: Our code depends on the policy system setting its policies in + appropriate prefs for us to read. Because we just look at prefs, we don't + need a "fake" here. + +## Databases / sources of truth + +These store data for our system. Some of it is per-web-app, and some of it is global. + +- **`WebAppRegistrar`**: This attempts to unify the reading of much of this data, and also holds an in-memory copy of the database data (in WebApp objects). +- **`WebAppDatabase`** / **`WebAppSyncBridge`**: This stores the web_app.proto object in a database, which is the preferred place to store information about a web app. +- **Icons on disk**: These are managed by the `WebAppIconManager` and stored on disk in the user's profile. +- **Prefs**: The `PrefService` is used to store information that is either global, or needs to persist after a web app is uninstalled. Most of these prefs live on the `Profile` (`profile->GetPrefs()`), but some prefs are in the global browser prefs (`g_browser_process->local_state()`). Some users of prefs: + - AppShimRegistry + - UserUninstalledPreinstalledWebAppPrefs +- **OS Integration**: Various OS integration requires storing state on the operating system. Sometimes we are able to read this state back, sometimes not. + +Accessing any of this information without an applicable 'lock' on the system is considered unsafe. + +## Relevant Classes & Managers + +The **[`WebAppProvider`](/chrome/browser/web_applications/web_app_provider.h)** is the per-profile object housing most of the various web app subsystems, acting as the "main()" of the web app implementation where everything starts. Unit tests use the `FakeWebAppProvider` version which allows tests to swap out some managers with fakes (and does this by default for a few). + +The objects that live on the WebAppProvider, often called 'Managers', are used to encapsulate common responsibilities or in-memory state that needs to be stored. See the respective header files for more detailed information: + +- **`WebAppCommandManager` & `WebAppCommandScheduler`**: The entry point for performing asynchronous operations safely via locks. +- **`WebAppRegistrar`**: Provides a queryable in-memory view of all installed web apps. +- **`WebAppSyncBridge`**: Synchronizes the in-memory registrar with the on-disk database and Chrome Sync; faked with an in-memory database and sync disabled by default. +- **`WebAppInstallManager`**: Orchestrates the installation of web apps. +- **`ManifestUpdateManager`**: Monitors and applies updates to web app manifests. +- **`ExternallyManagedAppManager`**: Handles installations from external sources like policies or preinstalled configurations. +- **`WebAppPolicyManager`**: Manages apps installed via enterprise policy. +- **`PreinstalledWebAppManager`**: Manages the installation of default "preinstalled" web apps. +- **`WebAppIconManager`**: Manages the loading and storage of app icons on disk. +- **`OsIntegrationManager`**: Manages all integrations with the host operating system. `FakeOsIntegrationManager` is used by default in unit tests. +- **`WebAppUiManager`**: Interface for performing UI operations like showing dialogs. `FakeWebAppUiManager` is used by default in unit tests. +- **`WebContentsManager`**: Factory for WebContents-based dependencies, wrapping the WebContents / network dependency for the entire system. `FakeWebContentsManager` is used by default in unit tests. +- **`FileUtilsWrapper`**: Utility for file system access. `TestFileUtils` is used by default in unit tests. + +Other relevant classes: + +- **[`WebApp`](/chrome/browser/web_applications/web_app.h)**: The representation of an installed web app in RAM, reflecting how a site configures its web app manifest plus internal bookkeeping. This does not include information like policy information, so usage of this class is often discouraged over the WebAppRegistrar, which combined multiple sources of truth holistically. +- **[`AppShimRegistry`](/chrome/browser/web_applications/app_shim_registry_mac.h)**: (Mac-only) Stores state in Chrome's "Local State" (global preferences) to reason about installed PWAs across all profiles without loading those profiles into memory. + +## Deep Dives + +- [Installation Pipeline](docs/installation_pipeline.md) +- [Manifest Representations in Code](docs/manifest_representations.md) +- [Integration Testing Framework](docs/integration-testing-framework.md) +- [OS Integration](docs/os_integration.md) +- [Manifest Update Process](docs/manifest_update_process.md) +- [Isolated Web Apps](docs/isolated_web_apps.md) +- [WebUI Web App](docs/webui_web_app.md) +- [Why is this test failing?](docs/why-is-this-test-failing.md) +- [How to create WebAppIntegration Tests](docs/how-to-create-webapp-integration-tests.md) + +## Testing + +Please see [testing.md](docs/testing.md). \ No newline at end of file
diff --git a/chrome/browser/web_applications/commands/README.md b/chrome/browser/web_applications/commands/README.md new file mode 100644 index 0000000..ab041ff --- /dev/null +++ b/chrome/browser/web_applications/commands/README.md
@@ -0,0 +1,55 @@ +# Commands (`chrome/browser/web_applications/commands`) + +This directory contains the implementations of the operations scheduleable by +the `WebAppCommandScheduler`. + +Some command operations are just one synchronous operation. These can be +scheduled as a callback instead of requiring a full class implementation (see +`ScheduleCallback` or `ScheduleCallbackWithResult` in the scheduler). + +## Role of Commands + +Commands are the **exclusive mechanism** for altering the state of the web app +system and its interaction with the OS. They are designed to prevent race +conditions when multiple app installations, updates, or uninstalls are happening +concurrently. + +By encapsulating logic within a `WebAppCommand`, the `WebAppCommandManager` +ensures that operations requiring exclusive access to resources (locks) are +sequenced correctly. + +## Best Practices + +- **Check Initial State:** Any number of queued operations can occur between + scheduling a command and it being run. Thus, always re-check the initial state + when the command starts, as (for example) the app may have just been + uninstalled!. +- **Locking:** Locks are automatically acquired by the system before + `StartWithLock` is called on the command. Ensure your command declares the + correct lock granularity to minimize contention while keeping the system safe. + Locks can sometimes be 'upgraded' via the `WebAppLockManager` object on the + lock. It is OK to schedule a command from another command, but to prevent + deadlocks, do not wait for it to complete before completing the original + command. +- **Delegate to Jobs:** A command often acts as an orchestrator for smaller + units of work called `jobs`. If a sequence of operations is reusable by three + or more commands, implement it as a [job](../jobs/README.md). +- **Callback Guarantee:** The command's completion callback (passed to the base + class on construction) is automatically called by the command infrastructure + when `CompleteAndSelfDestruct` is called or if the system is shut down. This + requires commands to **ensure** that `CompleteAndSelfDestruct()` is called after `StartWithLock()` is called, + , otherwise the entire system can hang. Commands can assume the + callback will be called after the command is destroyed, so no reentry is + possible. +- **Debugging:** The command's `GetMutableDebugValue()` is visible in + `chrome://web-app-internals`, making it extremely useful to populate with + detailed progression or error states. `DVLOG`s exist in the + `web_app_command_manager.cc` and `web_app_lock_manager.cc` which can be useful + to print out command information when they are scheduled and completed (e.g. + visible via the command line arg `--vmodule=web_app*=1`) +- **Metrics:** It is recommended that every command implements an UMA metric + that records the outcome of the command. The easiest way to do this is to + transform the callback that is passed to the base class constructor via a + metrics recording lambda (e.g. + `base::BindOnce([](Result result) { base::UmaHistogramEnumeration(...); return result;}).Then(std::move(callback))`). + This guarantees the metrics are always recorded, even on shutdown.
diff --git a/chrome/browser/web_applications/commands/external_app_resolution_command.cc b/chrome/browser/web_applications/commands/external_app_resolution_command.cc index 9385031..777a64c 100644 --- a/chrome/browser/web_applications/commands/external_app_resolution_command.cc +++ b/chrome/browser/web_applications/commands/external_app_resolution_command.cc
@@ -51,6 +51,7 @@ #include "components/webapps/browser/web_contents/web_app_url_loader.h" #include "components/webapps/common/web_app_id.h" #include "content/public/browser/web_contents.h" +#include "url/origin.h" namespace web_app { @@ -722,6 +723,18 @@ web_app_info_->trusted_icons = web_app_info_->manifest_icons; web_app_info_->trusted_icon_bitmaps = web_app_info_->icon_bitmaps; + if (!web_app_info_->scope.is_valid() || + !url::IsSameOriginWith(web_app_info_->scope, + web_app_info_->start_url()) || + !base::StartsWith(web_app_info_->start_url().spec(), + web_app_info_->scope.spec(), + base::CompareCase::SENSITIVE)) { + DLOG(ERROR) << "Invalid scope " + << web_app_info_->scope.possibly_invalid_spec() + << " for start_url " << web_app_info_->start_url(); + web_app_info_->scope = web_app_info_->start_url().GetWithoutFilename(); + } + if (!apps_lock_) { apps_lock_ = std::make_unique<SharedWebContentsWithAppLock>(); command_manager()->lock_manager().UpgradeAndAcquireLock(
diff --git a/chrome/browser/web_applications/commands/generated_icon_fix_command_unittest.cc b/chrome/browser/web_applications/commands/generated_icon_fix_command_unittest.cc new file mode 100644 index 0000000..d23bcf04 --- /dev/null +++ b/chrome/browser/web_applications/commands/generated_icon_fix_command_unittest.cc
@@ -0,0 +1,183 @@ +// Copyright 2026 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/web_applications/commands/generated_icon_fix_command.h" + +#include <memory> + +#include "base/check_deref.h" +#include "base/test/test_future.h" +#include "chrome/browser/web_applications/scheduler/generated_icon_fix_result.h" +#include "chrome/browser/web_applications/test/fake_web_app_provider.h" +#include "chrome/browser/web_applications/test/fake_web_contents_manager.h" +#include "chrome/browser/web_applications/test/web_app_install_test_utils.h" +#include "chrome/browser/web_applications/test/web_app_test.h" +#include "chrome/browser/web_applications/web_app_command_manager.h" +#include "chrome/browser/web_applications/web_app_helpers.h" +#include "chrome/browser/web_applications/web_app_icon_manager.h" +#include "chrome/browser/web_applications/web_app_install_info.h" +#include "chrome/browser/web_applications/web_app_registrar.h" +#include "chrome/browser/web_applications/web_app_registry_update.h" +#include "chrome/browser/web_applications/web_app_sync_bridge.h" +#include "components/webapps/common/web_app_id.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/image/image_unittest_util.h" +#include "ui/gfx/test/sk_gmock_support.h" + +namespace web_app { +namespace { +using ::testing::Contains; +using ::testing::Pair; + +class GeneratedIconFixCommandTest : public WebAppTest { + public: + void SetUp() override { + WebAppTest::SetUp(); + test::AwaitStartWebAppProviderAndSubsystems(profile()); + } + + webapps::AppId InstallAppWithGeneratedIcon() { + auto install_info = std::make_unique<WebAppInstallInfo>( + web_app::GenerateManifestIdFromStartUrlOnly( + GURL("https://example.com/app/")), + GURL("https://example.com/app/")); + install_info->title = u"Test App"; + + webapps::AppId app_id = + test::InstallWebApp(profile(), std::move(install_info)); + CHECK( + provider().registrar_unsafe().GetAppById(app_id)->is_generated_icon()); + return app_id; + } +}; + +TEST_F(GeneratedIconFixCommandTest, Success) { + webapps::AppId app_id = InstallAppWithGeneratedIcon(); + + // Verify it has a generated icon. + EXPECT_TRUE( + provider().registrar_unsafe().GetAppById(app_id)->is_generated_icon()); + + const GURL kIconUrl("https://example.com/app/icon.png"); + + // Update the app to have a manifest icon URL. + { + ScopedRegistryUpdate update = provider().sync_bridge_unsafe().BeginUpdate(); + WebApp* app = update->UpdateApp(app_id); + app->SetManifestIcons({apps::IconInfo(kIconUrl, 144)}); + } + + // Set up the fake icon downloader to return a real icon. + auto& icon_state = fake_web_contents_manager().GetOrCreateIconState(kIconUrl); + icon_state.bitmaps = {gfx::test::CreateBitmap(144, SK_ColorGREEN)}; + + base::test::TestFuture<GeneratedIconFixResult> future; + provider().command_manager().ScheduleCommand( + std::make_unique<GeneratedIconFixCommand>( + app_id, proto::GENERATED_ICON_FIX_SOURCE_RETROACTIVE, + future.GetCallback())); + + EXPECT_EQ(future.Get(), GeneratedIconFixResult::kSuccess); + + // Verify the icon is no longer generated. + EXPECT_FALSE( + provider().registrar_unsafe().GetAppById(app_id)->is_generated_icon()); + + base::test::TestFuture<WebAppIconManager::WebAppBitmaps> bitmaps_future; + provider().icon_manager().ReadAllIcons(app_id, bitmaps_future.GetCallback()); + ASSERT_TRUE(bitmaps_future.Wait()); + + EXPECT_THAT( + bitmaps_future.Get().manifest_icons.any, + Contains(Pair(144, gfx::test::EqualsBitmap(icon_state.bitmaps[0])))); +} + +TEST_F(GeneratedIconFixCommandTest, AppUninstalled) { + webapps::AppId app_id = InstallAppWithGeneratedIcon(); + + // Uninstall the app before the command runs. + test::UninstallWebApp(profile(), app_id); + + base::test::TestFuture<GeneratedIconFixResult> future; + provider().command_manager().ScheduleCommand( + std::make_unique<GeneratedIconFixCommand>( + app_id, proto::GENERATED_ICON_FIX_SOURCE_RETROACTIVE, + future.GetCallback())); + + EXPECT_EQ(future.Get(), GeneratedIconFixResult::kAppUninstalled); +} + +TEST_F(GeneratedIconFixCommandTest, DownloadFailure) { + webapps::AppId app_id = InstallAppWithGeneratedIcon(); + + const GURL kIconUrl("https://example.com/app/icon.png"); + + { + ScopedRegistryUpdate update = provider().sync_bridge_unsafe().BeginUpdate(); + WebApp* app = update->UpdateApp(app_id); + app->SetManifestIcons({apps::IconInfo(kIconUrl, 144)}); + } + + // Set up the fake icon downloader to fail. + auto& icon_state = fake_web_contents_manager().GetOrCreateIconState(kIconUrl); + icon_state.http_status_code = 404; + icon_state.trigger_primary_page_changed_if_fetched = true; + + base::test::TestFuture<GeneratedIconFixResult> future; + provider().command_manager().ScheduleCommand( + std::make_unique<GeneratedIconFixCommand>( + app_id, proto::GENERATED_ICON_FIX_SOURCE_RETROACTIVE, + future.GetCallback())); + + EXPECT_EQ(future.Get(), GeneratedIconFixResult::kDownloadFailure); + EXPECT_TRUE( + provider().registrar_unsafe().GetAppById(app_id)->is_generated_icon()); +} + +TEST_F(GeneratedIconFixCommandTest, StillGenerated) { + webapps::AppId app_id = InstallAppWithGeneratedIcon(); + + const GURL kIconUrl("https://example.com/app/icon.png"); + + { + ScopedRegistryUpdate update = provider().sync_bridge_unsafe().BeginUpdate(); + WebApp* app = update->UpdateApp(app_id); + app->SetManifestIcons({apps::IconInfo(kIconUrl, 144)}); + } + + // Downloader returns nothing, so PopulateProductIcons will still have + // is_generated_icon = true. + auto& icon_state = fake_web_contents_manager().GetOrCreateIconState(kIconUrl); + icon_state.bitmaps = {}; + + base::test::TestFuture<GeneratedIconFixResult> future; + provider().command_manager().ScheduleCommand( + std::make_unique<GeneratedIconFixCommand>( + app_id, proto::GENERATED_ICON_FIX_SOURCE_RETROACTIVE, + future.GetCallback())); + + EXPECT_EQ(future.Get(), GeneratedIconFixResult::kStillGenerated); + EXPECT_TRUE( + provider().registrar_unsafe().GetAppById(app_id)->is_generated_icon()); +} + +TEST_F(GeneratedIconFixCommandTest, FixSourceRecorded) { + webapps::AppId app_id = InstallAppWithGeneratedIcon(); + + base::test::TestFuture<GeneratedIconFixResult> future; + provider().command_manager().ScheduleCommand( + std::make_unique<GeneratedIconFixCommand>( + app_id, proto::GENERATED_ICON_FIX_SOURCE_RETROACTIVE, + future.GetCallback())); + + ASSERT_TRUE(future.Wait()); + + const WebApp* app = provider().registrar_unsafe().GetAppById(app_id); + ASSERT_TRUE(app->generated_icon_fix().has_value()); + EXPECT_EQ(app->generated_icon_fix()->source(), + proto::GENERATED_ICON_FIX_SOURCE_RETROACTIVE); +} + +} // namespace +} // namespace web_app
diff --git a/docs/webapps/cdp-integration.md b/chrome/browser/web_applications/docs/cdp-integration.md similarity index 100% rename from docs/webapps/cdp-integration.md rename to chrome/browser/web_applications/docs/cdp-integration.md
diff --git a/docs/webapps/cdp/common.mjs b/chrome/browser/web_applications/docs/cdp/common.mjs similarity index 100% rename from docs/webapps/cdp/common.mjs rename to chrome/browser/web_applications/docs/cdp/common.mjs
diff --git a/docs/webapps/cdp/demo.mjs b/chrome/browser/web_applications/docs/cdp/demo.mjs similarity index 100% rename from docs/webapps/cdp/demo.mjs rename to chrome/browser/web_applications/docs/cdp/demo.mjs
diff --git a/docs/webapps/cdp/demo2.mjs b/chrome/browser/web_applications/docs/cdp/demo2.mjs similarity index 100% rename from docs/webapps/cdp/demo2.mjs rename to chrome/browser/web_applications/docs/cdp/demo2.mjs
diff --git a/chrome/browser/web_applications/docs/concepts.md b/chrome/browser/web_applications/docs/concepts.md new file mode 100644 index 0000000..947a914 --- /dev/null +++ b/chrome/browser/web_applications/docs/concepts.md
@@ -0,0 +1,94 @@ +## Web Apps - Desktop Concepts + +In addition to the [universal web app concepts](/docs/webapps/concepts.md), there are several concepts specific to desktop web apps and the `WebAppProvider` system. + +### User Display Mode + +In addition to the developer-specified `display` (see [Display Mode](/docs/webapps/concepts.md#display-mode)), the user can specify how they want a WebApp to be displayed, with the only option being whether to "open in a window" or not. Internally, this is expressed in the same display mode enumeration type, but only the `kStandalone` and `kBrowser` values are used to specify "open in a window" and "do not open in a window", respectively. + +#### Effective Display Mode + +The pseudocode to determine the ACTUAL display mode a WebApp is displayed in is: + +```js +if (user_display_mode == kStandalone) + return developer_specified_display_mode; +else + return kBrowser; // Open in a tab. +``` + +#### Open-in-window + +This refers to the user specifying that a WebApp should open in the developer specified display mode. + +#### Open-in-browser-tab + +This refers to the user specifying that a WebApp should NOT open in a window, and thus the WebApp, if launched, will just be opened in a browser tab. + +### App Management + +Each app has one or more 'management source', specified by the [`WebAppManagement::Type`](https://source.chromium.org/search?q=f:web_app_management_type.h%20WebAppManagement::Type) enumeration. This signifies the system that is 'managing' the install, AKA responsible for installing or uninstalling the app. Internally, the web app system will ensure that the app will only be uninstalled if there are no sources left in the app. + +When a user installs an app, the `kSync` management source is specified, because user installs are considered 'managed' by the sync system (and installs will by synced to all devices). See the `WebAppManagement` enumeration for the description of other management sources. + +Installation by certain sources can cause the app to no longer be "uninstallable" by the user. The method [`CanUserUninstallWebApp`](https://source.chromium.org/search?q=f:web_app.h%20CanUserUninstallWebApp) function determines if this is the case. + +#### Placeholder app + +There are some webapps which are managed by external sources - for example, the enterprise policy force-install apps, or the system web apps for ChromeOS. These are generally not installed by user interaction, and the WebAppProvider needs to install something for each of these apps. + +Sometimes, the installation of these apps can fail because the install url is not reachable (usually a cert or login needs to occur, and the url is redirected). When this happens, the system [can](https://source.chromium.org/search?q=ExternalInstallOptions::install_placeholder) install a "placeholder" app, which is a fake application that, when launched, navigates to the install url of the application, given by the external app manager. + +To resolve placeholder apps back into the intended installation, another external +install is triggered for the same install URL. The +[`ExternalAppResolutionCommand`](https://source.chromium.org/search?q=ExternalAppResolutionCommand) is given the ID of the existing +placeholder app. After the new app is successfully installed, the +placeholder app is uninstalled. + +### Installation State + +A web app can exist in several different installation states, which determine +its capabilities and how it's presented to the user. These states are +represented internally by the [`InstallState` enum](/chrome/browser/web_applications/proto/web_app_install_state.proto). + +* **Suggested from another device**: The app is installed on another one of + the user's devices and has been synced to the current device, but it + hasn't been fully installed yet. These apps appear in `chrome://apps` (often + grayed out) but don't have OS integrations like shortcuts or protocol + handlers. They cannot be launched in a standalone window until they are + fully installed. This state corresponds to + `InstallState::SUGGESTED_FROM_ANOTHER_DEVICE`. + +* **Installed without OS integration**: The app is installed on the device, + but without any OS-level integrations. This is common for pre-installed + apps on non-ChromeOS platforms. Like suggested apps, they cannot be + launched in a standalone window until OS integration is enabled. This state + corresponds to `InstallState::INSTALLED_WITHOUT_OS_INTEGRATION`. + +* **Installed with OS integration**: The app is fully installed and + integrated with the operating system. This includes shortcuts, protocol + handling, file handling, and the ability to run on OS login. This is the + state for user-installed apps or apps that have had their OS integration + explicitly triggered. This state corresponds to + `InstallState::INSTALLED_WITH_OS_INTEGRATION`. + +To query for apps with specific capabilities, which often depend on their +installation state, the [`WebAppFilter`](/chrome/browser/web_applications/web_app_filter.h) class should be used. +For example, `WebAppFilter::IsSuggestedApp()` can be used to find apps that are +suggested from another device. + +#### Triggering a full installation + +For an app that is only "suggested" or "installed without OS integration", a +full installation with OS integration can be triggered by: + +* The user installing the app again through a normal installation flow (e.g., + the omnibox install icon). +* The user right-clicking the app on `chrome://apps` and selecting "Install". +* Programmatically, by scheduling an + [`InstallAppLocallyCommand`](/chrome/browser/web_applications/commands/install_app_locally_command.h). + +This was designed this way because on non-ChromeOS devices, it was considered a +bad user experience to fully install all of a user's synced web apps (creating +platform shortcuts, etc.), as this might not be expected by the user on a new +device.
diff --git a/docs/webapps/how-to-create-webapp-integration-tests.md b/chrome/browser/web_applications/docs/how-to-create-webapp-integration-tests.md similarity index 76% rename from docs/webapps/how-to-create-webapp-integration-tests.md rename to chrome/browser/web_applications/docs/how-to-create-webapp-integration-tests.md index b1d1180..2a4b6a3 100644 --- a/docs/webapps/how-to-create-webapp-integration-tests.md +++ b/chrome/browser/web_applications/docs/how-to-create-webapp-integration-tests.md
@@ -1,6 +1,6 @@ # How to create WebApp Integration Tests -Please see the the [Integration Testing Framework document][integration-testing-framework] for more information about specifics. +Please see the the [Integration Testing Framework document](integration-testing-framework.md) for more information about specifics. ## 1. Familiarize yourself with the test generation, building, and running process. @@ -14,10 +14,10 @@ ## 2. Determine what actions are needed for new critical user journeys -The goal of this step is to put all critical user journeys for the feature into the [critical user journeys file][cuj-spreadsheet] and any new actions/enums into their respective files ([actions][cuj-actions-sheet], [enums][cuj-enums-sheet]). +The goal of this step is to put all critical user journeys for the feature into the [critical user journeys file](/chrome/test/webapps/data/critical_user_journeys.md) and any new actions/enums into their respective files ([actions](/chrome/test/webapps/data/actions.md), [enums](/chrome/test/webapps/data/enums.md)). Steps: -1. Explore the existing [actions][cuj-actions] and [critical user journeys][cuj-spreadsheet] to get familiar with the existing support. +1. Explore the existing [actions](/chrome/test/webapps/data/actions.md) and [critical user journeys](/chrome/test/webapps/data/critical_user_journeys.md) to get familiar with the existing support. 2. Draft, possibly just in english, what all of the critical user journeys are. * Tip: Try not to 'collapse' multiple user journeys into one. It's easier to catalog them this way, and the testing framework script will collapse journeys for you during test generation. 3. (optional) Draft what new actions (or sites) will need to be implemented for these new journeys. @@ -31,11 +31,11 @@ 1. Implement the new actions that were determined by the last step. 2. Include a simple 'manual' test to verify it is working correctly. -See the [example browsertest][regular-browsertests] file to see the manual tests at the top, written by the action authors. +See the [example browsertest](https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/ui/views/web_apps/web_app_integration_browsertest.cc) file to see the manual tests at the top, written by the action authors. -For details about how to implement actions, see [Creating Actions in the `WebAppIntegrationTestDriver`][creating-actions]. Implementing or changing actions is usually done in [`WebAppIntegrationTestDriver`](https://source.chromium.org/search?q=WebAppIntegrationTestDriver&ss=chromium). If the action only works with the sync system, then it may have to be implemented in the `TestDelegate` interface and then in the [`WebAppIntegrationTestBase`](https://source.chromium.org/search?q=WebAppIntegrationTestBase&sq=&ss=chromium). The [dPWA team](#contact-the-team) should have informed you if there was anything specific you need to do here. +For details about how to implement actions, see [Creating Actions in the `WebAppIntegrationTestDriver`](integration-testing-framework.md#creating-action-implementations). Implementing or changing actions is usually done in [`WebAppIntegrationTestDriver`](https://source.chromium.org/search?q=WebAppIntegrationTestDriver&ss=chromium). If the action only works with the sync system, then it may have to be implemented in the `TestDelegate` interface and then in the [`WebAppIntegrationTestBase`](https://source.chromium.org/search?q=WebAppIntegrationTestBase&sq=&ss=chromium). The [dPWA team](#contact-the-team) should have informed you if there was anything specific you need to do here. -Before submitting, make sure to also [run the trybots on mac][running-mac-tests], as these are sometimes disabled on the CQ. +Before submitting, make sure to also [run the trybots on mac](integration-testing-framework.md#running-the-tests-on-mac), as these are sometimes disabled on the CQ. If in Step 2 above the team concluded a "Site" must be modified or created, these are located in the [test data directory](/chrome/test/data/web_apps/). @@ -44,21 +44,21 @@ ### Why write a 'manual' test when they are about to ge generated? Implementing an action is often flaky and uncovers bugs. If all of the tests are in the first CL and it has problems, this causes large reverts or (even worse) sheriffs to manually disable many tests over the next few days. To prevent this complexity, this first CL should only include a few manual tests to make sure that everything is working correctly before more tests are generated. -## 4. Add the new Critical User Journeys to the [file][cuj-spreadsheet], generate, and submit them. +## 4. Add the new Critical User Journeys to the [file](/chrome/test/webapps/data/critical_user_journeys.md), generate, and submit them. Finally, now that the changes are implemented and tested, they can be used in generated critical user journey tests. ### 4.1. Mark the action as supported. -Add to (or modify) this [file][supported-actions] marking the new actions as supported. +Add to (or modify) this [file](../../chrome/test/webapps/data/framework_supported_actions.csv) marking the new actions as supported. -To have the script actually generate tests using the new actions, they must be marked as supported in the [supported actions file][supported-actions]. The support is specified by a symbol per platform: +To have the script actually generate tests using the new actions, they must be marked as supported in the [supported actions file](../../chrome/test/webapps/data/framework_supported_actions.csv). The support is specified by a symbol per platform: - 🌕 - Full coverage - This means that the driver implements this action in a way that completely matches (or almost matches) the code paths that are used when the user triggers this action. - 🌓 - Partial coverage - This means that the testing framework implements this action in a way that accomplishes the state change or check, but does not fully match the code path that is used when the user triggers this action. - 🌑 - No coverage - This means the action is not supported and any tests using this action will only be partially generated. -If the action you have implemented is not present in the [file][supported-actions], please add it. +If the action you have implemented is not present in the [file](../../chrome/test/webapps/data/framework_supported_actions.csv), please add it. ### 4.2. Generate test changes. @@ -69,7 +69,7 @@ ``` The output should: -1. Generate a coverage report for the change in the [data directory][script-data-dir]. +1. Generate a coverage report for the change in the [data directory](../../chrome/test/webapps/data/). 2. Print new tests that need to be manually copied to the integration browsertest files. 3. Print out test ids that need to be removed. @@ -85,7 +85,7 @@ After all tests are added, `git cl format` is often required. It's a good idea to test all of the new tests locally if you can, and then after local verification a patch can be uploaded, the the trybots can be run, and a review can be requested from the team. -Before submitting, make sure to also [run the trybots on mac][running-mac-tests], as these are sometimes disabled on the CQ. +Before submitting, make sure to also [run the trybots on mac](integration-testing-framework.md#running-the-tests-on-mac), as these are sometimes disabled on the CQ. ### 4.3. Run new tests locally. @@ -143,7 +143,7 @@ - "deny without remember" will NOT launch the app. If the file is launched again, the user should be presented with the dialog again. - "deny with remember" will NOT launch the app and unregister the app as a file handler. The operating system should no longer have the file registered with the web app. -The existing [actions][cuj-actions-sheet] already have a lot of support for installing, launching, checking if a window was created, etc. The following changes will have to happen: +The existing [actions](/chrome/test/webapps/data/actions.md) already have a lot of support for installing, launching, checking if a window was created, etc. The following changes will have to happen: - Modify an existing site (maybe Site B?), or create a new site (Site D? File Handler?), which handles a test file type in it's manifest. - Because multiple browsertests can be running at the same time on a trybot, this type will probably have to be uniquely generated per test to avoid conflicts. - Action 1: detect if a file type is registered on an operating system. @@ -156,14 +156,3 @@ To contact the team for help, send an email to pwa-dev@chromium.org and/or post on #pwas on Chromium Slack. -[cuj-spreadsheet]: /chrome/test/webapps/data/critical_user_journeys.md -[cuj-actions-sheet]: /chrome/test/webapps/data/actions.md -[cuj-enums-sheet]: /chrome/test/webapps/data/enums.md -[regular-browsertests]: https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/ui/views/web_apps/web_app_integration_browsertest.cc -[regular-browsertests-wml]: https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/ui/views/web_apps/web_app_integration_browsertest_mac_win_linux.cc -[sync-browsertests-wml]: https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/sync/test/integration/two_client_web_apps_integration_test_mac_win_linux.cc -[supported-actions]: ../../chrome/test/webapps/data/framework_supported_actions.csv -[script-data-dir]: ../../chrome/test/webapps/data/ -[integration-testing-framework]: integration-testing-framework.md -[creating-actions]: integration-testing-framework.md#creating-action-implementations -[running-mac-tests]: integration-testing-framework.md#running-the-tests-on-mac
diff --git a/chrome/browser/web_applications/docs/installation_pipeline.md b/chrome/browser/web_applications/docs/installation_pipeline.md new file mode 100644 index 0000000..2b18a26 --- /dev/null +++ b/chrome/browser/web_applications/docs/installation_pipeline.md
@@ -0,0 +1,127 @@ +## [Web Apps](../README.md) - Installation + +Installing a webapp can come from a variety of channels. This section serves to enumerate them all and show how they fit together in the installation pipeline. + +### Flowchart + +Here is a graphic of the installation flow: + + + +[https://tinyurl.com/dpwa-installation-flowchart](https://tinyurl.com/dpwa-installation-flowchart) + +Note: The ExternallyManagedAppManager adds a few steps before this, and will sometimes (for placeholder apps) build a custom `WebAppInstallInfo` object to skip the 'build' steps. + +### Installation Commands + +There are a variety of [commands](https://source.chromium.org/search?q=f:install%20f:web_applications%2Fcommands&sq=&ss=chromium) used to install web apps. If introducing a new installation source, consider making a new command to isolate your operation (and prevent it from being complicated by other use-cases). + +### Installation Sources + +There are a variety of installation sources and expectations tied to those sources. + +#### Omnibox install icon + +User-initiated installation. To make the omnibox install icon visible, the document must: _Be promotable and installable_. NOT be inside of the scope of an installed WebApp with an effective [display mode display](concepts.md#effective-display-mode) mode that isn't `kBrowser`. + +Triggers an install view that will show the name & icon to the user to confirm install. If the manifest also includes screenshots with a wide form-factor, then a more detailed install dialog will be shown. + +This uses the [`FetchManifestAndInstallCommand`](https://source.chromium.org/search?q=FetchManifestAndInstallCommand&ss=chromium), providing just the `WebContents` of the installable page. + +Fails if, after the user clicks : _After clicking on the install icon, the `WebContents` is no longer_ [_promotable_](concepts.md#promotable), _skipping engagement checks_. The user rejects the installation dialog. + +#### 3-dot menu option "Install {App_Name}..." + +User-initiated installation. To make the install menu option visible, the document must: _Be promotable and installable_. NOT be inside of the scope of an installed WebApp with an effective [display mode display](concepts.md#effective-display-mode) mode that isn't `kBrowser`. + +Triggers an install view that will show the name & icon to the user to confirm install. If the manifest also includes screenshots with a wide form-factor, then a more detailed install dialog will be shown. + +Calls [`FetchManifestAndInstallCommand`](https://source.chromium.org/search?q=FetchManifestAndInstallCommand&ss=chromium) with the `WebContents` of the installable page, and `fallback_behavior = FallbackBehavior::kUseFallbackInfoWhenNotInstallable`. + +Fails if: _The user rejects the installation dialog_. + +Notably, this option does not go through the same exact pathway as the [omnibox install icon](#omnibox-install-icon), as it shares the call-site as the "Create Shortcut" method below. The main functional difference here is that if the site becomes no longer [promotable](concepts.md#promotable) in between clicking on the menu option and the install actually happening, it will not fail and instead fall back to a fake manifest and/or fake icons based on the favicon. Practically, this option doesn't show up if the site is not [promotable](concepts.md#promotable). Should it share installation pathways as the the [omnibox install icon?](#omnibox-install-icon) Probably, yes. + +#### 3-dot menu option "Create Shortcut..." + +User-initiated installation. This menu option is always available, except for internal chrome urls like chrome://settings. + +Prompts the user whether the shortcut should "open in a window". If the user checks this option, then the resulting WebApp will have the [user display](concepts.md#user-display-mode) set to `kStandalone` / open-in-a-window. + + +The document does not need to have a manifest for this install path to work. If no manifest is found, then a fake one is created with `start_url` equal to the document url, `name` equal to the document title, and the icons are generated from the favicon (if present). + +Calls [`FetchManifestAndInstallCommand`](https://source.chromium.org/search?q=FetchManifestAndInstallCommand&ss=chromium) with the `WebContents` of the installable page, and `fallback_behavior = FallbackBehavior::kAllowFallbackDataAlways`. + +Fails if: _The user rejects the shortcut creation dialog_. + +#### Externally Managed Apps + +These installations are more customizable than user installations, as these external app management surfaces need to specify all of the options up front (e.g. create shortcut on desktop, open in window, run on login, etc). The [`ExternalAppResolutionCommand`](https://source.chromium.org/search?q=ExternalAppResolutionCommand&sq=&ss=chromium%2Fchromium%2Fsrc) is used for this purpose. + +The general installation flow of an externally managed app is: + +1. A call to [`ExternallyManagedAppProvider::SynchronizeInstalledApps`](https://source.chromium.org/search?q=ExternallyManagedAppProvider::SynchronizeInstalledApps) +1. Finding all apps that need to be uninstalled and uninstalling them, find all + apps that need to be installed and: +1. Enqueue an `ExternalAppResolutionCommand` for each app to start resolving + what the final behavior should be. +1. Each command loads the url for the app. +1. If the url is successfully loaded, the command proceeds with a regular + installation pipeline (fetching manifest, icons, etc). +1. If the url fails to fully load (usually a redirect if the user needs to sign + in or corp credentials are not installed), and the external app manager + specified a [placeholder app was required](https://source.chromium.org/search?q=ExternalInstallOptions::install_placeholder) then an `InstallPlaceholderJob` + is used to install a placeholder app. + +These placeholder apps are not meant to stay, and to replace them with the intended apps, the following occurs: + +1. When a new installation is triggered for the same install URL, the + `ExternalAppResolutionCommand` is given the ID of the existing placeholder + app. +1. After the new app is successfully installed, the placeholder app is + uninstalled. + +#### Sync + +When an app is installed via sync on a non-ChromeOS device, it is initially +installed in a "suggested" state (`InstallState::SUGGESTED_FROM_ANOTHER_DEVICE`) +without full OS integration. See [Installation State](concepts.md#installation-state) in the concepts doc +for more details. On ChromeOS, synced apps are always fully installed with OS +integration. + +##### Retry on startup + +Sync installs have a few extra complications: + +- They need to be immediately saved to the database & be installed eventually. +- Many are often queued up during a new profile sign-in, and it's not uncommon for the user to quit before the installation queue finishes. + +Due to this, unlike other installs, a special [`WebApp::is_from_sync_and_pending_installation`](https://source.chromium.org/search?q=WebApp::is_from_sync_and_pending_installation) (protobuf variable is saved in the database. WebApps with this set to true are treated as not fully installed, and are often left out of app listings. This variable is reset back to `false` when the app is finished installing. + +To handle the cases above, on startup when the database is loaded, any WebApp with `is_from_sync_and_pending_installation` of `true` will be re-installed inside of [`WebAppSyncBridge::MaybeInstallAppsFromSyncAndPendingInstallation`](https://source.chromium.org/search?q=WebAppSyncBridge::MaybeInstallAppsFromSyncAndPendingInstallation) + +### Installation State Modifications + +#### Triggering a full installation + +On non-ChromeOS devices, an app can be in a "suggested" state (e.g. from sync) +or "installed without OS integration" (e.g. preinstalled). To trigger a full +installation with OS integration, the user can: +* Install the app again via a normal installation flow (e.g. using the + omnibox install icon). +* Right-click the app on `chrome://apps` and select "Install". + +Programmatically, this is handled by the [`InstallAppLocallyCommand`](https://source.chromium.org/search?q=InstallAppLocallyCommand). + +#### Creating Shortcuts + + +On non-ChromeOS devices, an app can be [not locally installed](concepts.md#installation-state). To become locally installed, the user can follow a normal install method (the install icon will show up), or they can interact with the app on `chrome://apps`. + +The `chrome://apps` code is unique here, and instead of re-installing the app, it schedules an [`InstallAppLocallyCommand`](https://source.chromium.org/search?q=InstallAppLocallyCommand) to set the app as locally installed and trigger OS integration. + +#### Creating Shortcuts + +Similarly to above, in `chrome://apps` the user can "Create Shortcuts..." for a web app. This should overwrite any shortcuts already created, and basically triggers OS integration to install shortcuts again via an [`OsIntegrationSynchronizeCommand`](https://source.chromium.org/search?q=OsIntegrationSynchronizeCommand). +
diff --git a/docs/webapps/integration-testing-framework.md b/chrome/browser/web_applications/docs/integration-testing-framework.md similarity index 74% rename from docs/webapps/integration-testing-framework.md rename to chrome/browser/web_applications/docs/integration-testing-framework.md index 1949e63..bffef57 100644 --- a/docs/webapps/integration-testing-framework.md +++ b/chrome/browser/web_applications/docs/integration-testing-framework.md
@@ -7,18 +7,18 @@ The WebAppProvider system has very wide action space and testing state interactions between all of the subsystems is very difficult. The integration testing framework is intended to help testing critical user journeys for installable web apps in a scalable fashion. The framework and process is broken down into the following pieces: -1. A list of [critical user journeys][cuj-spreadsheet] and the [actions][cuj-actions-sheet] used to make those journeys. -2. A [script][generate-script] that can process these (along with information about which action is supported by which platform). -3. [Tests][default-tests] generated by the script that use the [`WebAppIntegrationTestDriver`][test-driver] to execute actions. -4. [Coverage][coverage-win] information about what percentage of the critical user journeys are covered. +1. A list of [critical user journeys](/chrome/test/webapps/data/critical_user_journeys.md) and the [actions](/chrome/test/webapps/data/actions.md) used to make those journeys. +2. A [script](/chrome/test/webapps/generate_framework_tests_and_coverage.py) that can process these (along with information about which action is supported by which platform). +3. [Tests](/chrome/browser/ui/views/web_apps/web_app_integration_browsertest.cc) generated by the script that use the [`WebAppIntegrationTestDriver`](/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.h) to execute actions. +4. [Coverage](/chrome/test/webapps/coverage/coverage_win.tsv) information about what percentage of the critical user journeys are covered. How-tos / guides: -* [How to create WebApp Integration Tests][how-to-create] +* [How to create WebApp Integration Tests](how-to-create-webapp-integration-tests.md) * [Disabling a test](#disabling-a-test) -* [Why is this test failing?][why-is-this-test-failing] +* [Why is this test failing?](why-is-this-test-failing.md) Related: - * [WebAppProvider README.md](/docs/webapps/README.md) + * [WebAppProvider README.md](../README.md) ## When to add integration tests? Any web app feature (or any code in general) should have a combination of unit tests and browser tests that focus on testing the specific feature itself. Unit tests are the least likely to become flaky, and allow fine-grained testing of a system. Browser tests are more likely to be flaky but enable testing with most of the system running. Regular unit tests or browser tests should be used for testing system parts in isolation and for testing minute details like handling of error cases. @@ -57,14 +57,14 @@ #### Action Arguments When creating tests, there emerged a common scenario where a given action could be applied to multiple different sites. For example, the “navigate the browser to an installable site” action was useful if “site” could be customized. -To accept arguments, list the argument [types][cuj-enums-sheet] you wish to accept in the "Argument Types" column in the actions [file][cuj-actions-sheet]. If an required argument type does not exist, please add it to that [file][cuj-enums-sheet]. +To accept arguments, list the argument [types](/chrome/test/webapps/data/enums.md) you wish to accept in the "Argument Types" column in the actions [file](/chrome/test/webapps/data/actions.md). If an required argument type does not exist, please add it to that [file](/chrome/test/webapps/data/enums.md). When a test specified as action with arguments, it can also specify `ArgType::All`, which will create a separate test for every possible value of that argument. To allow for future de-parsing of modes (when generating C++ tests), modes will always be PascalCase. ##### Default argument values -Each [enumeration][cuj-enums-sheet] can specify a "default" enumeration value that is used if the test does not specify an argument value. This is done by a `*` character. +Each [enumeration](/chrome/test/webapps/data/enums.md) can specify a "default" enumeration value that is used if the test does not specify an argument value. This is done by a `*` character. #### Parameterized Action To help with testing scenarios like outlined above, an action can be defined that references or 'turns into' a set of non-parameterized actions. For example, an action `install_windowed` can be created and reference the set of actions `install_omnibox_icon`, `install_menu_option`, `install_create_shortcut_windowed`, `add_policy_app_windowed_shortcuts`, and `add_policy_app_windowed_no_shortcuts`. When a test case includes this action, it will generate multiple tests in which the parameterized action is replaced with the non-parameterized action. @@ -109,29 +109,29 @@ ### Sync Partition and Default Partition Due to some browsertest support limitations, certain actions are only supported in the sync testing framework. Because of this, the script supports a separate "partition" of tests for any test that uses sync actions. This means that at test output time, a test will either go in the "sync" partition or the "default" partition. -See the [sync tests design doc][sync-tests-dd] for more information. +See the [sync tests design doc](https://docs.google.com/document/d/139ktCajbmbFKh4T-vEhipTxilyYrXf_rlCBHIvrdeSg/edit) for more information. ## Script Design & Usage -The [script][generate-script] takes the following information: -* A list of [action][cuj-actions-sheet]-based [tests][cuj-spreadsheet] which fully test the WebAppProvider system (a.k.a. required-coverage tests). -* A list of actions [supported][framework-supported-actions] by the integration test framework (per-platform). +The [script](/chrome/test/webapps/generate_framework_tests_and_coverage.py) takes the following information: +* A list of [action](/chrome/test/webapps/data/actions.md)-based [tests](/chrome/test/webapps/data/critical_user_journeys.md) which fully test the WebAppProvider system (a.k.a. required-coverage tests). +* A list of actions [supported](/chrome/test/webapps/data/framework_supported_actions.csv) by the integration test framework (per-platform). The results of running the script is: * Console output (to stdout) of the minimal number of tests (per-platform) to run to achieve the maximum coverage of the critical user journeys. * If tests already exist, then these are taken into account and not printed. * If any existing tests are unnecessary, then the script will inform the developer that they can be removed. -* The resulting [coverage][coverage-win] of the system (with required-coverage tests as 100%). +* The resulting [coverage](/chrome/test/webapps/coverage/coverage_win.tsv) of the system (with required-coverage tests as 100%). -See the [design doc][design-doc] for more information and links. +See the [design doc](https://docs.google.com/document/d/e/2PACX-1vTFI0sXhZMvvg1B3sctYVUe64WbLVNzuXFUa6f3XyYTzKs2JnuFR8qKNyXYZsxE-rPPvsq__4ZCyrcS/pub) for more information and links. ### Downloading test data -The test data is hosted in this [spreadsheet][cuj-spreadsheet]. To download the latest copy of the data, run the included script: +The test data is hosted in this [spreadsheet](/chrome/test/webapps/data/critical_user_journeys.md). To download the latest copy of the data, run the included script: ```sh ./chrome/test/webapps/download_data_from_sheet.py ``` -This will download the data from the sheet into csv files in the [data/][script-data-dir] directory: +This will download the data from the sheet into csv files in the [data/](/chrome/test/webapps/data/) directory: * `actions.csv` This describes all actions that can be used in the required coverage tests (processed or unprocessed). * `coverage_required.csv` This is the full list of all tests needed to fully cover the Web App system. The first column specifies the platforms for testing, and the test starts on the second column. @@ -142,19 +142,19 @@ ```sh chrome/test/webapps/generate_framework_tests_and_coverage.py ``` -This uses the files in `chrome/test/webapps/data` and existing browsertests on the system (see `custom_partitions` and `default_partitions` in [`generate_framework_tests_and_coverage.py`][generate-script]) to: +This uses the files in `chrome/test/webapps/data` and existing browsertests on the system (see `custom_partitions` and `default_partitions` in [`generate_framework_tests_and_coverage.py`](/chrome/test/webapps/generate_framework_tests_and_coverage.py)) to: #### 1) Print all detected browsertests' changes to `stdout` or to existing test files. The script can remove tests (--delete-in-place) or add tests (--add-to-file) to existing test files. It is not smart enough to automatically create new test files and add tests to them because it usually involves modifying the BUILD file. If the test file does not exist, the file name and the tests will be printed out to `stdout` instead. If none of these flags are used, the script prints out the tests that need to be added or removed to `stdout` and have the tests match what it expects. It assumes: - * Browsertests are correctly described by the `TestPartitionDescription`s in [`generate_framework_tests_and_coverage.py`][generate-script]. + * Browsertests are correctly described by the `TestPartitionDescription`s in [`generate_framework_tests_and_coverage.py`](/chrome/test/webapps/generate_framework_tests_and_coverage.py). * Browsertests with the per-platform suffixes (e.g. `_mac`, `_win`, etc) are only run on those platforms This process doesn't modify the browsertests that are disabled by sheriffs. The script runner is thus expected to make the requested changes manually. In the rare case that a test is moving between files (if we are enabling a test on a new platform, for example), then the script runner should be careful to copy any sheriff changes to the browsertest as well. #### 2) Generate per-platform processed required coverage `tsv` files in `chrome/test/webapps/coverage` -These are the processed required coverage tests with markers per action to allow a conditional formatter (like the one [here][cuj-coverage-sheet]) to highlight what was and was not covered by the testing framework. +These are the processed required coverage tests with markers per action to allow a conditional formatter (like the one [here](https://docs.google.com/spreadsheets/u/1/d/e/2PACX-1vSbO6VsnWsq_9MN6JEXlL8asMqATHc2-pz9ed_Jlf5zHJGg2KAtegsorHqkQ5kydU6VCqebv_1gUCD5/pubhtml?gid=884228058)) to highlight what was and was not covered by the testing framework. * These files also contain a coverage % at the top of the file. Full coverage is the percent of the actions of the processed required coverage test that were executed and fully covered by the framework. Partial coverage also includes actions that are partially covered by the framework. * This includes loss of coverage from any disabled tests. Cool! @@ -190,29 +190,29 @@ To help debug or explore further, please see the [`graph_cli_tool.py`](graph_cli_tool.py) script which includes a number of command line utilities to process the various files. -Both this file and the [`generate_framework_tests_and_coverage.py`][generate-script] file support the `-v` option to print out informational logging. +Both this file and the [`generate_framework_tests_and_coverage.py`](/chrome/test/webapps/generate_framework_tests_and_coverage.py) file support the `-v` option to print out informational logging. ### Uploading test CLs -Once the tests have been generated from the CUJs, always run [`generate_framework_tests_and_coverage.py`][generate-script] as a sanity check to ensure that this outputs nothing in the terminal. This means that the [critical user journeys][cuj-spreadsheet] and the generated tests across all files are in sync and no new tests need to be generated. If this outputs something on the terminal, perform the debugging steps outlined above to understand why the two converge. +Once the tests have been generated from the CUJs, always run [`generate_framework_tests_and_coverage.py`](/chrome/test/webapps/generate_framework_tests_and_coverage.py) as a sanity check to ensure that this outputs nothing in the terminal. This means that the [critical user journeys](/chrome/test/webapps/data/critical_user_journeys.md) and the generated tests across all files are in sync and no new tests need to be generated. If this outputs something on the terminal, perform the debugging steps outlined above to understand why the two converge. -## [`WebAppIntegrationTestDriver`][test-driver] and Browsertest Implementation +## [`WebAppIntegrationTestDriver`](/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.h) and Browsertest Implementation -After the script has output the tests that are needed, they still need to be compiled and run by something. The [`WebAppIntegrationTestDriver`][test-driver] is what runs the actions, and the browsertests themselves are put into specific files based on which partition they will be run in (default or sync), and which platforms will be running them. +After the script has output the tests that are needed, they still need to be compiled and run by something. The [`WebAppIntegrationTestDriver`](/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.h) is what runs the actions, and the browsertests themselves are put into specific files based on which partition they will be run in (default or sync), and which platforms will be running them. These are all of the files that make up the browsertest and browsertest support of the dPWA integration test framework: -* [`WebAppIntegrationTestDriver`][test-driver] - This class implements most actions that are used by the generated tests. -* [`web_app_integration_browsertest.cc`][default-tests] - These are the cross-platform tests in the default partition. - * [`web_app_integration_browsertest_mac_win_linux.cc`][default-tests-mwl] - These are the default partition tests that only run on mac, windows, and linux. - * [`web_app_integration_browsertest_cros.cc`][default-tests-cros]. +* [`WebAppIntegrationTestDriver`](/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.h) - This class implements most actions that are used by the generated tests. +* [`web_app_integration_browsertest.cc`](/chrome/browser/ui/views/web_apps/web_app_integration_browsertest.cc) - These are the cross-platform tests in the default partition. + * [`web_app_integration_browsertest_mac_win_linux.cc`](/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_mac_win_linux.cc) - These are the default partition tests that only run on mac, windows, and linux. + * [`web_app_integration_browsertest_cros.cc`](/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_cros.cc). * `two_client_web_apps_integration_test_*` - These are the tests in the sync partition. - * [`two_client_web_apps_integration_test_mac_win_linux.cc`][sync-tests-mwl] - * [`two_client_web_apps_integration_test_cros.cc`][sync-tests-cros] + * [`two_client_web_apps_integration_test_mac_win_linux.cc`](/chrome/browser/sync/test/integration/two_client_web_apps_integration_test_mac_win_linux.cc) + * [`two_client_web_apps_integration_test_cros.cc`](/chrome/browser/sync/test/integration/two_client_web_apps_integration_test_cros.cc) ### Creating Action Implementations -The driver implements all actions for the generated tests. For tests in the sync partition (which require the functionality of the [`SyncTest`][sync-test-base] base class), some actions are delegated to the [`two_client_web_apps_integration_test_base.h`][sync-tests-base]). +The driver implements all actions for the generated tests. For tests in the sync partition (which require the functionality of the [`SyncTest`](chrome/browser/sync/test/integration/sync_test.h) base class), some actions are delegated to the [`two_client_web_apps_integration_test_base.h`](/chrome/browser/sync/test/integration/two_client_web_apps_integration_test_base.h)). Testing actions must: * Call the appropriate `BeforeState*Action()` and `AfterState*Action()` functions inside of their function body. @@ -254,22 +254,22 @@ ### Modifying a test -If you need to modify a test, that means you are changing a critical user journey on the platform. If that is intentional, then modifications must be done to the [critical-user-journey markdown file][cuj-spreadsheet], and not the tests - they are generated from this markdown and should always stay in-sync. +If you need to modify a test, that means you are changing a critical user journey on the platform. If that is intentional, then modifications must be done to the [critical-user-journey markdown file](/chrome/test/webapps/data/critical_user_journeys.md), and not the tests - they are generated from this markdown and should always stay in-sync. ## Understanding and Implementing Test Cases Actions are the basic building blocks of integration tests. A test is a sequence of actions. Each action has a name that must be a valid C++ identifier. -Actions are defined (and can be modified) in [this][cuj-actions-sheet] sheet. Tests are defined (and can be modified) in [this][cuj-spreadsheet] sheet. +Actions are defined (and can be modified) in [this](/chrome/test/webapps/data/actions.md) sheet. Tests are defined (and can be modified) in [this](/chrome/test/webapps/data/critical_user_journeys.md) sheet. ### Action Creation & Specification -[Actions][cuj-actions-sheet] are the building blocks of tests. +[Actions](/chrome/test/webapps/data/actions.md) are the building blocks of tests. This section is meant to help describe how the testing script works internally, but may not be helpful for those just looking to simply run the script. #### Templates -To help making test writing less repetitive, actions are described as templates in the [actions][cuj-actions-sheet] spreadsheet. Action templates specify actions while avoiding rote repetition. Each action template has a name (the **action base name**). Each action template supports arguments, which must be defined in the [enumeration sheet][cuj-enums-sheet]. Parameter values must also be valid C++ identifiers. +To help making test writing less repetitive, actions are described as templates in the [actions](/chrome/test/webapps/data/actions.md) spreadsheet. Action templates specify actions while avoiding rote repetition. Each action template has a name (the **action base name**). Each action template supports arguments, which must be defined in the [enumeration sheet](/chrome/test/webapps/data/enums.md). Parameter values must also be valid C++ identifiers. An action template without arguments specifies one action whose name matches the template. For example, the `check_tab_created` template generates the `check_tab_created` action. @@ -298,9 +298,9 @@ ### Test Creation & Specification -[Tests][cuj-spreadsheet] are created specifying actions. +[Tests](/chrome/test/webapps/data/critical_user_journeys.md) are created specifying actions. -For a step-by-step guide for creating a new integration test, see [this guide][how-to-create]. +For a step-by-step guide for creating a new integration test, see [this guide](how-to-create-webapp-integration-tests.md). #### Mindset The mindset for test creation and organization is to really exhaustively check every possible string of user actions. The framework will automatically combine tests that are the same except for state check actions. They are currently organized by: @@ -318,26 +318,5 @@ The framework is designed to be able to collapse tests that contain common non-'state-check' actions, so adding a new test does not always mean that a whole new test will be run by the framework. Sometimes it only adds a few extra state-check actions in an existing test. -If new actions are required for a test, see [How to create WebApp Integration Tests][how-to-create] for more information about how to add a new action. +If new actions are required for a test, see [How to create WebApp Integration Tests](how-to-create-webapp-integration-tests.md) for more information about how to add a new action. -[design-doc]: https://docs.google.com/document/d/e/2PACX-1vTFI0sXhZMvvg1B3sctYVUe64WbLVNzuXFUa6f3XyYTzKs2JnuFR8qKNyXYZsxE-rPPvsq__4ZCyrcS/pub -[cuj-spreadsheet]: /chrome/test/webapps/data/critical_user_journeys.md -[cuj-actions-sheet]: /chrome/test/webapps/data/actions.md -[cuj-enums-sheet]: /chrome/test/webapps/data/enums.md -[cuj-coverage-sheet]: https://docs.google.com/spreadsheets/u/1/d/e/2PACX-1vSbO6VsnWsq_9MN6JEXlL8asMqATHc2-pz9ed_Jlf5zHJGg2KAtegsorHqkQ5kydU6VCqebv_1gUCD5/pubhtml?gid=884228058 -[how-to-create]: how-to-create-webapp-integration-tests.md -[script-data-dir]: /chrome/test/webapps/data/ -[script-output-dir]: /chrome/test/webapps/output/ -[test-driver]: /chrome/browser/ui/views/web_apps/web_app_integration_test_driver.h -[default-tests]: /chrome/browser/ui/views/web_apps/web_app_integration_browsertest.cc -[default-tests-mwl]: /chrome/browser/ui/views/web_apps/web_app_integration_browsertest_mac_win_linux.cc -[default-tests-cros]: /chrome/browser/ui/views/web_apps/web_app_integration_browsertest_cros.cc -[sync-tests-mwl]: /chrome/browser/sync/test/integration/two_client_web_apps_integration_test_mac_win_linux.cc -[sync-tests-cros]: /chrome/browser/sync/test/integration/two_client_web_apps_integration_test_cros.cc -[sync-tests-base]: /chrome/browser/sync/test/integration/two_client_web_apps_integration_test_base.h -[sync-tests-dd]: https://docs.google.com/document/d/139ktCajbmbFKh4T-vEhipTxilyYrXf_rlCBHIvrdeSg/edit -[generate-script]: /chrome/test/webapps/generate_framework_tests_and_coverage.py -[coverage-win]: /chrome/test/webapps/coverage/coverage_win.tsv -[framework-supported-actions]: /chrome/test/webapps/data/framework_supported_actions.csv -[sync-test-base]: chrome/browser/sync/test/integration/sync_test.h -[why-is-this-test-failing]: why-is-this-test-failing.md
diff --git a/docs/webapps/isolated_web_apps.md b/chrome/browser/web_applications/docs/isolated_web_apps.md similarity index 100% rename from docs/webapps/isolated_web_apps.md rename to chrome/browser/web_applications/docs/isolated_web_apps.md
diff --git a/docs/webapps/manifest_representations.md b/chrome/browser/web_applications/docs/manifest_representations.md similarity index 96% rename from docs/webapps/manifest_representations.md rename to chrome/browser/web_applications/docs/manifest_representations.md index a4c23fe94..f1c16be3 100644 --- a/docs/webapps/manifest_representations.md +++ b/chrome/browser/web_applications/docs/manifest_representations.md
@@ -1,4 +1,4 @@ -# [Web Apps](../../README.md) - Manifest representations in code +# [Web Apps](../README.md) - Manifest representations in code This is a list of all the places where we represent [manifest](https://w3c.github.io/manifest/) data in our codebase.
diff --git a/chrome/browser/web_applications/docs/manifest_update_process.md b/chrome/browser/web_applications/docs/manifest_update_process.md new file mode 100644 index 0000000..820af20 --- /dev/null +++ b/chrome/browser/web_applications/docs/manifest_update_process.md
@@ -0,0 +1,58 @@ +# Manifest Update Process + +High level information: https://web.dev/manifest-updates/ + +The manifest update process is required whenever a new manifest is served to an existing web_app, which would mean that the database entries corresponding to that web application needs to be updated. With the [predictable app updating flag enabled](https://source.chromium.org/chromium/chromium/src/+/main:content/public/common/content_features.cc?q=%22kWebAppPredictableAppUpdating%22%20f:.*_features.cc&ss=chromium%2Fchromium%2Fsrc), the following information sheds some light on how the +manifest update system works in Chrome. + +## Things to note: +- Updates to security sensitive fields [1] (like `name`, `icon` and `short_name`) require explicit user approval. +- Updates to the app's icon follow the `Cache-Control:immutable` behavior of HTML, where updates are triggered **ONLY** if the icon url has changed. + - If the icon url **HAS** changed, but the a pixel by pixel comparison of the old and new icon shows a difference of <10%, the icon is updated silently. +- Updates to non-security sensitive fields are silent. + +This helps ensure: +- Network resources are saved and that icons are downloaded ONLY if the corresponding metadata for them have changed. +- Developers have a way of choosing when to trigger an update to their app's identities. +- The UX affordances are designed in a way to provide more control to the user on +what to do, should there be user intervention required for an update. + +## Steps to trigger a manifest update: +Whenever the tab has kicked off a [navigation to an url for a web_app](https://source.chromium.org/search?q=WebAppTabHelper::PrimaryPageChanged), a check is kicked off to determine if a manifest update is required or not. The update process is aborted if the following conditions are satisfied: + - If the app is not installed. + - If the installed app is a [System Web App](https://source.chromium.org/search?q=SystemWebAppManager), [placeholder app](https://source.chromium.org/search?q=Placeholder%20f:webapps%2Fconcepts.md) or [Isolated Web App](https://source.chromium.org/search?q=%22WebAppFilter::IsIsolatedApp%22&sq=&ss=chromium%2Fchromium%2Fsrc). + +Once the update is allowed to proceed, the following steps happen: + - Wait for the [page to finish loading and the manifest url to be loaded](https://source.chromium.org/search?q=ManifestUpdateManager%20PreUpdateWebContentsObserver&sq=). + - On successful page load, the [`ManifestSilentUpdateCommand`](https://source.chromium.org/search?q=ManifestSilentUpdateCommand&sq=) takes over to perform the following tasks: + - Fetching the manifest and all metadata defined in it for the url. + - Identifying if the update can be done silently, or it requires user intervention, or both. + - Parts of the update that happen silently is completed. + - If user intervention is required, pending update metadata is stored in the web app. + - As an implementation detail, for icon changes, the "new icons" are also stored on the disk inside the profile directory to conserve network resources and prevent [redownloading](https://source.chromium.org/search?q=WebAppIconManager::WritePendingIconData). + +## Steps to apply pending updates: + +If the update requires user intervention, that is surfaced to the user in a non-blocking way +by showing an expanded label saying [`App Update Available`](https://source.chromium.org/search?q=WebAppMenuButton::CanShowPendingUpdate&sq=) in a standalone app window. Apps running in a browser tab do not see that label. + +Clicking that label triggers the three dot menu dropdown, that has a `Review App Update` entrypoint. Clicking on that triggers the [`WebAppUpdateReviewDialog`](https://source.chromium.org/search?q=WebAppUpdateReviewDialog&sq=&ss=chromium%2Fchromium%2Fsrc), which shows the before and after state of the app. The metadata to show on the dialog is collected by the [`AppUpdateDataReadCommand`](https://source.chromium.org/search?q=AppUpdateDataReadCommand&ss=chromium%2Fchromium%2Fsrc). + +The user can choose to either: +- Ignore the update: The expanded label on the app window's three dot menu is no longer shown, unless a new update appears. +- Accept the update: The [`ApplyPendingManifestUpdateCommand`](https://source.chromium.org/search?q=ApplyPendingManifestUpdateCommand&sq=&ss=chromium%2Fchromium%2Fsrc) is triggered which applies any pending updates to the metadata and icons. +- Uninstall the app: Remove the app if they're not sure if the app update was malicious or not. + +# Testing + +- [`WebAppIntegrationTestDriver`](https://source.chromium.org/search?q=WebAppIntegrationTestDriver&ss=chromium%2Fchromium%2Fsrc) contains browser tests for the entire end-to-end working of the manifest update process. Please look at the [critical user journeys](https://source.chromium.org/chromium/chromium/src/+/main:chrome/test/webapps/data/critical_user_journeys.md?q=%22App%20identity%20updating%22%20f:critical_user_journeys.md&ss=chromium%2Fchromium%2Fsrc) and [integration testing framework](https://source.chromium.org/chromium/chromium/src/+/main:chrome/test/webapps/data/critical_user_journeys.md?q=%22App%20identity%20updating%22%20f:critical_user_journeys.md&ss=chromium%2Fchromium%2Fsrc) for more documentation on how to parse these +tests. +- [`ManifestSilentUpdateCommandTest`](https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/web_applications/commands/manifest_silent_update_command_unittest.cc) contains unit tests for the determination +part of the manifest update operation that determines if the updates need to happen +silently, or if pending data needs to be stored. +- [`ManifestSilentUpdateCommandBrowserTest`](https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/web_applications/commands/manifest_silent_update_command_browsertest.cc) contains browser tests for the determination part of the manifest update operation, that requires an active browser window to be available, for example, to check if the expanded label is available for pending updates. +- [`ApplyPendingManifestUpdateCommandTest`](https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/web_applications/commands/apply_pending_manifest_update_command_unittest.cc) contains unit tests for the application of pending updates to the web app database as well as icons stored on the disk. +- [`WebAppUpdateReviewDialogBrowserTests`](https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/ui/views/web_apps/web_app_update_review_dialog_browsertest.cc) contains browser tests for the end to end +flow, including the triggering of the dialog and verification of the expanded label +available on the web app. +
diff --git a/docs/webapps/os_integration.md b/chrome/browser/web_applications/docs/os_integration.md similarity index 86% rename from docs/webapps/os_integration.md rename to chrome/browser/web_applications/docs/os_integration.md index b34e19c..5ffbe5d 100644 --- a/docs/webapps/os_integration.md +++ b/chrome/browser/web_applications/docs/os_integration.md
@@ -1,13 +1,13 @@ -# [Web Apps](README.md) - Operating System Integration +# [Web Apps](../README.md) - Operating System Integration -The WebAppProvider system has to provide a lot of integrations with operating system surfaces for web apps. This functionality is usually different per operating system, and is usually invoked through the [`OsIntegrationManager`][2]. +The WebAppProvider system has to provide a lot of integrations with operating system surfaces for web apps. This functionality is usually different per operating system, and is usually invoked through the [`OsIntegrationManager`](/chrome/browser/web_applications/os_integration/os_integration_manager.h). -The [`OsIntegrationManager`][2]'s main responsibility is support the following operations: +The [`OsIntegrationManager`](/chrome/browser/web_applications/os_integration/os_integration_manager.h)'s main responsibility is support the following operations: 1. Install operating system integration for a given web app. 1. Update operating system integration for a given web app. 1. Uninstall/remove operating system integration for a given web app. -It owns sub-managers who are responsible for each individual operating system integration functionality (e.g. [`web_app_file_handler_manager.h`][1] which owns the file handling feature). That manager will implement the non-os-specific logic, and then call into functions that have os-specific implementations (e.g. `web_app_file_handler_registration.h/_mac.h/_win.h/_linux.h` files). +It owns sub-managers who are responsible for each individual operating system integration functionality (e.g. [`web_app_file_handler_manager.h`](/chrome/browser/web_applications/os_integration/web_app_file_handler_manager.h) which owns the file handling feature). That manager will implement the non-os-specific logic, and then call into functions that have os-specific implementations (e.g. `web_app_file_handler_registration.h/_mac.h/_win.h/_linux.h` files). Below are sections describing how each OS integration works. @@ -93,5 +93,3 @@ needs to be updated with a profile specific name and executes required update. -[1]: /chrome/browser/web_applications/os_integration/web_app_file_handler_manager.h -[2]: /chrome/browser/web_applications/os_integration/os_integration_manager.h \ No newline at end of file
diff --git a/docs/webapps/owners_expectations.md b/chrome/browser/web_applications/docs/owners_expectations.md similarity index 94% rename from docs/webapps/owners_expectations.md rename to chrome/browser/web_applications/docs/owners_expectations.md index 7a85645a..febb34d 100644 --- a/docs/webapps/owners_expectations.md +++ b/chrome/browser/web_applications/docs/owners_expectations.md
@@ -9,7 +9,7 @@ ## Expectations of owners * See [/docs/code_reviews.md#expectations-of-owners](../code_reviews.md#expectations-of-owners), but instead of 'last 90 days', 6 months is fine. -* Familiar with the project [README](README.md), architecture, common system constructs, testing, & the bespoke integration tests system. +* Familiar with the project [README](../README.md), architecture, common system constructs, testing, & the bespoke integration tests system. * Routes questions to appropriate specialists for sensitive areas (e.g. windows os integration code, app service integration, etc). Expected code review feedback examples (to give an idea of the types of things OWNERs should be thinking about when reviewing code):
diff --git a/docs/webapps/signed_web_bundle_parser_class_structure.png b/chrome/browser/web_applications/docs/signed_web_bundle_parser_class_structure.png similarity index 100% rename from docs/webapps/signed_web_bundle_parser_class_structure.png rename to chrome/browser/web_applications/docs/signed_web_bundle_parser_class_structure.png Binary files differ
diff --git a/chrome/browser/web_applications/docs/skills/.style.mdformat b/chrome/browser/web_applications/docs/skills/.style.mdformat new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/chrome/browser/web_applications/docs/skills/.style.mdformat
diff --git a/chrome/browser/web_applications/docs/skills/README.md b/chrome/browser/web_applications/docs/skills/README.md new file mode 100644 index 0000000..d487590 --- /dev/null +++ b/chrome/browser/web_applications/docs/skills/README.md
@@ -0,0 +1,16 @@ +# Agent Skills + +This directory contains specialized Agent Skills for Chromium development in the +web_applications directory. Because these are pretty specific to just this +directory, they are stored separately from the +[global agent skill area](../../../../../agents/skills/README.md) + +## How to Use + +To use a skill, you must first install it into your workspace. Creating a +symlink is preferred so that the skill stays up-to-date when you sync your local +checkout: + +```bash +gemini skills link chrome/browser/web_applications/docs/skills/<skill-name> --scope workspace +```
diff --git a/chrome/browser/web_applications/docs/skills/create-web-applications-unittest/SKILL.md b/chrome/browser/web_applications/docs/skills/create-web-applications-unittest/SKILL.md new file mode 100644 index 0000000..b5c23baa --- /dev/null +++ b/chrome/browser/web_applications/docs/skills/create-web-applications-unittest/SKILL.md
@@ -0,0 +1,180 @@ +--- +name: create-web-applications-unittest +description: Instructions for creating a unit test in the chrome/browser/web_applications directory, usually involving installed web applications or web app/PWA functionality. +--- + +# Creating Web Applications Unittests + +This skill guides the process of creating a unit test in the +chrome/browser/web_applications directory. First, read +[WebAppProvider README](../../../README.md) to understand how the WebAppProvider +system works. + +## 1. Test Base Class & System Startup + +Most tests in `chrome/browser/web_applications` should inherit from +`web_app::WebAppTest`. By default this utilizes a `TestingProfile` that +automatically uses a `FakeWebAppProvider` instead of the normal +`WebAppProvider`. + +The `FakeWebAppProvider` does *not* automatically start the Web App system. You +must explicitly start it by calling +`test::AwaitStartWebAppProviderAndSubsystems(profile());` in your `SetUp()` +method. + +## 2. Faking Dependencies, for Input & Verification + +To test without triggering actual downstream operations or without needing, say, +a full `WebContents` and network stack running, the `FakeWebAppProvider` +provides a way to swap out production managers with fake equivalents. This +**must** be done before system startup +(`test::AwaitStartWebAppProviderAndSubsystems(profile())`). Some of these fake +managers are created & used by the FakeWebAppProvider by default. + +Examples: + +- `FakeWebContentsManager` (default): Used extensively when installing web apps + to mock the manifest and page states that a real `WebContents` would provide. +- `FakeWebAppUiManager` (default): Helpful for faking UI surface responses (like + update dialogs or launch operations). +- `FakeWebAppOriginAssociationManager`: Frequently used with + `set_pass_through(true)` to instantly pass scope validation without actually + fetching association files over the network. +- `OsIntegrationTestOverrideImpl`: Accessible via + `WebAppTest::fake_os_integration()`, this becomes useful if + `fake_provider().UseRealOsIntegrationManager();` is called before + `AwaitStartWebAppProviderAndSubsystems` in the test setup. +- `FakeOsIntegrationManager` (default): Ensures that no os integration + operations actually occur on the system, and provides a few testing hooks to + fake some os integration fetching. +- `FakeExtensionsManager` (default): Fakes interaction with the extensions + system. +- `FakeWebAppDatabaseFactory` (default): Provides an in-memory database for + testing. +- others: `WebAppProvider` provides testing hooks like `SetClockForTesting()` + and `DisableDelayedPostStartupWorkForTesting()` prevents + `WebAppProvider::DoDelayedPostStartupWork` from being called automatically. + +Example: + +```cpp +void SetUp() override { + WebAppTest::SetUp(); + + // 1. Swap managers + fake_provider().SetOriginAssociationManager( + std::make_unique<FakeWebAppOriginAssociationManager>()); + + // 2. Start the system + test::AwaitStartWebAppProviderAndSubsystems(profile()); +} +``` + +## 3. Test Data Setup / Mocking Inputs + +Mock inputs and dependencies needed by the operation or system being tested. + +- **WebContents or Network**: If the operation operates on web contents or + fetches information from the network, use the `FakeWebContentsManager` + (usually via `WebAppTest::fake_web_contents_manager()`) to set up manifest + data, page state, and loaded icons before kicking off a fetch manifest + command. +- **UI Interactions**: Use `FakeWebAppUiManager` to respond to user dialog + prompts (e.g., accepting a PWA install dialog). +- **Filesystem**: Use `MockFileUtilsWrapper` for file system interactions and + assertions. The most common use-case here is faking that our disk is full to + cause a filesystem error for an operation, verifying that the failure is + handled correctly. It is generally OK for non-error tests to simply use the + real filesystem. +- **WebApp state**: + - Testing helpers exist in + `chrome/browser/web_applications/test/web_app_install_test_utils.h` for + installing apps in various configurations. + - Modifying the database to get the web app in necessary input states can be + done via operations on the `provider().scheduler()` if there a convenient + operation exists. Otherwise it can be done via a `ScopedRegistryUpdate` + created via `provider().sync_bridge_unsafe().BeginUpdate()`. + +*(Note, `test::InstallDummyWebApp` provides a simpler wrapper if you only need +the app to exist)*. + +## 4. Observers and Command Completion + +Tests will occasionally use observers to wait for a specific change to occur. +The `chrome/browser/web_applications/test/web_app_test_observers.h` file +provides several helpful utilities for this, such as: + +- `WebAppTestInstallObserver`: Waits for an app to be installed. +- `WebAppTestUninstallObserver`: Waits for an app to be uninstalled. +- `WebAppTestManifestUpdatedObserver`: Waits for a manifest update. + +This is an acceptable pattern, but it often requires the test to also wait for +the underlying commands handling that change to finish executing. To ensure the +system runs all queued tasks and is in a stable state after an observed event, +call: + +```cpp +provider().command_manager().AwaitAllCommandsCompleteForTesting(); +``` + +## 5. Validate state & check metrics + +When validating state, the best checks use the system's 'public' API or on the +dependencies (e.g. did the correct method get called on the FakeWebAppUiManager, +and does a scheduler operation return the right thing). It is acceptable to also +query internal state, like the `provider().registrar_unsafe()`, if no 'public' +API exists. + +Most operations should record UMA metrics. If this is the case, use a +`base::HistogramTester` to verify the right metrics were emitted. Sometimes this +is also a handy way to validate specific edge cases were hit without needing to +create test-only state inspection. + +## Example Test Fixture + +Example text fixture that simply runs a hypothetical command `MyWebAppCommand` +and validates the result. + +```cpp +#include "base/test/test_future.h" +#include "chrome/browser/web_applications/scheduler/my_web_app_command_result.h" +#include "chrome/browser/web_applications/test/fake_web_app_provider.h" +#include "chrome/browser/web_applications/test/fake_web_contents_manager.h" +#include "chrome/browser/web_applications/test/web_app_install_test_utils.h" +#include "chrome/browser/web_applications/test/web_app_test.h" +#include "chrome/browser/web_applications/web_app_command_scheduler.h" +// ... + +class MyWebAppCommandTest : public WebAppTest { + public: + void SetUp() override { + WebAppTest::SetUp(); + + // 1. Set up fake managers if needed, or customize database state. + // e.g. fake_provider().Set... + + // 2. Start the WebApp subsystem. + test::AwaitStartWebAppProviderAndSubsystems(profile()); + } + + // base::HistogramTester histogram_tester_; +}; + +TEST_F(MyWebAppCommandTest, SuccessCase) { + // 1. Set up state. (e.g. test::InstallDummyWebApp(...)) + + // 2. Run the operation. + base::test::TestFuture<MyWebAppCommandResult> future; + provider().scheduler().MyWebAppCommand( + // Input args + // ... + future.GetCallback()); + ASSERT_TRUE(future.Wait()); + EXPECT_EQ(MyWebAppCommandResult::kSuccess, future.Get<MyWebAppCommandResult>()); + + // 3. Verify state + // e.g. EXPECT_EQ(provider().registrar_unsafe().Get..., ....); + // EXPECT_THAT(histogram_tester_.GetAllSamples("HistogramName"), + // BucketsAre(Bucket(1, 0), Bucket(2, 10), Bucket(3, 5))); +} +```
diff --git a/docs/webapps/testing.md b/chrome/browser/web_applications/docs/testing.md similarity index 65% rename from docs/webapps/testing.md rename to chrome/browser/web_applications/docs/testing.md index 99f5752..532cb53 100644 --- a/docs/webapps/testing.md +++ b/chrome/browser/web_applications/docs/testing.md
@@ -1,7 +1,7 @@ # [Web Apps](../README.md) - Testing -Please read [Testing In Chromium][13] for general guidance on writing tests in chromium. +Please read [Testing In Chromium](../testing/testing_in_chromium.md) for general guidance on writing tests in chromium. The following tests are expected for writing code in this system: @@ -11,8 +11,7 @@ ### Known Issues -- Unit tests currently cannot rely on `WebContents` functionality, as that is not built as part of unit test frameworks. Instead, they must use the `FakeWebAppUrlLoader` or `FakeWebAppDataRetriever` classes. - - Note: This should be fixed in early 2023. See [bug][1] to make it easier to install apps in unit tests that require a web contents and [bug][2] to improve the `WebContents` dependency and current helper classes to allow the WebAppProvider system to not directly depend on `WebContents`. +- Unit tests currently cannot rely on `WebContents` functionality, as that is not built as part of unit test frameworks. Instead, they must use the `FakeWebContentsManager` class. - Installing web apps before the WebAppProvider system starts can be cumbersome. - Browser tests can use the `PRE_` test functionality to set up any state. - Unit tests must either load a static profile directory saved in the test data, or create a test-only way to explicitly delay the desired subsystem from starting. @@ -23,15 +22,15 @@ * They are very efficient. * They run on all relevant CQ trybots. -* They will always be supported by the [code coverage][8] framework. +* They will always be supported by the [code coverage](../testing/code_coverage.md) framework. -Unit tests are the fastest tests to execute and are expected to be used to test most cases, especially error cases. They are usually built on the `WebAppTest` base class, and use the `FakeWebAppProvider` to customize (or not) the [dependencies][3] of the `WebAppProvider` system. +Unit tests are the fastest tests to execute and are expected to be used to test most cases, especially error cases. They are usually built on the `WebAppTest` base class, and use the `FakeWebAppProvider` to customize (or not) the [dependencies](../README.md#external-dependencies) of the `WebAppProvider` system. Notes -- UI elements do not work in unit tests, and the appropriate fakes must be used (see [External Dependencies][3]). +- UI elements do not work in unit tests, and the appropriate fakes must be used (see [External Dependencies](../README.md#external-dependencies)). - If one of the external dependencies of the system cannot be faked out yet or the feature is tightly coupled to this, then it might make sense to use a browser test instead (or make that dependency fake-able). -- Please use the [`WebAppTest`][4] base class if possible. +- Please use the [`WebAppTest`](https://source.chromium.org/search?q=web_app_test.h) base class if possible. - Unit tests based on `WebAppTest` print a snapshot of chrome://web-app-internals to console on test failures. This can be a powerful debugging tool. The command line flag `--disable-web-app-internals-log` can be used to disable this feature. ## Browser tests @@ -45,7 +44,7 @@ Browser tests are much more expensive to run, as they run a fully functional browser. These tests are usually only created to test functionality that requires multiple parts of the system to be running or dependencies like the Sync service to be fully running and functional. It is good practice to have browsertests be as true-to-user-action as possible, to make sure that as much of our stack is exercised. -An example set of browser tests are in [`web_app_browsertest.cc`][6]. Please use the [`WebAppBrowserTestBase`][5] base class. +An example set of browser tests are in [`web_app_browsertest.cc`](https://source.chromium.org/search?q=web_app_browsertest.cc). Please use the [`WebAppBrowserTestBase`](https://source.chromium.org/search?q=WebAppBrowserTestBase) base class. Notes @@ -53,7 +52,7 @@ ## Integration tests -We have a custom integration testing framework that we use due to the complexity of our use-cases. See [integration-testing-framework.md][7] for more information. +We have a custom integration testing framework that we use due to the complexity of our use-cases. See [integration-testing-framework.md](integration-testing-framework.md) for more information. **It is a good idea to think about your integration tests early & figure out your CUJs with the team. Having your CUJs and integration tests working early greatly speeds up development & launch time.** @@ -63,9 +62,9 @@ ## Testing OS integration -It is very common to test OS integration. By default, OS integration is suppressed if the test extends [`WebAppTest`][4] or [`WebAppBrowserTestBase`][5]. +It is very common to test OS integration. By default, OS integration is suppressed if the test extends [`WebAppTest`](https://source.chromium.org/search?q=web_app_test.h) or [`WebAppBrowserTestBase`](https://source.chromium.org/search?q=WebAppBrowserTestBase). -End-to-end OS integration testing is facilitated using the [`OsIntegrationTestOverride`][9]. If OS integration CAN be tested in an automated way, this class will do so. If not, the existence of this override will stub-out the OS integration at the lowest level to test as much of our code as possible. +End-to-end OS integration testing is facilitated using the [`OsIntegrationTestOverride`](https://source.chromium.org/search?q=OsIntegrationTestOverride). If OS integration CAN be tested in an automated way, this class will do so. If not, the existence of this override will stub-out the OS integration at the lowest level to test as much of our code as possible. ## `Fake*` classes @@ -73,11 +72,11 @@ The most common pattern here is that the Fake will by default appear to work correctly, and a test can either specify it to return custom results, fail in specific ways, or simply check that it was used in the correct way. -An example is [fake_os_integration_manager.h][14], which pretends to successfully perform install, update, and uninstall operations on OS integration, but instead pretends to work and does simple bookkeeping for tests to check that it was called correctly. +An example is [fake_os_integration_manager.h](https://source.chromium.org/search?q=FakeOsIntegrationManager), which pretends to successfully perform install, update, and uninstall operations on OS integration, but instead pretends to work and does simple bookkeeping for tests to check that it was called correctly. ## `Mock*` classes -A class that start with `Mock` is a [gmock][12] version of the class. This allows the user to have complete control of exactly what that class does, verify it is called exactly as expected, etc. These tend to be much more powerful to use than a `Fake`, as you can easily specify every possible case you might want to check, like which arguments are called and the exact calling order of multiple functions, even across multiple mocks. The downsides are: +A class that start with `Mock` is a [gmock](https://github.com/google/googletest/tree/HEAD/googlemock) version of the class. This allows the user to have complete control of exactly what that class does, verify it is called exactly as expected, etc. These tend to be much more powerful to use than a `Fake`, as you can easily specify every possible case you might want to check, like which arguments are called and the exact calling order of multiple functions, even across multiple mocks. The downsides are: * Mocks end up being very verbose to use, often at the expense of test readiability. * Mocks require creating a mock class & learning how to use gmock. @@ -85,10 +84,10 @@ ## Tool: `FakeWebAppProvider` -The [`FakeWebAppProvider`][11] is basically a fake version of the WebAppProvider system, that uses the [`WebAppProvider`][10] root class to set up subsystems and can be used to selectively set fake subsystems or shut them +The [`FakeWebAppProvider`](https://source.chromium.org/search?q=FakeWebAppProvider) is basically a fake version of the WebAppProvider system, that uses the [`WebAppProvider`](https://source.chromium.org/search?q=WebAppProvider) root class to set up subsystems and can be used to selectively set fake subsystems or shut them down on a per-demand basis to test system shutdown use-cases. -By default, the `FakeWebAppProvider` will NOT start the `WebAppProvider` system, and it must be manually done so. This is usually done by calling [`AwaitStartWebAppProviderAndSubsystems`][15]. +By default, the `FakeWebAppProvider` will NOT start the `WebAppProvider` system, and it must be manually done so. This is usually done by calling [`AwaitStartWebAppProviderAndSubsystems`](https://source.chromium.org/search?q=AwaitStartWebAppProviderAndSubsystems). ## Common issue: Waiting @@ -108,7 +107,7 @@ ### `WebAppProvider` commands -[`WebAppCommandManager::AwaitAllCommandsCompleteForTesting`][16] will wait for all commands to complete. This will mostly handle all tasks in the `WebAppProvider`. +[`WebAppCommandManager::AwaitAllCommandsCompleteForTesting`](https://source.chromium.org/search?q=AwaitAllCommandsCompleteForTesting) will wait for all commands to complete. This will mostly handle all tasks in the `WebAppProvider`. ## Common issue: External Dependency that isn't faked @@ -120,19 +119,3 @@ 1. Create a new interface for this new external dependency, put it on the `WebAppProvider`, and create a fake for it so that you can test with it faked. 1. If all else fails, use a browser test. -[1]: https://b/269618710 -[2]: http://b/271124885 -[3]: README.md#external-dependencies -[4]: https://source.chromium.org/search?q=web_app_test.h -[5]: https://source.chromium.org/search?q=WebAppBrowserTestBase -[6]: https://source.chromium.org/search?q=web_app_browsertest.cc -[7]: integration-testing-framework.md -[8]: ../testing/code_coverage.md -[9]: https://source.chromium.org/search?q=OsIntegrationTestOverride -[10]: https://source.chromium.org/search?q=WebAppProvider -[11]: https://source.chromium.org/search?q=FakeWebAppProvider -[12]: https://github.com/google/googletest/tree/HEAD/googlemock -[13]: ../testing/testing_in_chromium.md -[14]: https://source.chromium.org/search?q=FakeOsIntegrationManager -[15]: https://source.chromium.org/search?q=AwaitStartWebAppProviderAndSubsystems -[16]: https://source.chromium.org/search?q=AwaitAllCommandsCompleteForTesting
diff --git a/docs/webapps/webapp_installation_process.png b/chrome/browser/web_applications/docs/webapp_installation_process.png similarity index 100% rename from docs/webapps/webapp_installation_process.png rename to chrome/browser/web_applications/docs/webapp_installation_process.png Binary files differ
diff --git a/docs/webapps/webappprovider_component_ownership.jpg b/chrome/browser/web_applications/docs/webappprovider_component_ownership.jpg similarity index 100% rename from docs/webapps/webappprovider_component_ownership.jpg rename to chrome/browser/web_applications/docs/webappprovider_component_ownership.jpg Binary files differ
diff --git a/docs/webapps/webui_web_app.md b/chrome/browser/web_applications/docs/webui_web_app.md similarity index 100% rename from docs/webapps/webui_web_app.md rename to chrome/browser/web_applications/docs/webui_web_app.md
diff --git a/docs/webapps/why-is-this-test-failing.md b/chrome/browser/web_applications/docs/why-is-this-test-failing.md similarity index 100% rename from docs/webapps/why-is-this-test-failing.md rename to chrome/browser/web_applications/docs/why-is-this-test-failing.md
diff --git a/chrome/browser/web_applications/jobs/README.md b/chrome/browser/web_applications/jobs/README.md new file mode 100644 index 0000000..c58de7b --- /dev/null +++ b/chrome/browser/web_applications/jobs/README.md
@@ -0,0 +1,32 @@ +# Jobs (`chrome/browser/web_applications/jobs`) + +This directory contains reusable units of work, referred to as "jobs". + +## Role of Jobs + +While **[Commands](../commands/README.md)** are scheduled by the +`WebAppCommandScheduler` and orchestrate the high-level workflow of web app +operations (such as "Fetch Manifest and Install"), these workflows often share +common steps (e.g., "Install from info", "Perform an update", "Transform a +manifest into a WebAppInstallInfo", etc). + +Jobs extract these common steps so they can be reused across different commands. + +## Best Practices + +- **Composability:** Jobs are designed to be composed together within a command + to form complex operations. +- **No Implicit Scheduling:** Jobs are not scheduled directly by the + `WebAppCommandScheduler`. A command must own and execute the job. +- **Clear Inputs/Outputs:** A job usually expects a clear set of inputs (often + via its constructor) and returns a specific `JobResult` type to the owning + command via a callback. +- **Factory Method:** Jobs should have a `CreateAndStart` static factory method + that returns a `std::unique_ptr` to the job. +- **Lock Passing:** Jobs should accept locks as raw pointers and store them as + `raw_ref`s. To be flexible, use the lock mixin type (like `WithAppResources`) + instead of the concrete lock class (e.g. `AppLock`). +- **Destruction Order:** A command using jobs should delete them after they + complete, or ensure the destruction order guarantees that the + `raw_ref`/`raw_ptr` in the job doesn't flag a dangling pointer issue when the + command is destroyed (since the command owns the lock).
diff --git a/chrome/browser/web_applications/os_integration/mac/app_shim_registry.h b/chrome/browser/web_applications/os_integration/mac/app_shim_registry.h index 1d870f2..67cb498 100644 --- a/chrome/browser/web_applications/os_integration/mac/app_shim_registry.h +++ b/chrome/browser/web_applications/os_integration/mac/app_shim_registry.h
@@ -26,11 +26,18 @@ class PrefRegistrySimple; // This class is used to store information about which app shims have been -// installed for which profiles in local storage. This is used to: +// installed for which profiles in local storage. This is needed to reason +// about the state of installed PWAs in all profiles without loading those +// profiles into memory. For this purpose, `AppShimRegistry` stores the needed +// information in Chrome's "Local State" (global preferences). +// This is used to: // - Open the last active profile when an app shim is launched. // - Populate the profile switcher menu in the app with only those profile // for which the app is installed. // - Only delete the app shim when it has been uninstalled for all profiles. +// - Store what file and protocol handlers are enabled for a web app in each +// profile it is installed in (to make sure all file and protocol handlers +// for the app are accounted for when updating the App Shim). // All base::FilePath arguments to functions are expected to be full profile // paths (e.g, the result of calling Profile::GetPath). //
diff --git a/chrome/browser/web_applications/test/fake_data_retriever.h b/chrome/browser/web_applications/test/fake_data_retriever.h index 9c5837e8..ff2693a5 100644 --- a/chrome/browser/web_applications/test/fake_data_retriever.h +++ b/chrome/browser/web_applications/test/fake_data_retriever.h
@@ -24,6 +24,10 @@ // All WebAppDataRetriever operations are async, so this class posts tasks // when running callbacks to simulate async behavior in tests as well. +// This class is essential for mocking the interaction with a `WebContents` +// during the web app installation flow. It allows tests to provide artificial +// manifest data, icon bitmaps, and installability checks without needing a +// real web page or network connection. class FakeDataRetriever : public WebAppDataRetriever { public: FakeDataRetriever();
diff --git a/chrome/browser/web_applications/test/fake_os_integration_manager.h b/chrome/browser/web_applications/test/fake_os_integration_manager.h index 67df97d..926f126 100644 --- a/chrome/browser/web_applications/test/fake_os_integration_manager.h +++ b/chrome/browser/web_applications/test/fake_os_integration_manager.h
@@ -17,6 +17,12 @@ class WebAppFileHandlerManager; class WebAppProtocolHandlerManager; +// A fake implementation of OsIntegrationManager that prevents the web app +// system from making actual modifications to the host operating system (e.g., +// creating shortcuts, registering file handlers, or adding uninstall entries). +// This is typically the default manager in unit tests, ensuring tests remain +// isolated and side-effect free. It can also be configured to mock existing +// OS state (like existing shortcuts) to test system behavior. class FakeOsIntegrationManager : public OsIntegrationManager { public: FakeOsIntegrationManager(
diff --git a/chrome/browser/web_applications/test/fake_web_app_database_factory.h b/chrome/browser/web_applications/test/fake_web_app_database_factory.h index aefa3ccf..56554f0 100644 --- a/chrome/browser/web_applications/test/fake_web_app_database_factory.h +++ b/chrome/browser/web_applications/test/fake_web_app_database_factory.h
@@ -26,6 +26,13 @@ class WebApp; } // namespace proto +// A fake implementation of AbstractWebAppDatabaseFactory that provides an +// in-memory database store (using syncer::InMemoryDataTypeStore) for the web +// app registry. This avoids real disk I/O in unit tests. +// Note: tests should strongly prefer acting through the public web app APIs +// (like WebAppCommandScheduler) rather than directly poking this database. +// This factory is primarily useful for testing startup conditions or migration +// logic that requires a specific pre-existing database state. class FakeWebAppDatabaseFactory : public AbstractWebAppDatabaseFactory { public: FakeWebAppDatabaseFactory();
diff --git a/chrome/browser/web_applications/test/fake_web_app_origin_association_manager.h b/chrome/browser/web_applications/test/fake_web_app_origin_association_manager.h index 7e1ac7d..5fef7ba 100644 --- a/chrome/browser/web_applications/test/fake_web_app_origin_association_manager.h +++ b/chrome/browser/web_applications/test/fake_web_app_origin_association_manager.h
@@ -13,6 +13,10 @@ namespace web_app { // Fake implementation of WebAppOriginAssociationManager. +// When tested components need to validate origin associations (e.g. for scope +// extensions or migrations), tests can either use `SetData` to mock specific +// validation responses, or call `set_pass_through(true)` to simply bypass the +// network request entirely and return the inputted associations as valid. class FakeWebAppOriginAssociationManager : public WebAppOriginAssociationManager { public:
diff --git a/chrome/browser/web_applications/test/fake_web_app_ui_manager.h b/chrome/browser/web_applications/test/fake_web_app_ui_manager.h index 26483b9..e204b29f 100644 --- a/chrome/browser/web_applications/test/fake_web_app_ui_manager.h +++ b/chrome/browser/web_applications/test/fake_web_app_ui_manager.h
@@ -29,6 +29,11 @@ } // namespace webapps namespace web_app { +// A fake implementation of WebAppUiManager used in unit tests to prevent +// actually opening browser windows or showing UI dialogs. +// It allows tests to track UI interactions (like tab reparenting and window +// launches) and can be configured to automatically accept or reject dialogs +// (e.g., install dialogs, identity update dialogs). class FakeWebAppUiManager : public WebAppUiManager { public: FakeWebAppUiManager();
diff --git a/chrome/browser/web_applications/test/os_integration_test_override_impl.h b/chrome/browser/web_applications/test/os_integration_test_override_impl.h index 1cdd697..f3b7dbb 100644 --- a/chrome/browser/web_applications/test/os_integration_test_override_impl.h +++ b/chrome/browser/web_applications/test/os_integration_test_override_impl.h
@@ -56,6 +56,21 @@ // saved `scoped_refptr<OsIntegrationTestOverride>`. This ensures that all os // integration (disk folders, windows registry changes, etc) have been removed. // +// This overrides the execution of actual OS integration at the lowest layer, +// simulating success without altering the developer's raw OS environment, +// allowing tests to read the 'expected' state of OS integrations cleanly. +// +// Usage in tests: +// 1. Setup an `OsIntegrationTestOverrideImpl::BlockingRegistration` inside of +// `SetUp()` (needs `ScopedAllowBlockingForTesting`). +// 2. Utilize the provider to check states: +// `OsIntegrationTestOverrideImpl::Get()->IsShortcutCreated(...)`. +// 3. IMPORTANT TEARDOWN RULE: App uninstallation does file I/O operations and +// expects the override to still be alive. So, perform +// `test::UninstallAllWebApps(profile());` in `TearDown()` before resetting +// the override. Note that `WebAppTest::TearDown()` handles this cleanup +// automatically. +// // `test_override()` can be used to view or modify the OS state. // // Note: This override does not apply if there is a
diff --git a/chrome/browser/web_applications/web_app.cc b/chrome/browser/web_applications/web_app.cc index 23e212c..bd94c40 100644 --- a/chrome/browser/web_applications/web_app.cc +++ b/chrome/browser/web_applications/web_app.cc
@@ -281,6 +281,14 @@ : std::nullopt), manifest_id_(manifest_id), parent_app_id_(parent_app_id) { + // Fix invalid scope values. + if (!scope_.is_valid() || !url::IsSameOriginWith(scope_, start_url_) || + !base::StartsWith(start_url_.spec(), scope_.spec(), + base::CompareCase::SENSITIVE)) { + DLOG(ERROR) << "Invalid scope " << scope_.possibly_invalid_spec() + << " for start_url " << start_url_; + scope_ = start_url_.GetWithoutFilename(); + } // Must drop the fragments and queries per `scope` rules // https://w3c.github.io/manifest/#scope-member GURL::Replacements replacements;
diff --git a/chrome/browser/web_applications/web_app.h b/chrome/browser/web_applications/web_app.h index 56642a9..34badbf 100644 --- a/chrome/browser/web_applications/web_app.h +++ b/chrome/browser/web_applications/web_app.h
@@ -68,6 +68,13 @@ InstalledByPassKey() = default; }; +// Represents an installed web app in RAM. Its member fields largely reflect all +// the ways a site can configure their web app manifest, plus miscellaneous +// internal bookkeeping and user settings. +// +// Some settings on this class can also be influenced by other sources of truth +// like policy. Thus it is often safer to access properties via getters on the +// WebAppRegistrar, which combines these sources of truth. class WebApp { public: // This creates a web app object, and will CHECK-fail if the arguments are
diff --git a/chrome/browser/web_applications/web_app_provider.h b/chrome/browser/web_applications/web_app_provider.h index 667489dc..9e6a94a 100644 --- a/chrome/browser/web_applications/web_app_provider.h +++ b/chrome/browser/web_applications/web_app_provider.h
@@ -73,6 +73,8 @@ // Connects Web App features, such as the installation of default and // policy-managed web apps, with Profiles (as WebAppProvider is a // Profile-linked KeyedService) and their associated PrefService. +// This is a per-profile object housing all the various web app subsystems. +// This is the "main()" of the web app implementation where everything starts. // // Lifecycle notes: // - WebAppProvider and its sub-managers are not ready for use until the
diff --git a/chrome/browser/web_applications/web_app_registrar.h b/chrome/browser/web_applications/web_app_registrar.h index 31387b0..fe6ef2b 100644 --- a/chrome/browser/web_applications/web_app_registrar.h +++ b/chrome/browser/web_applications/web_app_registrar.h
@@ -126,6 +126,20 @@ BASE_DECLARE_FEATURE(kPreinstalledBrowserTabWebAppsForcedDefaultCaptureOff); // A registry model. This is a read-only container, which owns WebApp objects. +// This is where all the WebApps live in memory, and what many other subsystems +// query to look up any given web app's fields. Mutations to the registry must +// use a ScopedRegistryUpdate, and this must occur within a command or job +// (where a lock is held). +// +// Accessing the registrar should happen through a lock that has +// `WithAppResources` (e.g. AppLock). If accessed through the WebAppProvider, +// then any data read is potentially uncommmited (and thus unsafe). +// +// Other responsibilities of this class: +// - Operations that compare or operate on multiple web apps, (e.g. +// FindAppThatCapturesLinksInScope). +// - Combining multiple sources of truth (e.g. GetAppRunOnOsLoginMode, which +// must consider both the user's preference AND the admin's policy). class WebAppRegistrar { public: // Returns if the given display mode is supported for navigation capturing.
diff --git a/chrome/browser/web_applications/web_app_sync_bridge.h b/chrome/browser/web_applications/web_app_sync_bridge.h index c32dcb3..8c2cc72 100644 --- a/chrome/browser/web_applications/web_app_sync_bridge.h +++ b/chrome/browser/web_applications/web_app_sync_bridge.h
@@ -91,12 +91,25 @@ // While WebAppRegistrar is a read-only model, WebAppSyncBridge is a // controller for that model. WebAppSyncBridge is responsible for: // - Registry initialization (reading model from a persistent storage like -// LevelDb or prefs). +// LevelDb or prefs). // - Writing all the registry updates to a persistent store and sync. // -// WebAppSyncBridge is the key class to support integration with Unified Sync -// and Storage (USS) system. The sync bridge exclusively owns +// WebAppSyncBridge is the key class to support integration with the Unified +// Sync and Storage (USS) system. The sync bridge exclusively owns // DataTypeLocalChangeProcessor and WebAppDatabase (the storage). +// +// This is "bridge" between the WebAppProvider system's in-memory representation +// of web apps and the Unified Sync and Storage (USS) system's database +// representation. See syncer::DataTypeSyncBridge for more information about +// this integration. It installs new apps, uninstalls apps the user uninstalled +// elsewhere, and updates metadata. It also tells the sync system if there are +// local changes. +// +// Note: This only stores per-web-app data, and that data will be deleted if the +// web app is uninstalled. To store data that persists after uninstall, or +// applies to a more general scope than a single web app, then the +// `proto::DatabaseMetadata` object can be used (preferred), or the +// `PrefService` on the `Profile` object or on the browser process. class WebAppSyncBridge : public syncer::DataTypeSyncBridge { public: // Disable the logic that resumes pending sync installs, and fixes cases where
diff --git a/chrome/browser/web_applications/web_app_ui_manager.h b/chrome/browser/web_applications/web_app_ui_manager.h index e435672..79e4f5fb 100644 --- a/chrome/browser/web_applications/web_app_ui_manager.h +++ b/chrome/browser/web_applications/web_app_ui_manager.h
@@ -106,6 +106,14 @@ // A chrome/browser/ representation of the chrome/browser/ui/ UI manager to // perform Web App UI operations or listen to Web App UI events, including // events from WebAppTabHelpers. +// +// All methods / operations on this class are ideally impotent, where all +// information for the operation is passed as arguments, and the operation +// doesn't do any state changes to the WebApp system. When the operation is +// done, the results are returned directly or returned by calling a callback +// argument. This ensures that state changing complexity all lives in the WebApp +// system internals, and also allows unit tests to test those operations easy +// while this subsystem is faked using the FakeWebAppUiManager. class WebAppUiManager { public: using ShowIntentPickerBubbleCallback = base::OnceCallback<void(bool)>;
diff --git a/chrome/browser/webshare/chromeos/sharesheet_client.cc b/chrome/browser/webshare/chromeos/sharesheet_client.cc index 7222fcc..6f03a4ad 100644 --- a/chrome/browser/webshare/chromeos/sharesheet_client.cc +++ b/chrome/browser/webshare/chromeos/sharesheet_client.cc
@@ -22,7 +22,6 @@ #include "chrome/browser/sharesheet/sharesheet_metrics.h" #include "chrome/browser/sharesheet/sharesheet_service.h" #include "chrome/browser/sharesheet/sharesheet_service_factory.h" -#include "chrome/browser/visibility_timer_tab_helper.h" #include "chrome/browser/webshare/prepare_directory_task.h" #include "chrome/browser/webshare/prepare_subdirectory_task.h" #include "chrome/browser/webshare/share_service_impl.h" @@ -31,6 +30,7 @@ #include "components/prefs/pref_service.h" #include "components/services/app_service/public/cpp/intent.h" #include "components/services/app_service/public/cpp/intent_util.h" +#include "components/visibility_timer/visibility_timer_tab_helper.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/web_contents.h" @@ -135,8 +135,9 @@ if (profile->IsIncognitoProfile() && !files.empty()) { // Random number of seconds in the range [1.0, 2.0). double delay_seconds = 1.0 + 1.0 * base::RandDouble(); - VisibilityTimerTabHelper::CreateForWebContents(web_contents()); - VisibilityTimerTabHelper::FromWebContents(web_contents()) + visibility_timer::VisibilityTimerTabHelper::CreateForWebContents( + web_contents()); + visibility_timer::VisibilityTimerTabHelper::FromWebContents(web_contents()) ->PostTaskAfterVisibleDelay( FROM_HERE, base::BindOnce(std::move(callback),
diff --git a/chrome/browser/webshare/mac/sharing_service_operation.mm b/chrome/browser/webshare/mac/sharing_service_operation.mm index 3fe343d..9325106e 100644 --- a/chrome/browser/webshare/mac/sharing_service_operation.mm +++ b/chrome/browser/webshare/mac/sharing_service_operation.mm
@@ -17,11 +17,11 @@ #include "base/strings/utf_string_conversions.h" #include "base/uuid.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/visibility_timer_tab_helper.h" #include "chrome/browser/webshare/prepare_directory_task.h" #include "chrome/browser/webshare/prepare_subdirectory_task.h" #include "chrome/browser/webshare/share_service_impl.h" #include "chrome/browser/webshare/store_files_task.h" +#include "components/visibility_timer/visibility_timer_tab_helper.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/render_widget_host_view.h" #include "content/public/browser/storage_partition.h" @@ -77,8 +77,10 @@ if (profile->IsIncognitoProfile() && !shared_files_.empty()) { // Random number of seconds in the range [1.0, 2.0). double delay_seconds = 1.0 + 1.0 * base::RandDouble(); - VisibilityTimerTabHelper::CreateForWebContents(web_contents_.get()); - VisibilityTimerTabHelper::FromWebContents(web_contents_.get()) + visibility_timer::VisibilityTimerTabHelper::CreateForWebContents( + web_contents_.get()); + visibility_timer::VisibilityTimerTabHelper::FromWebContents( + web_contents_.get()) ->PostTaskAfterVisibleDelay( FROM_HERE, base::BindOnce(std::move(callback_),
diff --git a/chrome/browser_exposed_mojom_targets.gni b/chrome/browser_exposed_mojom_targets.gni index 1da81ea15..157d34d 100644 --- a/chrome/browser_exposed_mojom_targets.gni +++ b/chrome/browser_exposed_mojom_targets.gni
@@ -95,6 +95,7 @@ "//chrome/services/media_gallery_util/public/mojom:mojom", "//chrome/services/printing/public/mojom:mojom", "//chrome/services/removable_storage_writer/public/mojom:mojom", + "//components/accessibility_annotator/core/logging:mojo_bindings", "//components/attribution_reporting:mojom", "//components/attribution_reporting:registration_header_error_mojom", "//components/attribution_reporting:registration_mojom",
diff --git a/chrome/build/android-arm32.pgo.txt b/chrome/build/android-arm32.pgo.txt index 89b1ea86..ea78501 100644 --- a/chrome/build/android-arm32.pgo.txt +++ b/chrome/build/android-arm32.pgo.txt
@@ -1 +1 @@ -chrome-android32-main-1773727083-15022bb40074349673f8cda13aad7a79b3d8e6f1-2542f993bbaae82d44ac619ac5e172553ab8685d.profdata +chrome-android32-main-1773791628-5d6048779450ee4f0261b1e7295e9eb21a5d9765-6a1da59d09aedb97c29f3398934134d058c5e112.profdata
diff --git a/chrome/build/android-desktop-x64.pgo.txt b/chrome/build/android-desktop-x64.pgo.txt index 49e5afa..8a921e38 100644 --- a/chrome/build/android-desktop-x64.pgo.txt +++ b/chrome/build/android-desktop-x64.pgo.txt
@@ -1 +1 @@ -chrome-android-desktop-x64-main-1773748612-aa842fefe441df739c188e24aa3e01f98c050188-eb32defcecc7ddcb69ea920b630f20cd6150106b.profdata +chrome-android-desktop-x64-main-1773813322-70921fb27d5d07d3721361e5b22cc19577f57100-9f5dad26b06283cadc13958728bdaae7abccc6c6.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt index 7fcb0dd0..3011c36 100644 --- a/chrome/build/mac-arm.pgo.txt +++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@ -chrome-mac-arm-main-1773748612-82912146273a94c908b18017aa9ff6c60900aa38-eb32defcecc7ddcb69ea920b630f20cd6150106b.profdata +chrome-mac-arm-main-1773813322-03482ebb3abf5ffaa7fb372d9aa6133e5253e4a2-9f5dad26b06283cadc13958728bdaae7abccc6c6.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt index 3cb5bdf..cebd1fa 100644 --- a/chrome/build/mac.pgo.txt +++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@ -chrome-mac-main-1773748612-851e6e1285e07dd6405825399da15de5dfa4a815-eb32defcecc7ddcb69ea920b630f20cd6150106b.profdata +chrome-mac-main-1773791628-c5b5a976ae6c29f85df4c84a87e893a2ed69ba57-6a1da59d09aedb97c29f3398934134d058c5e112.profdata
diff --git a/chrome/build/win-arm64.pgo.txt b/chrome/build/win-arm64.pgo.txt index 17d541c..a87a990 100644 --- a/chrome/build/win-arm64.pgo.txt +++ b/chrome/build/win-arm64.pgo.txt
@@ -1 +1 @@ -chrome-win-arm64-main-1773748612-0a8a5355d608f4cc69351017a3276677a298d26c-eb32defcecc7ddcb69ea920b630f20cd6150106b.profdata +chrome-win-arm64-main-1773791628-540ace6fbfacd5bd10a3d7b38f0632efa785ba88-6a1da59d09aedb97c29f3398934134d058c5e112.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index 8315cd6..68b704dd 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-main-1773759527-70950484ea2cd62e58a1a4112293a2f84eb8c061-532b5165f4aac5e985d95622a0f533c9e9e87c0d.profdata +chrome-win32-main-1773802723-171ebe5dfc0ba64f655e7ea8a4a2a77db4ee8bc6-69cd84da1e7f8aaef1238a429e2d1227d6b6bc20.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index 64db761..1e309f8 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-main-1773759527-cb74ad71caafc4383a6a16e445af4f951890372b-532b5165f4aac5e985d95622a0f533c9e9e87c0d.profdata +chrome-win64-main-1773802723-bb6ae7256919b8a4ee32332d19f53e528f7012a7-69cd84da1e7f8aaef1238a429e2d1227d6b6bc20.profdata
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn index 82449391..cf26244 100644 --- a/chrome/common/BUILD.gn +++ b/chrome/common/BUILD.gn
@@ -501,7 +501,10 @@ } static_library("url_constants") { - visibility = [ "//chrome/common/*" ] + visibility = [ + "//chrome/browser/contextual_tasks/*", + "//chrome/common/*", + ] sources = [ "url_constants.h", "webui_url_constants.cc",
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc index 101e2f0..26f457e 100644 --- a/chrome/common/chrome_features.cc +++ b/chrome/common/chrome_features.cc
@@ -115,11 +115,6 @@ // Enable project Crostini, Linux VMs on Chrome OS. BASE_FEATURE(kCrostini, base::FEATURE_DISABLED_BY_DEFAULT); -// Enables infrastructure for generating Ansible playbooks for the default -// Crostini container from software configurations in JSON schema. -BASE_FEATURE(kCrostiniAnsibleSoftwareManagement, - base::FEATURE_DISABLED_BY_DEFAULT); - #endif // BUILDFLAG(IS_CHROMEOS) // Enables stricter cryptography settings for CNSA2 compliance. This is not @@ -139,12 +134,6 @@ base::FEATURE_DISABLED_BY_DEFAULT); #endif -#if BUILDFLAG(IS_CHROMEOS) -// If enabled, specified extensions cannot be closed via the task manager. -BASE_FEATURE(kDesktopTaskManagerEndProcessDisabledForExtension, - base::FEATURE_DISABLED_BY_DEFAULT); -#endif // BUILDFLAG(IS_CHROMEOS) - // Enables the chrome://chrome-finds-internals page. BASE_FEATURE(kChromeFindsInternals, base::FEATURE_DISABLED_BY_DEFAULT); @@ -196,16 +185,6 @@ // If the feature is disabled, Chrome Apps continue to work. If enabled, Chrome // Apps will not launch and will be marked in the UI as deprecated. BASE_FEATURE(kChromeAppsDeprecation, base::FEATURE_ENABLED_BY_DEFAULT); - -// Enables the new create shortcut flow where fire and forget entities are -// created from three dot menu > Save and Share > Create Shortcut instead of -// PWAs. -BASE_FEATURE(kShortcutsNotApps, base::FEATURE_ENABLED_BY_DEFAULT); - -// Enables the opening of the desktop and highlighting of the shortcut created -// as part of the new Create Shortcut flow. Requires kShortcutsNotApps to be -// enabled to work. -BASE_FEATURE(kShortcutsNotAppsRevealDesktop, base::FEATURE_ENABLED_BY_DEFAULT); #endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) #if BUILDFLAG(IS_CHROMEOS) @@ -1325,10 +1304,6 @@ BASE_FEATURE(kUserValueDefaultBrowserStrings, base::FEATURE_DISABLED_BY_DEFAULT); -// Enables or disables push subscriptions keeping Chrome running in the -// background when closed. -BASE_FEATURE(kPushMessagingBackgroundMode, base::FEATURE_DISABLED_BY_DEFAULT); - // Shows a confirmation dialog when updates to a PWAs icon has been detected. BASE_FEATURE(kPwaUpdateDialogForIcon, base::FEATURE_DISABLED_BY_DEFAULT); @@ -1344,12 +1319,6 @@ "AbusiveOriginNotificationPermissionRevocation", base::FEATURE_ENABLED_BY_DEFAULT); -#if BUILDFLAG(IS_CHROMEOS) -// Enables permanent removal of Legacy Supervised Users on startup. -BASE_FEATURE(kRemoveSupervisedUsersOnStartup, - base::FEATURE_DISABLED_BY_DEFAULT); -#endif - #if BUILDFLAG(ENABLE_EXTENSIONS_CORE) BASE_FEATURE(kSafetyHubExtensionsUwSTrigger, base::FEATURE_ENABLED_BY_DEFAULT); // Enables extensions that do not display proper privacy practices in the
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h index 9228222..c097fec 100644 --- a/chrome/common/chrome_features.h +++ b/chrome/common/chrome_features.h
@@ -102,9 +102,6 @@ #if BUILDFLAG(IS_CHROMEOS) COMPONENT_EXPORT(CHROME_FEATURES) BASE_DECLARE_FEATURE(kCrostini); -COMPONENT_EXPORT(CHROME_FEATURES) -COMPONENT_EXPORT(CHROME_FEATURES) -BASE_DECLARE_FEATURE(kCrostiniAnsibleSoftwareManagement); #endif // BUILDFLAG(IS_CHROMEOS) COMPONENT_EXPORT(CHROME_FEATURES) @@ -118,10 +115,6 @@ BASE_DECLARE_FEATURE(kPreinstalledWebAppAlwaysMigrateForTesting); #endif -#if BUILDFLAG(IS_CHROMEOS) -BASE_DECLARE_FEATURE(kDesktopTaskManagerEndProcessDisabledForExtension); -#endif // BUILDFLAG(IS_CHROMEOS) - COMPONENT_EXPORT(CHROME_FEATURES) BASE_DECLARE_FEATURE(kChromeFindsInternals); @@ -135,9 +128,6 @@ BASE_DECLARE_FEATURE(kDesktopPWAsElidedExtensionsMenu); COMPONENT_EXPORT(CHROME_FEATURES) -BASE_DECLARE_FEATURE(kDesktopPWAsFlashAppNameInsteadOfOrigin); - -COMPONENT_EXPORT(CHROME_FEATURES) BASE_DECLARE_FEATURE(kDesktopPWAsPreventClose); COMPONENT_EXPORT(CHROME_FEATURES) @@ -148,10 +138,6 @@ #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) COMPONENT_EXPORT(CHROME_FEATURES) BASE_DECLARE_FEATURE(kChromeAppsDeprecation); -COMPONENT_EXPORT(CHROME_FEATURES) -BASE_DECLARE_FEATURE(kShortcutsNotApps); -COMPONENT_EXPORT(CHROME_FEATURES) -BASE_DECLARE_FEATURE(kShortcutsNotAppsRevealDesktop); #endif #if BUILDFLAG(IS_ANDROID) @@ -159,17 +145,6 @@ BASE_DECLARE_FEATURE(kDisplayEdgeToEdgeFullscreen); #endif -COMPONENT_EXPORT(CHROME_FEATURES) BASE_DECLARE_FEATURE(kDnsOverHttps); -COMPONENT_EXPORT(CHROME_FEATURES) -extern const base::FeatureParam<std::string> kDnsOverHttpsTemplatesParam; -COMPONENT_EXPORT(CHROME_FEATURES) - -COMPONENT_EXPORT(CHROME_FEATURES) -BASE_DECLARE_FEATURE(kEnableAmbientAuthenticationInGuestSession); - -COMPONENT_EXPORT(CHROME_FEATURES) -BASE_DECLARE_FEATURE(kEnableAmbientAuthenticationInIncognito); - #if BUILDFLAG(IS_ANDROID) COMPONENT_EXPORT(CHROME_FEATURES) BASE_DECLARE_FEATURE(kEnableFullscreenToAnyScreenAndroid); @@ -177,8 +152,6 @@ #if BUILDFLAG(IS_CHROMEOS) COMPONENT_EXPORT(CHROME_FEATURES) -BASE_DECLARE_FEATURE(kEnterpriseReportingInChromeOS); -COMPONENT_EXPORT(CHROME_FEATURES) BASE_DECLARE_FEATURE(kForcedAppRelaunchOnPlaceholderUpdate); COMPONENT_EXPORT(CHROME_FEATURES) BASE_DECLARE_FEATURE(kUnicornChromeActivityReporting); @@ -872,12 +845,6 @@ kHappinessTrackingSurveysForSecurityPageTriggerId; #endif -#if BUILDFLAG(IS_CHROMEOS) - -COMPONENT_EXPORT(CHROME_FEATURES) -BASE_DECLARE_FEATURE(kHappinessTrackingPrivacyHubPostLaunch); -#endif - COMPONENT_EXPORT(CHROME_FEATURES) BASE_DECLARE_FEATURE(kHttpsFirstBalancedMode); COMPONENT_EXPORT(CHROME_FEATURES) BASE_DECLARE_FEATURE(kHttpsFirstBalancedModeAutoEnable); @@ -971,9 +938,6 @@ BASE_DECLARE_FEATURE(kPrintPreviewCrosPrimary); #endif -COMPONENT_EXPORT(CHROME_FEATURES) -BASE_DECLARE_FEATURE(kPushMessagingBackgroundMode); - COMPONENT_EXPORT(CHROME_FEATURES) BASE_DECLARE_FEATURE(kPwaUpdateDialogForIcon); COMPONENT_EXPORT(CHROME_FEATURES) @@ -984,11 +948,6 @@ COMPONENT_EXPORT(CHROME_FEATURES) BASE_DECLARE_FEATURE(kAbusiveNotificationPermissionRevocation); -#if BUILDFLAG(IS_CHROMEOS) -COMPONENT_EXPORT(CHROME_FEATURES) -BASE_DECLARE_FEATURE(kRemoveSupervisedUsersOnStartup); -#endif - #if BUILDFLAG(ENABLE_EXTENSIONS_CORE) COMPONENT_EXPORT(CHROME_FEATURES) BASE_DECLARE_FEATURE(kSafetyHubExtensionsUwSTrigger);
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc index 06ba851..94b94127 100644 --- a/chrome/common/chrome_switches.cc +++ b/chrome/common/chrome_switches.cc
@@ -142,16 +142,6 @@ // Comma-separated list of SSL cipher suites to disable. const char kCipherSuiteBlacklist[] = "cipher-suite-blacklist"; -// Comma-separated list of BrowserThreads that cause browser process to crash if -// the given browser thread is not responsive. UI/IO are the BrowserThreads that -// are supported. -// -// For example: -// --crash-on-hang-threads=UI:18,IO:18 --> Crash the browser if UI or IO is -// not responsive for 18 seconds while the other browser thread is -// responsive. -const char kCrashOnHangThreads[] = "crash-on-hang-threads"; - // Some platforms like ChromeOS default to empty desktop. // Browser tests may need to add this switch so that at least one browser // instance is created on startup. @@ -273,10 +263,6 @@ // Enables the multi-level undo system for bookmarks. const char kEnableBookmarkUndo[] = "enable-bookmark-undo"; -// This applies only when the process type is "service". Enables the Cloud Print -// Proxy component within the service process. -const char kEnableCloudPrintProxy[] = "enable-cloud-print-proxy"; - #if BUILDFLAG(IS_CHROMEOS) // If enabled, DevTools will allow creating pwa_handler, to enable executing // CDP methods (i.e. PWA.install) on browsers connected remotely @@ -342,20 +328,6 @@ // When a user with zero extensions installed clicks on the extensions puzzle // piece in the Chrome toolbar, Chrome displays a submenu suggesting the user // to explore the Chrome Web Store. -const char kExtensionsToolbarZeroStateVariation[] = - "extensions-toolbar-zero-state-variation"; - -// This variation of the Zero State extensions toolbar recommendation presents -// the user with a single link to the Chrome Web Store home page. -const char kExtensionsToolbarZeroStateSingleWebStoreLink[] = - "extensions-toolbar-zero-state-single-web-store-link"; - -// This variation of the Zero State extensions toolbar recommendation suggests -// extension categories the user can explore in the Chrome Web Store. -// (e.g. find coupons, increase productivity) -const char kExtensionsToolbarZeroStateExploreExtensionsByCategory[] = - "extensions-toolbar-zero-state-explore-extensions-by-category"; - // Forces application mode. This hides certain system UI elements and forces // the app to be installed if it hasn't been already. const char kForceAppMode[] = "force-app-mode"; @@ -487,11 +459,6 @@ // other proxy server flags that are passed. const char kNoProxyServer[] = "no-proxy-server"; -// Disables the service process from adding itself as an autorun process. This -// does not delete existing autorun registrations, it just prevents the service -// from registering a new one. -const char kNoServiceAutorun[] = "no-service-autorun"; - // Does not automatically open a browser window on startup (used when // launching Chrome for the purpose of hosting background apps). const char kNoStartupWindow[] = "no-startup-window"; @@ -617,9 +584,6 @@ // Simulates a critical update being available. const char kSimulateCriticalUpdate[] = "simulate-critical-update"; -// Simulates that elevation is needed to recover upgrade channel. -const char kSimulateElevatedRecovery[] = "simulate-elevated-recovery"; - // Simulates that current version is outdated. const char kSimulateOutdated[] = "simulate-outdated"; @@ -684,6 +648,8 @@ // Custom delay for memory log. This should be used only for testing purpose. const char kTestMemoryLogDelayInMinutes[] = "test-memory-log-delay-in-minutes"; +// Passes the name of the current running automated test to Chrome. +const char kTestName[] = "test-name"; // Identifies a list of download sources as trusted, but only if proper group // policy is set. @@ -800,6 +766,8 @@ #endif #if BUILDFLAG(IS_CHROMEOS) +// Custom crosh command. +const char kCroshCommand[] = "crosh-command"; // Disables logging redirect for testing. const char kDisableLoggingRedirect[] = "disable-logging-redirect"; @@ -947,7 +915,6 @@ #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_MAC) || \ BUILDFLAG(IS_WIN) -const char kEnableNewAppMenuIcon[] = "enable-new-app-menu-icon"; // Causes the browser to launch directly in guest mode. const char kGuest[] = "guest";
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h index f8cf3c1..b6fe61a2 100644 --- a/chrome/common/chrome_switches.h +++ b/chrome/common/chrome_switches.h
@@ -61,7 +61,6 @@ extern const char kCaptureAutoReject[]; extern const char kCheckForUpdateIntervalSec[]; extern const char kCipherSuiteBlacklist[]; -extern const char kCrashOnHangThreads[]; extern const char kCreateBrowserOnStartupForTests[]; extern const char kCredits[]; extern const char kCustomDevtoolsFrontend[]; @@ -96,7 +95,6 @@ extern const char kEnableAudioDebugRecordingsFromExtension[]; extern const char kEnableAutoReload[]; extern const char kEnableBookmarkUndo[]; -extern const char kEnableCloudPrintProxy[]; extern const char kEnableDomainReliability[]; extern const char kEnableDevToolsGreenDevUi[]; #if BUILDFLAG(IS_CHROMEOS) @@ -117,9 +115,6 @@ extern const char kExtensionContentVerificationEnforce[]; extern const char kExtensionContentVerificationEnforceStrict[]; extern const char kExtensionExperimentalActor[]; -extern const char kExtensionsToolbarZeroStateVariation[]; -extern const char kExtensionsToolbarZeroStateSingleWebStoreLink[]; -extern const char kExtensionsToolbarZeroStateExploreExtensionsByCategory[]; extern const char kForceAppMode[]; #if BUILDFLAG(IS_CHROMEOS) extern const char kForceDevToolsAvailable[]; @@ -153,7 +148,6 @@ extern const char kNoFirstRun[]; extern const char kNoPings[]; extern const char kNoProxyServer[]; -extern const char kNoServiceAutorun[]; extern const char kNoStartupWindow[]; extern const char kOnTheFlyMhtmlHashComputation[]; extern const char kOpenInNewWindow[]; @@ -183,7 +177,6 @@ extern const char kSilentLaunch[]; extern const char kSimulateBrowsingDataLifetime[]; extern const char kSimulateCriticalUpdate[]; -extern const char kSimulateElevatedRecovery[]; extern const char kSimulateOutdated[]; extern const char kSimulateOutdatedNoAU[]; extern const char kSimulateUpgrade[]; @@ -201,6 +194,7 @@ extern const char kThisTabCaptureAutoAccept[]; extern const char kThisTabCaptureAutoReject[]; extern const char kTestMemoryLogDelayInMinutes[]; +extern const char kTestName[]; extern const char kTrustedDownloadSources[]; extern const char kUnlimitedStorage[]; extern const char kUnsafelyDisableDevToolsSelfXssWarnings[]; @@ -239,6 +233,7 @@ #endif #if BUILDFLAG(IS_CHROMEOS) +extern const char kCroshCommand[]; extern const char kDisableLoggingRedirect[]; extern const char kDisableLoginScreenApps[]; extern const char kShortMergeSessionTimeoutForTest[]; @@ -289,7 +284,6 @@ #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_MAC) || \ BUILDFLAG(IS_WIN) -extern const char kEnableNewAppMenuIcon[]; extern const char kGuest[]; #endif
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index 43d8d32..f05343a 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h
@@ -919,6 +919,15 @@ // toolbar. inline constexpr char kShowForwardButton[] = "browser.show_forward_button"; +// An integer pref that records how many times a user hovers on a bookmark bar +// button. +inline constexpr char kBookmarkBarHoverCount[] = "bookmark_bar.hover_count"; + +// An integer pref that records how many times a user navigates to a bookmark +// bar link. +inline constexpr char kBookmarkBarNavigationCount[] = + "bookmark_bar.navigation_count"; + // A boolean pref set to true if the Split Tab button should be pinned to the // toolbar. inline constexpr char kPinSplitTabButton[] = "browser.pin_split_tab_button"; @@ -2520,17 +2529,6 @@ // "xkb:us::eng". inline constexpr char kHardwareKeyboardLayout[] = "intl.hardware_keyboard"; -// An integer pref. Its valid values are defined in -// enterprise_management::DeviceRegisterRequest::PsmExecutionResult enum which -// indicates all possible PSM execution results in the Chrome OS enrollment -// flow. -inline constexpr char kEnrollmentPsmResult[] = "EnrollmentPsmResult"; - -// An int64 pref to record the timestamp of PSM retrieving the device's -// determination successfully in the Chrome OS enrollment flow. -inline constexpr char kEnrollmentPsmDeterminationTime[] = - "EnrollmentPsmDeterminationTime"; - // The local state pref that stores device activity times before reporting // them to the policy server. inline constexpr char kDeviceActivityTimes[] = "device_status.activity_times"; @@ -2565,41 +2563,9 @@ inline constexpr char kDeviceRefreshTokenAnyApiIsV3Used[] = "device_refresh_token_is_v3_used.any-api"; -// Device requisition for enterprise enrollment. -inline constexpr char kDeviceEnrollmentRequisition[] = - "enrollment.device_requisition"; - -// Sub organization for enterprise enrollment. -inline constexpr char kDeviceEnrollmentSubOrganization[] = - "enrollment.sub_organization"; - -// Whether to automatically start the enterprise enrollment step during OOBE. -inline constexpr char kDeviceEnrollmentAutoStart[] = "enrollment.auto_start"; - -// Whether the user may exit enrollment. -inline constexpr char kDeviceEnrollmentCanExit[] = "enrollment.can_exit"; - // A string pref with initial locale set in VPD or manifest. inline constexpr char kInitialLocale[] = "intl.initial_locale"; -// A boolean pref of the device registered flag (second part after first login). -inline constexpr char kDeviceRegistered[] = "DeviceRegistered"; - -// Boolean pref to signal corrupted enrollment to force the device through -// enrollment recovery flow upon next boot. -inline constexpr char kEnrollmentRecoveryRequired[] = - "EnrollmentRecoveryRequired"; - -// String pref with the data about the OS version and browser version at the -// time of enrollment. The format is established by release management team. -// The Chrome OS version format is -// [Milestone.]TIP_BUILD.BRANCH_BUILD.BRANCH_BRANCH_BUILD. -// Example: 15711.0.0 -// For browser version the format is MAJOR.MINOR.BRANCH.BUILD. -// Example: 122.0.6252.0 -inline constexpr char kEnrollmentVersionOS[] = "EnrollmentVersionOS"; -inline constexpr char kEnrollmentVersionBrowser[] = "EnrollmentVersionBrowser"; - // Pref name for whether we should show the Getting Started module in the Help // app. inline constexpr char kHelpAppShouldShowGetStarted[] =
diff --git a/chrome/common/read_anything/read_anything.mojom b/chrome/common/read_anything/read_anything.mojom index fcc6d48c..b8c30226 100644 --- a/chrome/common/read_anything/read_anything.mojom +++ b/chrome/common/read_anything/read_anything.mojom
@@ -336,6 +336,9 @@ // to determine whether the browser and renderer are still connected when RM // is closed before the actual connection timeout. AckReadingModeHidden(); + + // Informs the browser that the TTS engine has stalled. + OnSpeechEngineStalled(); }; // Untrusted WebUI-side handler for requests from the browser.
diff --git a/chrome/common/url_constants.h b/chrome/common/url_constants.h index abef2c6..494addf 100644 --- a/chrome/common/url_constants.h +++ b/chrome/common/url_constants.h
@@ -715,6 +715,10 @@ // The URL for the Windows 7/8.1 deprecation help center article. inline constexpr char kWindows78DeprecationURL[] = "https://support.google.com/chrome?p=unsupported_windows"; + +// The URL for the "Learn more" page for process isolation. +inline constexpr char kProcessIsolationLearnMoreUrl[] = + "https://support.google.com/chrome?p=process_isolation"; #endif #if BUILDFLAG(ENABLE_PLUGINS)
diff --git a/chrome/common/webui_url_constants.h b/chrome/common/webui_url_constants.h index 95abced..d9f76a7 100644 --- a/chrome/common/webui_url_constants.h +++ b/chrome/common/webui_url_constants.h
@@ -469,6 +469,9 @@ "managed-user-profile-notice"; inline constexpr char kChromeUIManagedUserProfileNoticeUrl[] = "chrome://managed-user-profile-notice/"; +inline constexpr char kChromeUIManagedUserProfileNoticeRefreshURL[] = + "chrome://managed-user-profile-notice/" + "managed_user_profile_notice_refresh.html"; inline constexpr char kChromeUIProfileCustomizationHost[] = "profile-customization"; inline constexpr char kChromeUIProfileCustomizationURL[] =
diff --git a/chrome/renderer/accessibility/read_anything/read_anything_app_controller.cc b/chrome/renderer/accessibility/read_anything/read_anything_app_controller.cc index eef202b..0608eb7 100644 --- a/chrome/renderer/accessibility/read_anything/read_anything_app_controller.cc +++ b/chrome/renderer/accessibility/read_anything/read_anything_app_controller.cc
@@ -1450,7 +1450,9 @@ .SetMethod("close", &ReadAnythingAppController::CloseUI) .SetMethod("togglePinState", &ReadAnythingAppController::TogglePinState) .SetMethod("sendPinStateRequest", - &ReadAnythingAppController::SendPinStateRequest); + &ReadAnythingAppController::SendPinStateRequest) + .SetMethod("onSpeechEngineStalled", + &ReadAnythingAppController::OnSpeechEngineStalled); } ui::AXNodeID ReadAnythingAppController::RootId() const { @@ -2473,6 +2475,10 @@ RecordEstimatedWordsHeard(); } +void ReadAnythingAppController::OnSpeechEngineStalled() { + page_handler_->OnSpeechEngineStalled(); +} + void ReadAnythingAppController::OnTabWillDetach() { model_.set_will_hide(true); if (read_aloud_model_.speech_playing()) {
diff --git a/chrome/renderer/accessibility/read_anything/read_anything_app_controller.h b/chrome/renderer/accessibility/read_anything/read_anything_app_controller.h index 89cbeb8..bde3109 100644 --- a/chrome/renderer/accessibility/read_anything/read_anything_app_controller.h +++ b/chrome/renderer/accessibility/read_anything/read_anything_app_controller.h
@@ -350,6 +350,7 @@ void TogglePresentation(); void TogglePinState(); void OnPinStatusReceived(bool pin_state) override; + void OnSpeechEngineStalled(); // Returns the current active distillation method state as an integer. int GetDistillationMethod() const;
diff --git a/chrome/renderer/accessibility/read_anything/read_anything_app_controller_browsertest.cc b/chrome/renderer/accessibility/read_anything/read_anything_app_controller_browsertest.cc index ba0d579..ecef46c 100644 --- a/chrome/renderer/accessibility/read_anything/read_anything_app_controller_browsertest.cc +++ b/chrome/renderer/accessibility/read_anything/read_anything_app_controller_browsertest.cc
@@ -150,6 +150,7 @@ OnDistillationStateChanged, (read_anything::mojom::ReadAnythingDistillationState new_state), (override)); + MOCK_METHOD(void, OnSpeechEngineStalled, (), (override)); mojo::PendingRemote<read_anything::mojom::UntrustedPageHandler> BindNewPipeAndPassRemote() { @@ -211,6 +212,15 @@ Mock::VerifyAndClearExpectations(distiller_); } + void TearDown() override { + // `controller_` owns `distiller_` and RenderFrame (indirectly) owns + // `controller_`: it is a garbage-collected object owned by Oilpan and its + // lifetime is tied to the RenderFrame's lifetime. + controller_ = nullptr; + distiller_ = nullptr; + ChromeRenderViewTest::TearDown(); + } + ReadAnythingAppController& controller() { return *controller_; } ReadAnythingAppModel& model() { return controller_->model_; } ReadAloudAppModel& read_aloud_model() { @@ -382,13 +392,13 @@ static constexpr ui::AXNodeID kId5 = 100; ui::AXTreeID tree_id_; - raw_ptr<MockAXTreeDistiller, DanglingUntriaged> distiller_ = nullptr; + raw_ptr<MockAXTreeDistiller> distiller_ = nullptr; testing::StrictMock<MockReadAnythingUntrustedPageHandler> page_handler_; base::test::ScopedFeatureList scoped_feature_list_; // ReadAnythingAppController constructor and destructor are protected so // it's not accessible by std::make_unique. - raw_ptr<ReadAnythingAppController, DanglingUntriaged> controller_ = nullptr; + raw_ptr<ReadAnythingAppController> controller_ = nullptr; }; #if BUILDFLAG(IS_CHROMEOS)
diff --git a/chrome/renderer/safe_browsing/phishing_classifier_delegate_browsertest.cc b/chrome/renderer/safe_browsing/phishing_classifier_delegate_browsertest.cc index 75b89015..31c9369 100644 --- a/chrome/renderer/safe_browsing/phishing_classifier_delegate_browsertest.cc +++ b/chrome/renderer/safe_browsing/phishing_classifier_delegate_browsertest.cc
@@ -153,6 +153,14 @@ classifier_not_ready_ = false; } + void TearDown() override { + // `delegate_` owns `classifier_` and the RenderFrame owns `delegate_`; + // clear these pointers now to avoid dangling references. + classifier_ = nullptr; + delegate_ = nullptr; + ChromeRenderViewTest::TearDown(); + } + // Runs the ClassificationDone callback, then verify if message sent // by FakeRenderThread is correct. void RunAndVerifyClassificationDone(const ClientPhishingRequest& verdict) { @@ -207,10 +215,9 @@ Scorer::Create(mapped_region.region.Duplicate(), base::File())); } - raw_ptr<StrictMock<MockPhishingClassifier>, DanglingUntriaged> - classifier_; // Owned by |delegate_|. - raw_ptr<PhishingClassifierDelegate, DanglingUntriaged> - delegate_; // Owned by the RenderFrame. + // Owned by |delegate_|. + raw_ptr<StrictMock<MockPhishingClassifier>> classifier_; + raw_ptr<PhishingClassifierDelegate> delegate_; // Owned by the RenderFrame. bool classifier_not_ready_; base::test::ScopedFeatureList feature_list_; };
diff --git a/chrome/renderer/translate/translate_agent_browsertest.cc b/chrome/renderer/translate/translate_agent_browsertest.cc index bc5e8b9..6597177 100644 --- a/chrome/renderer/translate/translate_agent_browsertest.cc +++ b/chrome/renderer/translate/translate_agent_browsertest.cc
@@ -4,6 +4,7 @@ #include "components/translate/content/renderer/translate_agent.h" +#include <memory> #include <tuple> #include <utility> @@ -12,7 +13,6 @@ #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/functional/bind.h" -#include "base/memory/raw_ptr.h" #include "base/path_service.h" #include "base/run_loop.h" #include "base/time/time.h" @@ -179,7 +179,7 @@ class TranslateAgentBrowserTest : public ChromeRenderViewTest { public: - TranslateAgentBrowserTest() : translate_agent_(nullptr) {} + TranslateAgentBrowserTest() = default; TranslateAgentBrowserTest(const TranslateAgentBrowserTest&) = delete; TranslateAgentBrowserTest& operator=(const TranslateAgentBrowserTest&) = @@ -188,7 +188,8 @@ protected: void SetUp() override { ChromeRenderViewTest::SetUp(); - translate_agent_ = new TestTranslateAgent(GetMainRenderFrame()); + translate_agent_ = + std::make_unique<TestTranslateAgent>(GetMainRenderFrame()); GetMainRenderFrame()->GetBrowserInterfaceBroker().SetBinderForTesting( translate::mojom::ContentTranslateDriver::Name_, @@ -203,11 +204,11 @@ GetMainRenderFrame()->GetBrowserInterfaceBroker().SetBinderForTesting( translate::mojom::ContentTranslateDriver::Name_, {}); - delete translate_agent_; + translate_agent_.reset(); ChromeRenderViewTest::TearDown(); } - raw_ptr<TestTranslateAgent, DanglingUntriaged> translate_agent_; + std::unique_ptr<TestTranslateAgent> translate_agent_; FakeContentTranslateDriver fake_translate_driver_; };
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index b77ad406..f04cee6 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -1595,6 +1595,7 @@ if (enable_extensions_core) { sources += [ + "../browser/extensions/all_urls_apitest.cc", "../browser/extensions/api/alarms/alarms_apitest.cc", "../browser/extensions/api/bookmarks/bookmarks_apitest.cc", "../browser/extensions/api/browsing_data/browsing_data_test.cc", @@ -2711,6 +2712,8 @@ "//chrome/browser/support_tool:support_tool_proto", "//chrome/browser/sync", "//chrome/browser/sync/test/integration:sync_integration_test_support", + "//chrome/browser/tab_contents", + "//chrome/browser/tab_contents:browser_tests", "//chrome/browser/tab_group_sync:factories", "//chrome/browser/task_manager/common", "//chrome/browser/themes", @@ -3529,7 +3532,6 @@ "../browser/devtools/protocol/form_devtools_issues_browsertest.cc", "../browser/direct_sockets/direct_sockets_apitest.cc", "../browser/download/download_browsertest.cc", - "../browser/download/download_danger_prompt_browsertest.cc", "../browser/download/download_frame_policy_browsertest.cc", "../browser/download/save_page_browsertest.cc", "../browser/enterprise/browser_management/management_service_browsertest.cc", @@ -3821,8 +3823,6 @@ "../browser/support_tool/policy_data_collector_browsertest.cc", "../browser/support_tool/support_tool_util_browsertest.cc", "../browser/sync/sessions/sync_sessions_router_tab_helper_browsertest.cc", - "../browser/tab_contents/navigation_metrics_recorder_browsertest.cc", - "../browser/tab_contents/view_source_browsertest.cc", "../browser/task_manager/providers/web_contents/background_contents_tag_browsertest.cc", "../browser/task_manager/providers/web_contents/devtools_tag_browsertest.cc", "../browser/task_manager/providers/web_contents/subframe_task_browsertest.cc", @@ -4830,7 +4830,6 @@ "../browser/controlled_frame/scoped_test_driver_proxy.h", "../browser/extensions/ai_language_model_browsertest.cc", "../browser/extensions/alert_apitest.cc", - "../browser/extensions/all_urls_apitest.cc", "../browser/extensions/api/activity_log_private/activity_log_private_apitest.cc", "../browser/extensions/api/autofill_private/autofill_private_api_unittest.cc", "../browser/extensions/api/autofill_private/autofill_private_apitest.cc", @@ -6840,7 +6839,6 @@ "../browser/ui/webui/chrome_urls/chrome_urls_handler_unittest.cc", "../browser/ui/webui/fileicon_source_unittest.cc", "../browser/ui/webui/log_web_ui_url_unittest.cc", - "../browser/visibility_timer_tab_helper_unittest.cc", "../browser/webauthn/chrome_web_authentication_delegate_base_unittest.cc", "../browser/webauthn/password_credential_fetcher_unittest.cc", "../common/chrome_content_client_unittest.cc", @@ -7105,6 +7103,7 @@ "//chrome/browser/feedback:unit_tests", "//chrome/browser/file_system_access", "//chrome/browser/file_system_access:unit_tests", + "//chrome/browser/finds/core:unit_tests", "//chrome/browser/first_party_sets", "//chrome/browser/gcm", "//chrome/browser/gcm:unit_tests", @@ -7115,6 +7114,7 @@ "//chrome/browser/history", "//chrome/browser/history_clusters", "//chrome/browser/history_clusters:unit_tests", + "//chrome/browser/idle", "//chrome/browser/loader:unit_tests", "//chrome/browser/media:unittests", "//chrome/browser/media/prefs", @@ -8119,7 +8119,6 @@ "../browser/ui/android/tab_contents/chrome_web_contents_view_delegate_android_unittest.cc", "../browser/ui/android/toolbar/adaptive_toolbar_bridge_unittest.cc", "../browser/ui/android/toolbar/location_bar_model_android_unittest.cc", - "../browser/wallet/android/boarding_pass_detector_unittest.cc", "../browser/webauthn/android/cable_module_android_unittest.cc", "../browser/webauthn/android/cable_registration_state_unittest.cc", "../browser/webauthn/android/credential_sorter_android_unittest.cc", @@ -8191,10 +8190,11 @@ "//chrome/browser/ui/plus_addresses:unit_tests", "//chrome/browser/ui/serial", "//chrome/browser/ui/serial:test_support", - "//chrome/browser/ui/side_panel/test:native_unit_test_support_java", + "//chrome/browser/ui/side_panel/android:unit_tests", + "//chrome/browser/ui/side_panel/test/android:native_unit_test_support_java", "//chrome/browser/ui/tabs:tab_enums", "//chrome/browser/usb", - "//chrome/common/wallet:mojo_bindings", + "//chrome/browser/wallet/android:unit_tests", "//chrome/services/media_gallery_util:unit_tests", "//components/back_forward_cache", "//components/bookmarks/common/android", @@ -8401,7 +8401,6 @@ "../browser/sync/sessions/browser_list_router_helper_unittest.cc", "../browser/sync/sessions/sync_sessions_router_tab_helper_unittest.cc", "../browser/sync/sync_ui_util_unittest.cc", # Sync setup uses native ui. - "../browser/tab_contents/form_interaction_tab_helper_unittest.cc", "../browser/task_manager/sampling/task_group_unittest.cc", "../browser/task_manager/sampling/task_manager_impl_unittest.cc", "../browser/task_manager/task_manager_observer_unittest.cc", @@ -8565,6 +8564,7 @@ deps += [ "//chrome/browser/actor", "//chrome/browser/actor/ui/task_list_bubble:unit_tests", + "//chrome/browser/autocomplete:aim_eligibility_service", "//chrome/browser/autofill/actor:unit_tests", "//chrome/browser/bluetooth", "//chrome/browser/contextual_cueing:unit_tests", @@ -8592,6 +8592,8 @@ "//chrome/browser/send_tab_to_self:unit_tests", "//chrome/browser/serial", "//chrome/browser/signin:signin_promo", + "//chrome/browser/tab_contents", + "//chrome/browser/tab_contents:unit_tests", "//chrome/browser/tab_group_sync:factories", "//chrome/browser/task_manager/common", "//chrome/browser/ui/bookmarks:unit_tests", @@ -8649,6 +8651,7 @@ "//chrome/browser/ui/webui:webui_util", "//chrome/browser/ui/webui/access_code_cast:unit_tests", "//chrome/browser/ui/webui/app_management:unit_tests", + "//chrome/browser/ui/webui/content_annotator_internals:unit_tests", "//chrome/browser/ui/webui/cr_components/composebox", "//chrome/browser/ui/webui/data_sharing", "//chrome/browser/ui/webui/metrics_reporter:test_support", @@ -10206,7 +10209,6 @@ "../browser/safe_browsing/cloud_content_scanning/cloud_binary_upload_service_unittest.cc", "../browser/safe_browsing/cloud_content_scanning/deep_scanning_utils_unittest.cc", "../browser/safe_browsing/cloud_content_scanning/file_analysis_request_unittest.cc", - "../browser/safe_browsing/cloud_content_scanning/file_opening_job_unittest.cc", "../browser/safe_browsing/download_protection/download_feedback_service_unittest.cc", "../browser/safe_browsing/download_protection/download_feedback_unittest.cc", "../browser/safe_browsing/download_protection/path_sanitizer_unittest.cc", @@ -10675,6 +10677,7 @@ "//chrome/browser/ui/page_info", "//chrome/browser/ui/tab_contents", "//chrome/browser/ui/tabs:tab_enums", + "//chrome/browser/ui/tabs/projects", "//chrome/browser/ui/toasts", "//chrome/browser/ui/toolbar:test_support", "//chrome/browser/ui/toolbar:unit_tests", @@ -10805,6 +10808,7 @@ "../browser/ui/views/omnibox/omnibox_match_cell_view_unittest.cc", "../browser/ui/views/omnibox/omnibox_result_view_unittest.cc", "../browser/ui/views/omnibox/omnibox_view_views_unittest.cc", + "../browser/ui/views/omnibox/webui_readonly_omnibox_unittest.cc", "../browser/ui/views/overlay/overlay_controls_fade_animation_unittest.cc", "../browser/ui/views/overlay/video_overlay_window_views_unittest.cc", "../browser/ui/views/page_info/page_info_bubble_view_unittest.cc", @@ -11529,6 +11533,7 @@ "../browser/ui/browser_command_controller_interactive_uitest.cc", "../browser/ui/browser_focus_interactive_uitest.cc", "../browser/ui/extensions/controlled_home_dialog_interactive_uitest.cc", + "../browser/ui/extensions/download_danger_dialog_interactive_uitest.cc", "../browser/ui/fullscreen_keyboard_browsertest_base.cc", "../browser/ui/fullscreen_keyboard_browsertest_base.h", "../browser/ui/keyboard_lock_interactive_uitest.cc", @@ -11756,6 +11761,7 @@ "//chrome/browser/ui/webui/access_code_cast:interactive_ui_tests", "//chrome/browser/ui/webui/searchbox:searchbox_test_utils", "//chrome/browser/ui/webui/skills", + "//chrome/browser/ui/webui/whats_new:interactive_ui_tests", "//chrome/browser/web_applications:features", "//chrome/browser/web_applications:interactive_ui_tests", "//chrome/browser/web_applications:web_applications_test_support",
diff --git a/chrome/test/data/extensions/api_test/declarative_net_request/dynamic_rules/background.js b/chrome/test/data/extensions/api_test/declarative_net_request/dynamic_rules/background.js index 6625421..806098c 100644 --- a/chrome/test/data/extensions/api_test/declarative_net_request/dynamic_rules/background.js +++ b/chrome/test/data/extensions/api_test/declarative_net_request/dynamic_rules/background.js
@@ -34,7 +34,7 @@ } function createLargeRegexRuleWithID(id) { - let rule = createRegexRuleWithID(id); + const rule = createRegexRuleWithID(id); rule.condition.regexFilter = '.{512}x'; return rule; } @@ -49,7 +49,7 @@ chrome.test.assertNoLastError(); // Sort by ID first since assertEq respects order of arrays. - let comparator = (rule1, rule2) => rule1.id - rule2.id; + const comparator = (rule1, rule2) => rule1.id - rule2.id; actualRules.sort(comparator); expectedRules.sort(comparator);
diff --git a/chrome/test/data/extensions/api_test/declarative_net_request/dynamic_rules_limits/background.js b/chrome/test/data/extensions/api_test/declarative_net_request/dynamic_rules_limits/background.js index fd4184f..cb063afcf 100644 --- a/chrome/test/data/extensions/api_test/declarative_net_request/dynamic_rules_limits/background.js +++ b/chrome/test/data/extensions/api_test/declarative_net_request/dynamic_rules_limits/background.js
@@ -2,18 +2,18 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -var updateDynamicRules = chrome.declarativeNetRequest.updateDynamicRules; -var getDynamicRules = chrome.declarativeNetRequest.getDynamicRules; +const updateDynamicRules = chrome.declarativeNetRequest.updateDynamicRules; +const getDynamicRules = chrome.declarativeNetRequest.getDynamicRules; // Rule limits are actually set after the browser replies to the extension's // "ready" message. -var ruleLimit = -1; -var unsafeRuleLimit = -1; -var regexRuleLimit = -1; +let ruleLimit = -1; +let unsafeRuleLimit = -1; +let regexRuleLimit = -1; -var nextId = 1; +let nextId = 1; -var createRuleWithID = function(id) { +const createRuleWithID = function(id) { return { id: id, priority: 1, @@ -22,7 +22,7 @@ }; }; -var createRedirectRuleWithID = function(id) { +const createRedirectRuleWithID = function(id) { return { id: id, priority: 1, @@ -31,7 +31,7 @@ }; }; -var createRegexRuleWithID = function(id) { +const createRegexRuleWithID = function(id) { return { id: id, priority: 1, @@ -42,13 +42,13 @@ // Verifies the current set of rules. Ensures no error is signalled and proceeds // to the next test. -var verifyCurrentRulesCallback = function() { +const verifyCurrentRulesCallback = function() { chrome.test.assertNoLastError(); getDynamicRules(function(rules) { chrome.test.assertNoLastError(); - var comparator = function(rule1, rule2) { + const comparator = function(rule1, rule2) { return rule1.id - rule2.id; }; @@ -60,7 +60,7 @@ chrome.test.succeed(); }); }; -var currentRules = []; +let currentRules = []; const testCases = [ // Sanity check that rule limits received from the browser have been set. @@ -74,7 +74,7 @@ // Ensure that an extension can add up to `regexRuleLimit` number of regex // rules. function regexRuleLimitReached() { - var newRules = []; + let newRules = []; while (newRules.length < regexRuleLimit) { newRules.push(createRegexRuleWithID(nextId++)); } @@ -95,7 +95,7 @@ // Ensure that an extension can add up to `unsafeRuleLimit` number of "unsafe" // rules. function unsafeRuleLimitReached() { - var newRules = []; + let newRules = []; while (newRules.length < unsafeRuleLimit) { newRules.push(createRedirectRuleWithID(nextId++)); } @@ -115,8 +115,8 @@ // Ensure we can add up to `ruleLimit` no. of rules. function ruleLimitReached() { - var numRulesToAdd = ruleLimit - currentRules.length; - var newRules = []; + const numRulesToAdd = ruleLimit - currentRules.length; + let newRules = []; while (newRules.length < numRulesToAdd) newRules.push(createRuleWithID(nextId++));
diff --git a/chrome/test/data/extensions/api_test/declarative_net_request/fenced_frames/background.js b/chrome/test/data/extensions/api_test/declarative_net_request/fenced_frames/background.js index 0e4e955..d548e96 100644 --- a/chrome/test/data/extensions/api_test/declarative_net_request/fenced_frames/background.js +++ b/chrome/test/data/extensions/api_test/declarative_net_request/fenced_frames/background.js
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -var expectedCallback; -var tab; +let expectedCallback; +let tab; // Navigates to |url| and invokes |callback| when a rule has been queued. function navigateTab(url, callback) { @@ -11,16 +11,16 @@ chrome.tabs.update(tab.id, {url: url}); } -var matchedRules = []; -var documentIds = []; -var nextDocumentId = 1; +let matchedRules = []; +const documentIds = []; +let nextDocumentId = 1; -var onRuleMatchedDebugCallback = (rule) => { +const onRuleMatchedDebugCallback = (rule) => { matchedRules.push(rule); expectedCallback(tab); }; -var testServerPort; +let testServerPort; function getServerURL(host) { if (!testServerPort) throw new Error('Called getServerURL outside of runTests.'); @@ -59,10 +59,10 @@ chrome.test.assertEq(expectedRuleInfo, matchedRule); } -// Opaque initiators serialize to "null". -const kOpaqueInitiator = "null"; +// Opaque initiators serialize to 'null'. +const kOpaqueInitiator = 'null'; -var tests = [ +const tests = [ function setup() { chrome.declarativeNetRequest.onRuleMatchedDebug.addListener( onRuleMatchedDebugCallback); @@ -217,7 +217,7 @@ chrome.test.getConfig(async (config) => { testServerPort = config.testServer.port; tab = await new Promise(function(resolve, reject) { - chrome.tabs.create({"url": "about:blank"}, (value) => { + chrome.tabs.create({url: 'about:blank'}, (value) => { resolve(value); }); });
diff --git a/chrome/test/data/extensions/api_test/declarative_net_request/get_matched_rules/background.js b/chrome/test/data/extensions/api_test/declarative_net_request/get_matched_rules/background.js index 9bbadb2..6e4e374 100644 --- a/chrome/test/data/extensions/api_test/declarative_net_request/get_matched_rules/background.js +++ b/chrome/test/data/extensions/api_test/declarative_net_request/get_matched_rules/background.js
@@ -14,14 +14,14 @@ chrome.tabs.update({url: url}); } -var testServerPort; +let testServerPort; function getServerURL(host) { if (!testServerPort) throw new Error('Called getServerURL outside of runTests.'); return `http://${host}:${testServerPort}/`; } -var testData = [ +const testData = [ {host: 'ab.com', rule: {ruleId: 1, rulesetId: 'rules1'}}, {host: 'abc.com', rule: {ruleId: 2, rulesetId: 'rules1'}}, {host: 'abcd.com', rule: {ruleId: 1, rulesetId: 'rules2'}}, @@ -113,19 +113,19 @@ chrome.test.getConfig(function(config) { testServerPort = config.testServer.port; - var tests = []; + const tests = []; // First add the dynamic and session rule, since it's required by one of the // latter tests. tests.push(addDynamicRule); tests.push(addSessionRule); - for (var i = 0; i < testData.length; ++i) { - var test = createTest(i); + for (let i = 0; i < testData.length; ++i) { + const test = createTest(i); // Assign a name to the function so that the extension test framework prints // the sub-test name. - Object.defineProperty(test, 'name', {value: 'test' + i}) + Object.defineProperty(test, 'name', {value: `test${i}`}) tests.push(test); }
diff --git a/chrome/test/data/extensions/api_test/declarative_net_request/modify_headers/background.js b/chrome/test/data/extensions/api_test/declarative_net_request/modify_headers/background.js index c0e06ce9..120174c4 100644 --- a/chrome/test/data/extensions/api_test/declarative_net_request/modify_headers/background.js +++ b/chrome/test/data/extensions/api_test/declarative_net_request/modify_headers/background.js
@@ -14,8 +14,8 @@ chrome.tabs.update({url: url}); } -var testServerPort; -var host = 'xyz.com'; +let testServerPort; +const host = 'xyz.com'; function getServerURL(path) { if (!testServerPort) throw new Error('Called getServerURL outside of runTests.'); @@ -29,7 +29,7 @@ // Adds or updates the given header name/value to |headers|. function addOrUpdateHeader(headers, headerName, headerValue) { - var index = + const index = headers.findIndex(header => header.name.toLowerCase() == headerName); if (index != -1) { headers[index].value = headerValue; @@ -42,12 +42,12 @@ // that it isn't visible to web request listeners. Then proceeds to the next // test. function checkCookieHeaderRemoved(expectRemoved) { - var echoCookieUrl = getServerURL('echoheader?cookie'); + const echoCookieUrl = getServerURL('echoheader?cookie'); // Register web request listeners for |echoCookieUrl|. - var filter = {urls: [echoCookieUrl]}; - var extraInfoSpec = ['requestHeaders', 'extraHeaders']; - var onSendHeadersSeen = false; + const filter = {urls: [echoCookieUrl]}; + const extraInfoSpec = ['requestHeaders', 'extraHeaders']; + let onSendHeadersSeen = false; chrome.webRequest.onSendHeaders.addListener(function listener(details) { chrome.webRequest.onSendHeaders.removeListener(listener); onSendHeadersSeen = true; @@ -96,7 +96,7 @@ // Removes all the cookies and optionally checks if |optCurrentCookiesSet| // corresponds to the current cookies. Returns a promise. function checkAndResetCookies(optCurrentCookiesSet) { - var removeCookiesPromise = + const removeCookiesPromise = function(cookieParams) { return new Promise((resolve, reject) => { chrome.cookies.remove(cookieParams, function(details) { @@ -106,18 +106,18 @@ }); } - var url = getServerURL(''); + const url = getServerURL(''); return new Promise((resolve, reject) => { chrome.cookies.getAll({url: url}, function(cookies) { if (optCurrentCookiesSet) { chrome.test.assertEq(cookies.length, optCurrentCookiesSet.size); - for (var i = 0; i < cookies.length; ++i) + for (let i = 0; i < cookies.length; ++i) chrome.test.assertTrue(optCurrentCookiesSet.has(cookies[i].name)); } - var promises = []; - for (var i = 0; i < cookies.length; ++i) + const promises = []; + for (let i = 0; i < cookies.length; ++i) promises.push(removeCookiesPromise({url: url, name: cookies[i].name})); Promise.all(promises).then(resolve, reject); @@ -129,12 +129,12 @@ // and that it isn't visible to web request listeners. Then proceeds to the next // test. function checkSetCookieHeaderRemoved(expectRemoved) { - var setCookieUrl = getServerURL('set-cookie?foo1=bar1&foo2=bar2'); + const setCookieUrl = getServerURL('set-cookie?foo1=bar1&foo2=bar2'); // Register web request listeners for |setCookieUrl|. - var filter = {urls: [setCookieUrl]}; - var extraInfoSpec = ['responseHeaders', 'extraHeaders']; - var onResponseStartedSeen = false; + const filter = {urls: [setCookieUrl]}; + const extraInfoSpec = ['responseHeaders', 'extraHeaders']; + let onResponseStartedSeen = false; chrome.webRequest.onResponseStarted.addListener(function listener(details) { chrome.webRequest.onResponseStarted.removeListener(listener); onResponseStartedSeen = true; @@ -148,7 +148,7 @@ navigateTab(setCookieUrl, function(tab) { chrome.test.assertTrue(onResponseStartedSeen); - var expectedCookies = expectRemoved ? [] : ['foo1', 'foo2']; + const expectedCookies = expectRemoved ? [] : ['foo1', 'foo2']; checkAndResetCookies(new Set(expectedCookies)).then(chrome.test.succeed); }); }); @@ -157,13 +157,13 @@ // Checks whether the cookie request header added by Web request extension was // removed. Then proceeds to the next test. function checkAddWebRequestCookie(expectRemoved) { - var echoCookieUrl = getServerURL('echoheader?cookie'); + const echoCookieUrl = getServerURL('echoheader?cookie'); // Register web request listeners for |echoCookieUrl|. - var filter = {urls: [echoCookieUrl]}; - var extraInfoSpec = ['requestHeaders', 'extraHeaders', 'blocking']; - var onBeforeSendHeadersSeen = false; - var onBeforeSendHeadersListener = function listener(details) { + const filter = {urls: [echoCookieUrl]}; + const extraInfoSpec = ['requestHeaders', 'extraHeaders', 'blocking']; + let onBeforeSendHeadersSeen = false; + const onBeforeSendHeadersListener = function listener(details) { onBeforeSendHeadersSeen = true; addOrUpdateHeader(details.requestHeaders, 'cookie', 'webRequest=true'); return {requestHeaders: details.requestHeaders}; @@ -171,8 +171,8 @@ chrome.webRequest.onBeforeSendHeaders.addListener( onBeforeSendHeadersListener, filter, extraInfoSpec); - var onActionIgnoredCalled = false; - var onActionIgnoredListener = function(details) { + let onActionIgnoredCalled = false; + const onActionIgnoredListener = function(details) { onActionIgnoredCalled = true; chrome.test.assertEq('request_headers', details.action); }; @@ -199,13 +199,13 @@ // Checks whether the set-cookie request header added by Web request extension // was removed. function checkAddWebRequestSetCookie(expectRemoved) { - var url = getServerURL('echo'); + const url = getServerURL('echo'); // Register web request listeners for |url|. - var filter = {urls: [url]}; - var extraInfoSpec = ['responseHeaders', 'extraHeaders', 'blocking']; - var onHeadersReceivedSeen = false; - var onHeadersReceivedListener = function listener(details) { + const filter = {urls: [url]}; + const extraInfoSpec = ['responseHeaders', 'extraHeaders', 'blocking']; + let onHeadersReceivedSeen = false; + const onHeadersReceivedListener = function listener(details) { onHeadersReceivedSeen = true; addOrUpdateHeader(details.responseHeaders, 'set-cookie', 'webRequest=true'); return {responseHeaders: details.responseHeaders}; @@ -213,8 +213,8 @@ chrome.webRequest.onHeadersReceived.addListener( onHeadersReceivedListener, filter, extraInfoSpec); - var onActionIgnoredCalled = false; - var onActionIgnoredListener = function(details) { + let onActionIgnoredCalled = false; + const onActionIgnoredListener = function(details) { onActionIgnoredCalled = true; chrome.test.assertEq('response_headers', details.action); }; @@ -229,7 +229,7 @@ chrome.test.assertTrue(onHeadersReceivedSeen); chrome.test.assertEq(expectRemoved, onActionIgnoredCalled); - var expectedCookies = expectRemoved ? [] : ['webRequest'] + const expectedCookies = expectRemoved ? [] : ['webRequest'] checkAndResetCookies(new Set(expectedCookies)).then(chrome.test.succeed); }); }); @@ -245,7 +245,7 @@ }); } -var removeCookieRule = { +const removeCookieRule = { id: 1, priority: 1, condition: {urlFilter: host, resourceTypes: ['main_frame']}, @@ -254,7 +254,7 @@ requestHeaders: [{header: 'cookie', operation: 'remove'}] } }; -var removeSetCookieRule = { +const removeSetCookieRule = { id: 2, priority: 1, condition: {urlFilter: host, resourceTypes: ['main_frame']}, @@ -263,13 +263,13 @@ responseHeaders: [{header: 'set-cookie', operation: 'remove'}] } }; -var allowRule = { +const allowRule = { id: 3, priority: 1, condition: {urlFilter: host, resourceTypes: ['main_frame']}, action: {type: 'allow'} }; -var setCustomRequestHeaderRule = { +const setCustomRequestHeaderRule = { id: 10, priority: 1, condition: {urlFilter: host, resourceTypes: ['main_frame']}, @@ -278,7 +278,7 @@ requestHeaders: [{header: 'header1', operation: 'set', value: 'value-1'}] } }; -var appendRequestHeadersRule = { +const appendRequestHeadersRule = { id: 100, priority: 1, condition: {urlFilter: host, resourceTypes: ['main_frame']}, @@ -288,7 +288,7 @@ } }; -var tests = [ +const tests = [ function testCookieWithoutRules() { navigateTab(getServerURL('set-cookie?foo1=bar1&foo2=bar2'), function() { checkCookieHeaderRemoved(false); @@ -296,7 +296,7 @@ }, function testAppendRequestHeaderRule() { - var rules = [appendRequestHeadersRule]; + const rules = [appendRequestHeadersRule]; chrome.declarativeNetRequest.updateDynamicRules( {addRules: rules}, function() { chrome.test.assertNoLastError(); @@ -306,7 +306,7 @@ }, function addRulesAndTestCookieRemoval() { - var rules = [removeCookieRule]; + const rules = [removeCookieRule]; chrome.declarativeNetRequest.updateDynamicRules( {removeRuleIds: [appendRequestHeadersRule.id], addRules: rules}, function() { @@ -320,7 +320,7 @@ }, function addRulesAndTestSetCookieRemoval() { - var rules = [removeSetCookieRule]; + const rules = [removeSetCookieRule]; chrome.declarativeNetRequest.updateDynamicRules( {addRules: rules}, function() { chrome.test.assertNoLastError(); @@ -339,7 +339,7 @@ // be added back by web request listeners since Declarative Net Request // actions have higher priority than web request actions. function testAddWebRequestCookieWithRules() { - var rules = [removeCookieRule]; + const rules = [removeCookieRule]; chrome.declarativeNetRequest.updateDynamicRules( {addRules: rules}, function() { chrome.test.assertNoLastError(); @@ -355,7 +355,7 @@ // be added back by web request listeners since Declarative Net Request // actions have higher priority than web request actions. function testAddWebRequestSetCookieWithRules() { - var rules = [removeSetCookieRule]; + const rules = [removeSetCookieRule]; chrome.declarativeNetRequest.updateDynamicRules( {addRules: rules}, function() { chrome.test.assertNoLastError(); @@ -371,7 +371,7 @@ }, function testSetCustomRequestHeaderRule() { - var rules = [setCustomRequestHeaderRule]; + const rules = [setCustomRequestHeaderRule]; chrome.declarativeNetRequest.updateDynamicRules( {removeRuleIds: [allowRule.id], addRules: rules}, function() { chrome.test.assertNoLastError(); @@ -380,7 +380,7 @@ }, function testSetCustomResponseHeaderRule() { - var rules = [ + const rules = [ { id: 20, priority: 3, @@ -421,7 +421,7 @@ } ]; - var expectedResponseHeaders = { + const expectedResponseHeaders = { header1: 'original, rule-20, rule-22', header2: 'rule-20', header3: 'rule-20, rule-22',
diff --git a/chrome/test/data/extensions/api_test/declarative_net_request/on_rules_matched_debug/background.js b/chrome/test/data/extensions/api_test/declarative_net_request/on_rules_matched_debug/background.js index 7623519..2519e6d5 100644 --- a/chrome/test/data/extensions/api_test/declarative_net_request/on_rules_matched_debug/background.js +++ b/chrome/test/data/extensions/api_test/declarative_net_request/on_rules_matched_debug/background.js
@@ -14,12 +14,12 @@ chrome.tabs.update({url: url}); } -var matchedRules = []; -var onRuleMatchedDebugCallback = (rule) => { +let matchedRules = []; +const onRuleMatchedDebugCallback = (rule) => { matchedRules.push(rule); }; -var testServerPort; +let testServerPort; function getServerURL(host) { if (!testServerPort) throw new Error('Called getServerURL outside of runTests.'); @@ -55,7 +55,7 @@ chrome.test.assertEq(expectedRuleInfo, matchedRule); } -var tests = [ +const tests = [ function setup() { chrome.declarativeNetRequest.onRuleMatchedDebug.addListener( onRuleMatchedDebugCallback); @@ -74,7 +74,7 @@ const rule = { id: 1, priority: 1, - condition: {urlFilter: 'def', 'resourceTypes': ['main_frame']}, + condition: {urlFilter: 'def', resourceTypes: ['main_frame']}, action: {type: 'block'}, };
diff --git a/chrome/test/data/extensions/api_test/declarative_net_request/prerendering/background.js b/chrome/test/data/extensions/api_test/declarative_net_request/prerendering/background.js index 572dabd3..d66d945 100644 --- a/chrome/test/data/extensions/api_test/declarative_net_request/prerendering/background.js +++ b/chrome/test/data/extensions/api_test/declarative_net_request/prerendering/background.js
@@ -39,28 +39,28 @@ { addRules: [ { - 'id': 1, - 'priority': 1, - 'condition': { - 'urlFilter': 'block_main', - 'resourceTypes': ['main_frame'] + id: 1, + priority: 1, + condition: { + urlFilter: 'block_main', + resourceTypes: ['main_frame'] }, - 'action': {'type': 'block'} + action: {type: 'block'} }, { - 'id': 2, - 'priority': 1, - 'condition': - {'urlFilter': 'block_sub', 'resourceTypes': ['sub_frame']}, - 'action': {'type': 'block'} + id: 2, + priority: 1, + condition: + {urlFilter: 'block_sub', resourceTypes: ['sub_frame']}, + action: {type: 'block'} }, { - 'id': 3, - 'priority': 1, - 'condition': - {'urlFilter': 'block_image', 'resourceTypes': ['image']}, - 'action': {'type': 'block'} + id: 3, + priority: 1, + condition: + {urlFilter: 'block_image', resourceTypes: ['image']}, + action: {type: 'block'} } ] },
diff --git a/chrome/test/data/extensions/api_test/declarative_net_request/update_static_rules/background.js b/chrome/test/data/extensions/api_test/declarative_net_request/update_static_rules/background.js index c4ce52e..385889fd 100644 --- a/chrome/test/data/extensions/api_test/declarative_net_request/update_static_rules/background.js +++ b/chrome/test/data/extensions/api_test/declarative_net_request/update_static_rules/background.js
@@ -54,8 +54,8 @@ chrome.test.assertEq(['rules1-1', 'rules1-2', 'rules1-3', 'rules2-1', 'rules2-2', 'rules2-3'], await getActiveRules()); - chrome.test.assertEq([], await getDisabledRuleIds("rules1")); - chrome.test.assertEq([], await getDisabledRuleIds("rules2")); + chrome.test.assertEq([], await getDisabledRuleIds('rules1')); + chrome.test.assertEq([], await getDisabledRuleIds('rules2')); chrome.test.succeed(); }, async function disableRuleset1Rules() { @@ -64,8 +64,8 @@ chrome.test.assertEq(['rules1-1', 'rules2-1', 'rules2-2', 'rules2-3'], await getActiveRules()); - chrome.test.assertEq([2, 3], await getDisabledRuleIds("rules1")); - chrome.test.assertEq([], await getDisabledRuleIds("rules2")); + chrome.test.assertEq([2, 3], await getDisabledRuleIds('rules1')); + chrome.test.assertEq([], await getDisabledRuleIds('rules2')); chrome.test.succeed(); }, async function disableRulesets() { @@ -75,8 +75,8 @@ {disableRulesetIds: ['rules1', 'rules2']}); chrome.test.assertEq([], await getActiveRules()); - chrome.test.assertEq([2, 3], await getDisabledRuleIds("rules1")); - chrome.test.assertEq([], await getDisabledRuleIds("rules2")); + chrome.test.assertEq([2, 3], await getDisabledRuleIds('rules1')); + chrome.test.assertEq([], await getDisabledRuleIds('rules2')); chrome.test.succeed(); }, async function enableRuleset1Rule() { @@ -85,8 +85,8 @@ await updateStaticRules({rulesetId: 'rules1', enableRuleIds: [3]}); chrome.test.assertEq([], await getActiveRules()); - chrome.test.assertEq([2], await getDisabledRuleIds("rules1")); - chrome.test.assertEq([], await getDisabledRuleIds("rules2")); + chrome.test.assertEq([2], await getDisabledRuleIds('rules1')); + chrome.test.assertEq([], await getDisabledRuleIds('rules2')); chrome.test.succeed(); }, async function disableRuleset2Rules() { @@ -95,8 +95,8 @@ await updateStaticRules({rulesetId: 'rules2', disableRuleIds: [2, 3]}); chrome.test.assertEq([], await getActiveRules()); - chrome.test.assertEq([2], await getDisabledRuleIds("rules1")); - chrome.test.assertEq([2, 3], await getDisabledRuleIds("rules2")); + chrome.test.assertEq([2], await getDisabledRuleIds('rules1')); + chrome.test.assertEq([2, 3], await getDisabledRuleIds('rules2')); chrome.test.succeed(); }, async function enableRulesetsAgain() { @@ -107,8 +107,8 @@ chrome.test.assertEq(['rules1-1', 'rules1-3', 'rules2-1'], await getActiveRules()); - chrome.test.assertEq([2], await getDisabledRuleIds("rules1")); - chrome.test.assertEq([2, 3], await getDisabledRuleIds("rules2")); + chrome.test.assertEq([2], await getDisabledRuleIds('rules1')); + chrome.test.assertEq([2, 3], await getDisabledRuleIds('rules2')); chrome.test.succeed(); }, async function enableRuleset2Rule() { @@ -117,8 +117,8 @@ chrome.test.assertEq(['rules1-1', 'rules1-3', 'rules2-1', 'rules2-2'], await getActiveRules()); - chrome.test.assertEq([2], await getDisabledRuleIds("rules1")); - chrome.test.assertEq([3], await getDisabledRuleIds("rules2")); + chrome.test.assertEq([2], await getDisabledRuleIds('rules1')); + chrome.test.assertEq([3], await getDisabledRuleIds('rules2')); chrome.test.succeed(); }, async function disableInvalidRulesetRules() { @@ -128,8 +128,8 @@ chrome.test.assertEq(['rules1-1', 'rules1-3', 'rules2-1', 'rules2-2'], await getActiveRules()); - chrome.test.assertEq([2], await getDisabledRuleIds("rules1")); - chrome.test.assertEq([3], await getDisabledRuleIds("rules2")); + chrome.test.assertEq([2], await getDisabledRuleIds('rules1')); + chrome.test.assertEq([3], await getDisabledRuleIds('rules2')); chrome.test.succeed(); }, async function disableRulesetRulesExceedingLimits() { @@ -142,8 +142,8 @@ chrome.test.assertEq(['rules1-1', 'rules1-3', 'rules2-1', 'rules2-2'], await getActiveRules()); - chrome.test.assertEq([2], await getDisabledRuleIds("rules1")); - chrome.test.assertEq([3], await getDisabledRuleIds("rules2")); + chrome.test.assertEq([2], await getDisabledRuleIds('rules1')); + chrome.test.assertEq([3], await getDisabledRuleIds('rules2')); chrome.test.succeed(); }, async function updateStaticRulesWithEmptyList() { @@ -153,13 +153,13 @@ chrome.test.assertEq(['rules1-1', 'rules1-3', 'rules2-1', 'rules2-2'], await getActiveRules()); - chrome.test.assertEq([2], await getDisabledRuleIds("rules1")); - chrome.test.assertEq([3], await getDisabledRuleIds("rules2")); + chrome.test.assertEq([2], await getDisabledRuleIds('rules1')); + chrome.test.assertEq([3], await getDisabledRuleIds('rules2')); chrome.test.succeed(); }, async function getDisabledRuleIdsErrorForInvalidRuleset() { await verifyGetDisabledRuleIdsError( - "invalid_rules", "Error: Invalid ruleset id: invalid_rules."); + 'invalid_rules', 'Error: Invalid ruleset id: invalid_rules.'); chrome.test.succeed(); }, ]);
diff --git a/chrome/test/data/extensions/api_test/developer/packaged_app/main.js b/chrome/test/data/extensions/api_test/developer/packaged_app/main.js index e42517ee..6b78cf7 100644 --- a/chrome/test/data/extensions/api_test/developer/packaged_app/main.js +++ b/chrome/test/data/extensions/api_test/developer/packaged_app/main.js
@@ -2,11 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -chrome.test.sendMessage("app_launched"); +chrome.test.sendMessage('app_launched'); chrome.app.runtime.onLaunched.addListener(function() { chrome.app.window.create('main.html', { - 'width': 600, - 'height': 600 + width: 600, + height: 600 }); });
diff --git a/chrome/test/data/extensions/api_test/document_scan/perform_scan.js b/chrome/test/data/extensions/api_test/document_scan/perform_scan.js index 2483cad..a892c04 100644 --- a/chrome/test/data/extensions/api_test/document_scan/perform_scan.js +++ b/chrome/test/data/extensions/api_test/document_scan/perform_scan.js
@@ -10,7 +10,6 @@ local: true, secure: true, }; - var savedId; chrome.documentScan.getScannerList(filter, response => { chrome.test.assertEq(OperationResult.SUCCESS, response.result); chrome.test.assertEq(1, response.scanners.length);
diff --git a/chrome/test/data/extensions/api_test/document_scan/scan_utils.js b/chrome/test/data/extensions/api_test/document_scan/scan_utils.js index 7bedb93..80c4bff 100644 --- a/chrome/test/data/extensions/api_test/document_scan/scan_utils.js +++ b/chrome/test/data/extensions/api_test/document_scan/scan_utils.js
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -OperationResult = chrome.documentScan.OperationResult; -OptionType = chrome.documentScan.OptionType; +const OperationResult = chrome.documentScan.OperationResult; +const OptionType = chrome.documentScan.OptionType; async function getScannerList(filter) { return new Promise(resolve => { @@ -60,7 +60,7 @@ format: 'format', }; if (maxReadSize != undefined) { - options['maxReadSize'] = maxReadSize; + options.maxReadSize = maxReadSize; } chrome.documentScan.startScan(scannerHandle, options, resolve); });
diff --git a/chrome/test/data/extensions/api_test/gcm/events/on_message.js b/chrome/test/data/extensions/api_test/gcm/events/on_message.js index cff5f35..d4142b4 100644 --- a/chrome/test/data/extensions/api_test/gcm/events/on_message.js +++ b/chrome/test/data/extensions/api_test/gcm/events/on_message.js
@@ -5,14 +5,14 @@ onload = function() { chrome.test.runTests([ function onMessage() { - var expectedCalls = 4; - var fromAndCollapseKeyTested = false; - var fromTested = false; - var collapseKeyTested = false; - var regularMessageTested = false; - var eventHandler = function(message) { - var hasFrom = false; - var hasCollapseKey = false; + let expectedCalls = 4; + let fromAndCollapseKeyTested = false; + let fromTested = false; + let collapseKeyTested = false; + let regularMessageTested = false; + const eventHandler = function(message) { + let hasFrom = false; + let hasCollapseKey = false; if (message.hasOwnProperty('from')) { // Test with from. chrome.test.assertEq('12345678', message.from);
diff --git a/chrome/test/data/extensions/api_test/gcm/events/on_send_error.js b/chrome/test/data/extensions/api_test/gcm/events/on_send_error.js index 208a3239..21350ea 100644 --- a/chrome/test/data/extensions/api_test/gcm/events/on_send_error.js +++ b/chrome/test/data/extensions/api_test/gcm/events/on_send_error.js
@@ -5,19 +5,19 @@ onload = function() { chrome.test.runTests([ function onSendError() { - var currentError = 0; - var totalMessages = 0; - var eventHandler = function(error) { + let currentError = 0; + let totalMessages = 0; + const eventHandler = function(error) { chrome.test.assertEq(3, Object.keys(error.details).length); chrome.test.assertTrue( - error.details.hasOwnProperty("expectedMessageId")); + error.details.hasOwnProperty('expectedMessageId')); chrome.test.assertTrue( - error.details.hasOwnProperty("expectedErrorMessage")); + error.details.hasOwnProperty('expectedErrorMessage')); chrome.test.assertEq(error.details.expectedMessageId, error.messageId); chrome.test.assertEq(error.details.expectedErrorMessage, error.errorMessage); currentError += 1; - var tempTotalMessages = +error.details.totalMessages; + const tempTotalMessages = +error.details.totalMessages; if (totalMessages == 0) totalMessages = tempTotalMessages; else
diff --git a/chrome/test/data/extensions/api_test/gcm/functions/incognito/test.js b/chrome/test/data/extensions/api_test/gcm/functions/incognito/test.js index e65dd6b..7839135 100644 --- a/chrome/test/data/extensions/api_test/gcm/functions/incognito/test.js +++ b/chrome/test/data/extensions/api_test/gcm/functions/incognito/test.js
@@ -4,7 +4,7 @@ chrome.test.runTests([ function testIncognito() { - chrome.gcm.register(["Sender"], function(registrationId) { + chrome.gcm.register(['Sender'], function(registrationId) { chrome.test.assertEq(chrome.runtime.lastError != undefined, chrome.extension.inIncognitoContext); chrome.test.succeed();
diff --git a/chrome/test/data/extensions/api_test/gcm/functions/register/register.js b/chrome/test/data/extensions/api_test/gcm/functions/register/register.js index 020831d..76b2acc 100644 --- a/chrome/test/data/extensions/api_test/gcm/functions/register/register.js +++ b/chrome/test/data/extensions/api_test/gcm/functions/register/register.js
@@ -4,7 +4,7 @@ chrome.test.runTests([ function testRegister() { - var senderIds = ["Sender1", "Sender2"]; + const senderIds = ['Sender1', 'Sender2']; chrome.gcm.register(senderIds, function(registrationId) { chrome.test.succeed(); });
diff --git a/chrome/test/data/extensions/api_test/gcm/functions/register_validation/register_validation.js b/chrome/test/data/extensions/api_test/gcm/functions/register_validation/register_validation.js index 0f62922..4f5420e 100644 --- a/chrome/test/data/extensions/api_test/gcm/functions/register_validation/register_validation.js +++ b/chrome/test/data/extensions/api_test/gcm/functions/register_validation/register_validation.js
@@ -3,29 +3,29 @@ // found in the LICENSE file. function generateSenderIds(size) { - var senders = []; - for (var i = 0; i < size; i++) { - senders.push("Sender" + i); + const senders = []; + for (let i = 0; i < size; i++) { + senders.push('Sender' + i); } return senders; } function toArrayDefinitionString(senderIds) { - var idsString = "["; + let idsString = '['; senderIds.forEach(function(element, index) { - if (index > 0) idsString += ", "; - idsString += "\"" + element + "\""; + if (index > 0) idsString += ', '; + idsString += `"${element}"`; }); - idsString += "]"; + idsString += ']'; return idsString; } -var registrationCount = 0; +let registrationCount = 0; function registerSuccessfully(senderIds) { chrome.gcm.register(senderIds, function(registrationId) { - var expectedRegistrationId = senderIds.length + "-" + (registrationCount++); - chrome.test.assertEq("" + expectedRegistrationId, registrationId); + const expectedRegistrationId = `${senderIds.length}-${registrationCount++}`; + chrome.test.assertEq(`${expectedRegistrationId}`, registrationId); chrome.test.succeed(); }); } @@ -33,7 +33,7 @@ function registerInvalidParameters(senderIds) { try { chrome.gcm.register(senderIds, function(registrationId) { - chrome.test.fail("Arguments: " + toArrayDefinitionString(senderIds)); + chrome.test.fail(`Arguments: ${toArrayDefinitionString(senderIds)}`); }); } catch (e) { chrome.test.succeed(); @@ -54,10 +54,10 @@ registerInvalidParameters([]); }, function failureWithEmptySenderOnly() { - registerInvalidParameters([""]); + registerInvalidParameters(['']); }, function failureWithEmptySender() { - registerInvalidParameters(["good", ""]); + registerInvalidParameters(['good', '']); }, function failureWithTooManySenders() { registerInvalidParameters(generateSenderIds(101));
diff --git a/chrome/test/data/extensions/api_test/gcm/functions/send/send.js b/chrome/test/data/extensions/api_test/gcm/functions/send/send.js index 7e477ff..543d60e 100644 --- a/chrome/test/data/extensions/api_test/gcm/functions/send/send.js +++ b/chrome/test/data/extensions/api_test/gcm/functions/send/send.js
@@ -4,12 +4,12 @@ function createMessage() { return { - messageId: "message-id", - destinationId: "destination-id", + messageId: 'message-id', + destinationId: 'destination-id', timeToLive: 86400, data: { - "key1": "value1", - "key2": "value" + key1: 'value1', + key2: 'value' } }; } @@ -32,7 +32,7 @@ } function scenario(messageMutations, send) { - var message = createMessage(); + const message = createMessage(); messageMutations.forEach(function(mutation) { mutation(message); }); @@ -67,13 +67,13 @@ expectFailureWhen(function(message) { delete message.messageId; }); }, function failureWhenMessageIdIsEmpty() { - expectFailureWhen(function(message) { message.messageId = ""; }); + expectFailureWhen(function(message) { message.messageId = ''; }); }, function failureWhenDestinationIdMissing() { expectFailureWhen(function(message) { delete message.destinationId; }); }, function failureWhenDestinationIdIsEmpty() { - expectFailureWhen(function(message) { message.destinationId = ""; }); + expectFailureWhen(function(message) { message.destinationId = ''; }); }, function failureWhenDataIsMissing() { expectFailureWhen(function(message) { delete message.data; }); @@ -82,49 +82,49 @@ expectFailureWhen(function(message) { message.data = {}; }); }, function failureWhenDataKeyIsEmpty() { - expectFailureWhen(function(message) { message.data[""] = "value"; }); + expectFailureWhen(function(message) { message.data[''] = 'value'; }); }, function successWhenDataKeyHasGoogDotInIt() { expectSuccessWhen(function(message) { - message.data["something.goog."] = "value"; + message.data['something.goog.'] = 'value'; }); }, function failureWhenDataKeyIsGoogDot() { - expectFailureWhen(function(message) { message.data["goog."] = "value"; }); + expectFailureWhen(function(message) { message.data['goog.'] = 'value'; }); }, function failureWhenDataKeyIsGoogDotPrefixed() { expectFailureWhen(function(message) { - message.data["goog.something"] = "value"; + message.data['goog.something'] = 'value'; }); }, function failureWhenDataKeyIsGoogDotMixedCasedPrefixed() { expectFailureWhen(function(message) { - message.data["GoOg.something"] = "value"; + message.data['GoOg.something'] = 'value'; }); }, function successWhenDataKeyHasGoogleInIt() { expectSuccessWhen(function(message) { - message.data["somthing.google"] = "value"; + message.data['somthing.google'] = 'value'; }); }, function failureWhenDataKeyIsGoogle() { expectFailureWhen(function(message) { - message.data["google"] = "value"; + message.data['google'] = 'value'; }); }, function failureWhenDataKeyIsMixedCasedGoogle() { expectFailureWhen(function(message) { - message.data["GoOgLe"] = "value"; + message.data['GoOgLe'] = 'value'; }); }, function failureWhenDataKeyIsGooglePrefixed() { expectFailureWhen(function(message) { - message.data["googleSomething"] = "value"; + message.data['googleSomething'] = 'value'; }); }, function failureWhenDataKeyIsCollapeKey() { expectFailureWhen(function(message) { - message.data["collapse_key"] = "value"; + message.data['collapse_key'] = 'value'; }); }, function failureWhenMessageIsTooLarge() { @@ -136,12 +136,12 @@ return base.substring(0, len); } - var source = "abcdefghijklmnopqrstuvwxyz"; + const source = 'abcdefghijklmnopqrstuvwxyz'; // Creates 8 * (256 + 256) == 4096 bytes of message data which together // with data put in by default is more than allowed max. - var entries = 8; + let entries = 8; while (entries > 0) { - var s = generateString(source + entries, 256); + const s = generateString(source + entries, 256); message.data[s] = s; --entries; }
diff --git a/chrome/test/data/extensions/api_test/gcm/functions/send_message_data/send_message_data.js b/chrome/test/data/extensions/api_test/gcm/functions/send_message_data/send_message_data.js index ef190fa..42ff814 100644 --- a/chrome/test/data/extensions/api_test/gcm/functions/send_message_data/send_message_data.js +++ b/chrome/test/data/extensions/api_test/gcm/functions/send_message_data/send_message_data.js
@@ -2,19 +2,19 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -var message = { - messageId: "message-id", - destinationId: "destination-id", +const MESSAGE = { + messageId: 'message-id', + destinationId: 'destination-id', timeToLive: 100, data: { - "key1": "value1", - "key2": "value2" + key1: 'value1', + key2: 'value2' } }; chrome.test.runTests([ function testSend() { - chrome.gcm.send(message, function(messageId) { + chrome.gcm.send(MESSAGE, function(messageId) { chrome.test.succeed(); }); }
diff --git a/chrome/test/data/extensions/api_test/gcm/functions/send_message_default_ttl/send_message_default_ttl.js b/chrome/test/data/extensions/api_test/gcm/functions/send_message_default_ttl/send_message_default_ttl.js index 1025a0e..c3335e4 100644 --- a/chrome/test/data/extensions/api_test/gcm/functions/send_message_default_ttl/send_message_default_ttl.js +++ b/chrome/test/data/extensions/api_test/gcm/functions/send_message_default_ttl/send_message_default_ttl.js
@@ -2,18 +2,18 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -var message = { - messageId: "message-id", - destinationId: "destination-id", +const MESSAGE = { + messageId: 'message-id', + destinationId: 'destination-id', data: { - "key1": "value1", - "key2": "value2" + key1: 'value1', + key2: 'value2' } }; chrome.test.runTests([ function testSend() { - chrome.gcm.send(message, function(messageId) { + chrome.gcm.send(MESSAGE, function(messageId) { chrome.test.succeed(); }); }
diff --git a/chrome/test/data/extensions/api_test/gcm/functions/unregister/unregister.js b/chrome/test/data/extensions/api_test/gcm/functions/unregister/unregister.js index e140e9d..cb98f0e 100644 --- a/chrome/test/data/extensions/api_test/gcm/functions/unregister/unregister.js +++ b/chrome/test/data/extensions/api_test/gcm/functions/unregister/unregister.js
@@ -4,7 +4,7 @@ chrome.test.runTests([ function testUnregister() { - var senderIds = ["Sender1", "Sender2"]; + const senderIds = ['Sender1', 'Sender2']; chrome.gcm.register(senderIds, function(registrationId) { if (chrome.runtime.lastError) chrome.test.fail(); @@ -19,7 +19,7 @@ function testUnregisterWithServerError() { chrome.gcm.unregister(function() { if (chrome.runtime.lastError != undefined && - chrome.runtime.lastError.message == "Server error occurred.") { + chrome.runtime.lastError.message == 'Server error occurred.') { chrome.test.succeed(); } else { chrome.test.fail();
diff --git a/chrome/test/data/extensions/api_test/metrics/test.js b/chrome/test/data/extensions/api_test/metrics/test.js index e602bbab..115a6c1 100644 --- a/chrome/test/data/extensions/api_test/metrics/test.js +++ b/chrome/test/data/extensions/api_test/metrics/test.js
@@ -41,21 +41,25 @@ }, function recordValue() { - chrome.metricsPrivate.recordValue({ - 'metricName': 'test.h.1', - 'type': chrome.metricsPrivate.MetricTypeType.HISTOGRAM_LOG, - 'min': 1, - 'max': 100, - 'buckets': 50 - }, 42); + chrome.metricsPrivate.recordValue( + { + metricName: 'test.h.1', + type: chrome.metricsPrivate.MetricTypeType.HISTOGRAM_LOG, + min: 1, + max: 100, + buckets: 50 + }, + 42); - chrome.metricsPrivate.recordValue({ - 'metricName': 'test.h.2', - 'type': chrome.metricsPrivate.MetricTypeType.HISTOGRAM_LINEAR, - 'min': 1, - 'max': 200, - 'buckets': 50 - }, 42); + chrome.metricsPrivate.recordValue( + { + metricName: 'test.h.2', + type: chrome.metricsPrivate.MetricTypeType.HISTOGRAM_LINEAR, + min: 1, + max: 200, + buckets: 50 + }, + 42); chrome.metricsPrivate.recordPercentage('test.h.3', 42); chrome.metricsPrivate.recordPercentage('test.h.3', 42); @@ -94,12 +98,12 @@ }, function getFieldTrial() { - var test1Callback = function(group) { + const test1Callback = function(group) { chrome.test.assertEq('', group); chrome.metricsPrivate.getFieldTrial('apitestfieldtrial2', test2Callback); }; - var test2Callback = function(group) { + const test2Callback = function(group) { chrome.test.assertEq('group1', group); chrome.test.succeed(); }; @@ -126,33 +130,33 @@ }, function testBucketSizeChanges() { - var linear1 = { - 'metricName': 'test.bucketchange.linear', - 'type': chrome.metricsPrivate.MetricTypeType.HISTOGRAM_LINEAR, - 'min': 0, - 'max': 100, - 'buckets': 10 + const linear1 = { + metricName: 'test.bucketchange.linear', + type: chrome.metricsPrivate.MetricTypeType.HISTOGRAM_LINEAR, + min: 0, + max: 100, + buckets: 10 }; - var linear2 = { - 'metricName': 'test.bucketchange.linear', - 'type': chrome.metricsPrivate.MetricTypeType.HISTOGRAM_LINEAR, - 'min': 0, - 'max': 100, - 'buckets': 20 + const linear2 = { + metricName: 'test.bucketchange.linear', + type: chrome.metricsPrivate.MetricTypeType.HISTOGRAM_LINEAR, + min: 0, + max: 100, + buckets: 20 }; - var log1 = { - 'metricName': 'test.bucketchange.log', - 'type': chrome.metricsPrivate.MetricTypeType.HISTOGRAM_LOG, - 'min': 0, - 'max': 100, - 'buckets': 10 + const log1 = { + metricName: 'test.bucketchange.log', + type: chrome.metricsPrivate.MetricTypeType.HISTOGRAM_LOG, + min: 0, + max: 100, + buckets: 10 }; - var log2 = { - 'metricName': 'test.bucketchange.log', - 'type': chrome.metricsPrivate.MetricTypeType.HISTOGRAM_LOG, - 'min': 0, - 'max': 100, - 'buckets': 20 + const log2 = { + metricName: 'test.bucketchange.log', + type: chrome.metricsPrivate.MetricTypeType.HISTOGRAM_LOG, + min: 0, + max: 100, + buckets: 20 }; chrome.metricsPrivate.recordValue(linear1, 42);
diff --git a/chrome/test/data/extensions/api_test/native_messaging/test.js b/chrome/test/data/extensions/api_test/native_messaging/test.js index 4b193651..af166ce 100644 --- a/chrome/test/data/extensions/api_test/native_messaging/test.js +++ b/chrome/test/data/extensions/api_test/native_messaging/test.js
@@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -var appName = 'com.google.chrome.test.echo'; -var inServiceWorker = 'ServiceWorkerGlobalScope' in self; -var extensionUrl = chrome.runtime.getURL('/'); +const APP_NAME = 'com.google.chrome.test.echo'; +const inServiceWorker = 'ServiceWorkerGlobalScope' in self; +const extensionUrl = chrome.runtime.getURL('/'); function checkMessageUrl(url) { if (inServiceWorker) { @@ -17,7 +17,7 @@ chrome.test.getConfig(function(config) { chrome.test.runTests([ function invalidHostName() { - var message = {'text': 'Hello!'}; + const message = {text: 'Hello!'}; chrome.runtime.sendNativeMessage( 'not.installed.app', message, chrome.test.callbackFail( @@ -27,7 +27,7 @@ }, function nonexistentHost() { - var message = {'text': 'Hello!'}; + const message = {text: 'Hello!'}; chrome.runtime.sendNativeMessage( 'com.google.chrome.test.host_binary_missing', message, chrome.test.callbackFail( @@ -37,9 +37,9 @@ }, function sendMessageWithCallback() { - var message = {'text': 'Hi there!', 'number': 3}; + const message = {text: 'Hi there!', number: 3}; chrome.runtime.sendNativeMessage( - appName, message, chrome.test.callbackPass(function(response) { + APP_NAME, message, chrome.test.callbackPass(function(response) { chrome.test.assertEq(1, response.id); chrome.test.assertEq(message, response.echo); checkMessageUrl(response.caller_url); @@ -48,17 +48,17 @@ // The goal of this test is just not to crash. function sendMessageWithoutCallback() { - var message = {'text': 'Hi there!', 'number': 3}; - chrome.runtime.sendNativeMessage(appName, message); + const message = {text: 'Hi there!', number: 3}; + chrome.runtime.sendNativeMessage(APP_NAME, message); chrome.test.succeed(); // Mission Complete }, function bigMessage() { // Create a special message for which the test host must try sending a // message that is bigger than the limit. - var message = {'bigMessageTest': true}; + const message = {bigMessageTest: true}; chrome.runtime.sendNativeMessage( - appName, message, + APP_NAME, message, chrome.test.callbackFail( 'Error when communicating with the native messaging host.', function(response) { @@ -68,9 +68,9 @@ function invalidMessage() { // Create a special message that's not valid JSON. - var message = {sendInvalidResponse: true}; + const message = {sendInvalidResponse: true}; chrome.runtime.sendNativeMessage( - appName, message, + APP_NAME, message, chrome.test.callbackFail( 'The sender sent an invalid JSON message; message ignored.', function(response) {
diff --git a/chrome/test/data/extensions/api_test/native_messaging_connect/test.js b/chrome/test/data/extensions/api_test/native_messaging_connect/test.js index 7124469f..e9e42ea 100644 --- a/chrome/test/data/extensions/api_test/native_messaging_connect/test.js +++ b/chrome/test/data/extensions/api_test/native_messaging_connect/test.js
@@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -var appName = 'com.google.chrome.test.echo'; -var inServiceWorker = 'ServiceWorkerGlobalScope' in self; -var extensionUrl = chrome.runtime.getURL('/'); +const APP_NAME = 'com.google.chrome.test.echo'; +const inServiceWorker = 'ServiceWorkerGlobalScope' in self; +const extensionUrl = chrome.runtime.getURL('/'); function checkMessageUrl(url) { if (inServiceWorker) { @@ -17,11 +17,11 @@ chrome.test.getConfig(function(config) { chrome.test.runTests([ function connect() { - var messagesToSend = + const messagesToSend = [{'text': 'foo'}, {'text': 'bar', 'funCount': 9001}, {}]; - var currentMessage = 0; + let currentMessage = 0; - port = chrome.runtime.connectNative(appName); + const port = chrome.runtime.connectNative(APP_NAME); port.postMessage(messagesToSend[currentMessage]); port.onMessage.addListener(function(message) { @@ -40,7 +40,7 @@ // Verify that the case when host stops itself is handled properly. function stopHost() { - port = chrome.runtime.connectNative(appName); + const port = chrome.runtime.connectNative(APP_NAME); port.onDisconnect.addListener( chrome.test.callback(function() {}, 'Native host has exited.'));
diff --git a/chrome/test/data/extensions/api_test/native_messaging_launch/test.js b/chrome/test/data/extensions/api_test/native_messaging_launch/test.js index 7988554..31b26e5 100644 --- a/chrome/test/data/extensions/api_test/native_messaging_launch/test.js +++ b/chrome/test/data/extensions/api_test/native_messaging_launch/test.js
@@ -2,20 +2,20 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -var appName = 'com.google.chrome.test.inbound_native_echo'; +const APP_NAME = 'com.google.chrome.test.inbound_native_echo'; chrome.runtime.onConnectNative.addListener(port => { chrome.test.getConfig(function(config) { chrome.test.runTests([ function sender() { - chrome.test.assertEq(port.sender.nativeApplication, appName); + chrome.test.assertEq(port.sender.nativeApplication, APP_NAME); chrome.test.succeed(); }, function sendMessages() { - var messagesToSend = + const messagesToSend = [{'text': 'foo'}, {'text': 'bar', 'funCount': 9001}, {}]; - var currentMessage = 0; + let currentMessage = 0; port.postMessage(messagesToSend[currentMessage]); @@ -23,14 +23,14 @@ chrome.test.assertEq(currentMessage + 1, message.id); chrome.test.assertEq(messagesToSend[currentMessage], message.echo); chrome.test.assertEq( - message.caller_url, window.location.origin + '/'); + message.caller_url, `${window.location.origin}/`); chrome.test.assertTrue(!!message.args); chrome.test.assertTrue(message.args.includes( - '--native-messaging-connect-extension=' + - document.location.host)); + `--native-messaging-connect-extension=${ + document.location.host}`)); chrome.test.assertTrue(message.args.includes( - '--native-messaging-connect-host=' + appName)); + `--native-messaging-connect-host=${APP_NAME}`)); chrome.test.assertEq('test-connect-id', message.connect_id); currentMessage++;
diff --git a/chrome/test/data/extensions/api_test/native_messaging_launch_unsupported/test.js b/chrome/test/data/extensions/api_test/native_messaging_launch_unsupported/test.js index cbc9e30d..1eaf470 100644 --- a/chrome/test/data/extensions/api_test/native_messaging_launch_unsupported/test.js +++ b/chrome/test/data/extensions/api_test/native_messaging_launch_unsupported/test.js
@@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -var appName = 'com.google.chrome.test.echo'; +const APP_NAME = 'com.google.chrome.test.echo'; chrome.runtime.onConnectNative.addListener(port => { chrome.test.runTests([ function test() { - chrome.test.assertEq(port.sender.nativeApplication, appName); + chrome.test.assertEq(port.sender.nativeApplication, APP_NAME); port.onDisconnect.addListener(chrome.test.callback( function() {}, 'Access to the specified native messaging host is forbidden.'));
diff --git a/chrome/test/data/extensions/api_test/native_messaging_send_native_message/test.js b/chrome/test/data/extensions/api_test/native_messaging_send_native_message/test.js index 8e2a1d8..dad068c3 100644 --- a/chrome/test/data/extensions/api_test/native_messaging_send_native_message/test.js +++ b/chrome/test/data/extensions/api_test/native_messaging_send_native_message/test.js
@@ -5,62 +5,63 @@ // Most of this file is copy-pasted from /api_test/native_messaging/lazy/test.js // and then adapted to use MV3 and test promises. -var appName = 'com.google.chrome.test.echo'; -var extensionUrl = chrome.runtime.getURL('/'); -var hostNotFoundError = 'Specified native messaging host not found.'; +const APP_NAME = 'com.google.chrome.test.echo'; +const extensionUrl = chrome.runtime.getURL('/'); +const HOST_NOT_FOUND_ERROR = 'Specified native messaging host not found.'; chrome.test.getConfig(function(config) { chrome.test.runTests([ // Tests calling with an app name that is not installed. function invalidHostNameCallback() { - var message = {text: 'Hello!'}; + const message = {text: 'Hello!'}; chrome.runtime.sendNativeMessage( 'not.installed.app', message, - chrome.test.callbackFail(hostNotFoundError, function(response) { + chrome.test.callbackFail(HOST_NOT_FOUND_ERROR, function(response) { chrome.test.assertEq(undefined, response); })); }, async function invalidHostNamePromise() { - var message = {test: 'Hello there!'}; + const message = {test: 'Hello there!'}; await chrome.test.assertPromiseRejects( chrome.runtime.sendNativeMessage('not.installed.app', message), - 'Error: ' + hostNotFoundError); + 'Error: ' + HOST_NOT_FOUND_ERROR); chrome.test.succeed(); }, // Tests calling with an app name that has a manifest, but no binary behind // it. See native_messaging_test_util for for information. function nonexistentHostCallback() { - var message = {text: 'Hello!'}; + const message = {text: 'Hello!'}; chrome.runtime.sendNativeMessage( 'com.google.chrome.test.host_binary_missing', message, - chrome.test.callbackFail(hostNotFoundError, function(response) { + chrome.test.callbackFail(HOST_NOT_FOUND_ERROR, function(response) { chrome.test.assertEq(undefined, response); })); }, async function nonexistentHostPromise() { - var message = {text: 'Hello!'}; + const message = {text: 'Hello!'}; await chrome.test.assertPromiseRejects( chrome.runtime.sendNativeMessage( 'com.google.chrome.test.host_binary_missing', message), - 'Error: ' + hostNotFoundError); + 'Error: ' + HOST_NOT_FOUND_ERROR); chrome.test.succeed(); }, // Tests a successful call to an app that does exist and responds with an // echo. See native_messaging_test_util for for information. function sendMessageWithCallback() { - var message = {text: 'Hi there!', number: 3}; + const message = {text: 'Hi there!', number: 3}; chrome.runtime.sendNativeMessage( - appName, message, chrome.test.callbackPass(function(response) { + APP_NAME, message, chrome.test.callbackPass(function(response) { chrome.test.assertEq(1, response.id); chrome.test.assertEq(message, response.echo); chrome.test.assertEq(extensionUrl, response.caller_url); })); }, async function sendMessageWithPromise() { - var message = {text: 'Hi there!', number: 3}; - const response = await chrome.runtime.sendNativeMessage(appName, message); + const message = {text: 'Hi there!', number: 3}; + const response = + await chrome.runtime.sendNativeMessage(APP_NAME, message); chrome.test.assertEq(1, response.id); chrome.test.assertEq(message, response.echo); chrome.test.assertEq(extensionUrl, response.caller_url); @@ -70,9 +71,9 @@ // Creates a special message for which the test host must try sending a // message that is bigger than the limit. function bigMessageCallback() { - var message = {bigMessageTest: true}; + const message = {bigMessageTest: true}; chrome.runtime.sendNativeMessage( - appName, message, + APP_NAME, message, chrome.test.callbackFail( 'Error when communicating with the native messaging host.', function(response) { @@ -80,9 +81,9 @@ })); }, async function bigMessagePromise() { - var message = {bigMessageTest: true}; + const message = {bigMessageTest: true}; await chrome.test.assertPromiseRejects( - chrome.runtime.sendNativeMessage(appName, message), + chrome.runtime.sendNativeMessage(APP_NAME, message), 'Error: Error when communicating with the native messaging host.'); chrome.test.succeed(); }
diff --git a/chrome/test/data/extensions/api_test/native_messaging_send_native_message_exe/test.js b/chrome/test/data/extensions/api_test/native_messaging_send_native_message_exe/test.js index e61a66669..6cde3040 100644 --- a/chrome/test/data/extensions/api_test/native_messaging_send_native_message_exe/test.js +++ b/chrome/test/data/extensions/api_test/native_messaging_send_native_message_exe/test.js
@@ -2,24 +2,25 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -var appName = 'com.google.chrome.test.exe.echo'; +const APP_NAME = 'com.google.chrome.test.exe.echo'; chrome.test.getConfig(function(config) { chrome.test.runTests([ function sendMessageWithCallback() { - var message = {echo: 'TryCallback', id: 1}; + const message = {echo: 'TryCallback', id: 1}; chrome.runtime.sendNativeMessage( - appName, message, chrome.test.callbackPass(function(response) { + APP_NAME, message, chrome.test.callbackPass(function(response) { chrome.test.assertEq(1, response.id); chrome.test.assertEq('TryCallback', response.echo); })); }, async function sendMessageWithPromise() { - var message = {echo: 'TryPromise', id: 2}; - const response = await chrome.runtime.sendNativeMessage(appName, message); + const message = {echo: 'TryPromise', id: 2}; + const response = + await chrome.runtime.sendNativeMessage(APP_NAME, message); chrome.test.assertEq(2, response.id); chrome.test.assertEq('TryPromise', response.echo); chrome.test.succeed(); }, ]); -}); \ No newline at end of file +});
diff --git a/chrome/test/data/extensions/api_test/networking_private/alias/test.js b/chrome/test/data/extensions/api_test/networking_private/alias/test.js index 4816a56..d93f56e7 100644 --- a/chrome/test/data/extensions/api_test/networking_private/alias/test.js +++ b/chrome/test/data/extensions/api_test/networking_private/alias/test.js
@@ -42,7 +42,7 @@ }, // ENS, ICCID, IMEI, MDN, MEID, and MIN are filtered for // networkingOnc. - ModelID:"test_model_id", + ModelID:'test_model_id', NetworkTechnology: 'GSM', RoamingState: 'Home', SIMLockStatus: { @@ -85,7 +85,7 @@ })); }, function verifyNoAccessToNetworkingPrivateOnlyMethods() { - var expectedError = 'Requires networkingPrivate API access.'; + const expectedError = 'Requires networkingPrivate API access.'; chrome.networking.onc.getVisibleNetworks('All', chrome.test.callbackFail(expectedError)); chrome.networking.onc.getEnabledNetworkTypes(
diff --git a/chrome/test/data/extensions/api_test/networking_private/chromeos/test.js b/chrome/test/data/extensions/api_test/networking_private/chromeos/test.js index a5acb780..8c67e733 100644 --- a/chrome/test/data/extensions/api_test/networking_private/chromeos/test.js +++ b/chrome/test/data/extensions/api_test/networking_private/chromeos/test.js
@@ -5,21 +5,21 @@ // The expectations in this test for the Chrome OS implementation. See // networking_private_chromeos_apitest.cc for more info. -var callbackPass = chrome.test.callbackPass; -var callbackFail = chrome.test.callbackFail; -var assertTrue = chrome.test.assertTrue; -var assertFalse = chrome.test.assertFalse; -var assertEq = chrome.test.assertEq; +const callbackPass = chrome.test.callbackPass; +const callbackFail = chrome.test.callbackFail; +const assertTrue = chrome.test.assertTrue; +const assertFalse = chrome.test.assertFalse; +const assertEq = chrome.test.assertEq; -var ActivationStateType = chrome.networkingPrivate.ActivationStateType; -var ConnectionStateType = chrome.networkingPrivate.ConnectionStateType; -var NetworkType = chrome.networkingPrivate.NetworkType; +const ActivationStateType = chrome.networkingPrivate.ActivationStateType; +const ConnectionStateType = chrome.networkingPrivate.ConnectionStateType; +const NetworkType = chrome.networkingPrivate.NetworkType; -var kCellularGuid = 'stub_cellular1_guid'; -var kDefaultPin = '1111'; -var kDefaultPuk = '12345678'; +const CELLULAR_GUID = 'stub_cellular1_guid'; +const DEFAULT_PIN = '1111'; +const DEFAULT_PUK = '12345678'; -var privateHelpers = { +const privateHelpers = { // networkToExpectedStatesMap is a Map string (network GUID) -> array of // strings (expected states). // For each network specified there, watches for onNetworksChanged events with @@ -48,7 +48,7 @@ const expectedStates = networkToExpectedStatesMap.get(network); if (!expectedStates) { chrome.test.fail( - 'Unexpected state change for network ' + network + ' (' + +')'); + `Unexpected state change for network ${network}`); } if (expectedStates.length > 0) { const expectedState = expectedStates.pop(); @@ -100,7 +100,7 @@ }; }, watchForCaptivePortalState: function(expectedGuid, expectedState, done) { - var self = this; + const self = this; this.onPortalDetectionCompleted = function(guid, state) { assertEq(expectedGuid, guid); assertEq(expectedState, state); @@ -126,19 +126,19 @@ } }; -var kFailure = 'Failure'; +const FAILURE = 'Failure'; function networkCallbackPass() { - var callbackCompleted = chrome.test.callbackAdded(); + const callbackCompleted = chrome.test.callbackAdded(); return function(result) { chrome.test.assertNoLastError(); - if (result === false || result === kFailure) - chrome.test.fail('Failed: ' + result); + if (result === false || result === FAILURE) + chrome.test.fail(`Failed: ${result}`); callbackCompleted(); }; } -var availableTests = [ +const availableTests = [ function startConnect() { chrome.networkingPrivate.startConnect('stub_wifi2_guid', networkCallbackPass()); @@ -154,12 +154,12 @@ }, function startActivate() { chrome.networkingPrivate.startActivate( - kCellularGuid, callbackPass(function() { + CELLULAR_GUID, callbackPass(function() { // For non Sprint networks, startActivate will delegate // showing the activation UI to the browser host and not // immediately activate the network. chrome.networkingPrivate.getState( - kCellularGuid, callbackPass(function(state) { + CELLULAR_GUID, callbackPass(function(state) { assertEq(ActivationStateType.NOT_ACTIVATED, state.Cellular.ActivationState); })); @@ -223,30 +223,30 @@ })); }, function forgetNetwork() { - var kNumNetworks = 2; - var kTestNetworkGuid = 'stub_wifi1_guid'; + const numNetworks = 2; + const testNetworkGuid = 'stub_wifi1_guid'; function guidExists(networks, guid) { - for (var n of networks) { - if (n.GUID == kTestNetworkGuid) + for (let n of networks) { + if (n.GUID == testNetworkGuid) return true; } return false; } - var filter = { + let filter = { networkType: NetworkType.WI_FI, visible: true, configured: true }; chrome.networkingPrivate.getNetworks( filter, callbackPass(function(networks) { - assertEq(kNumNetworks, networks.length); - assertTrue(guidExists(networks, kTestNetworkGuid)); + assertEq(numNetworks, networks.length); + assertTrue(guidExists(networks, testNetworkGuid)); chrome.networkingPrivate.forgetNetwork( - kTestNetworkGuid, callbackPass(function() { + testNetworkGuid, callbackPass(function() { chrome.networkingPrivate.getNetworks( filter, callbackPass(function(networks) { - assertEq(kNumNetworks - 1, networks.length); - assertFalse(guidExists(networks, kTestNetworkGuid)); + assertEq(numNetworks - 1, networks.length); + assertFalse(guidExists(networks, testNetworkGuid)); })); })); })); @@ -267,7 +267,7 @@ }, function getNetworks() { // Test 'type' and 'configured'. - var filter = { + let filter = { networkType: NetworkType.WI_FI, configured: true }; @@ -285,10 +285,10 @@ WiFi: { BSSID: '00:01:02:03:04:05', Frequency: 2400, - HexSSID: "7769666931", + HexSSID: '7769666931', Security: 'WEP-PSK', SignalStrength: 40, - SSID: "wifi1", + SSID: 'wifi1', } }, { GUID: 'stub_wifi2_guid', @@ -299,9 +299,9 @@ WiFi: { BSSID: '', Frequency: 5000, - HexSSID: "77696669325F50534B", + HexSSID: '77696669325F50534B', Security: 'WPA-PSK', - SSID: "wifi2_PSK", + SSID: 'wifi2_PSK', } }], result); @@ -321,10 +321,10 @@ WiFi: { BSSID: '00:01:02:03:04:05', Frequency: 2400, - HexSSID: "7769666931", + HexSSID: '7769666931', Security: 'WEP-PSK', SignalStrength: 40, - SSID: "wifi1", + SSID: 'wifi1', } }], result); @@ -376,10 +376,10 @@ WiFi: { BSSID: '00:01:02:03:04:05', Frequency: 2400, - HexSSID: "7769666931", + HexSSID: '7769666931', Security: 'WEP-PSK', SignalStrength: 40, - SSID: "wifi1", + SSID: 'wifi1', } }, { ConnectionState: ConnectionStateType.CONNECTED, @@ -415,10 +415,10 @@ WiFi: { BSSID: '', Frequency: 5000, - HexSSID: "77696669325F50534B", + HexSSID: '77696669325F50534B', Security: 'WPA-PSK', SignalStrength: 80, - SSID: "wifi2_PSK", + SSID: 'wifi2_PSK', } }], result); })); @@ -438,10 +438,10 @@ WiFi: { BSSID: '00:01:02:03:04:05', Frequency: 2400, - HexSSID: "7769666931", + HexSSID: '7769666931', Security: 'WEP-PSK', SignalStrength: 40, - SSID: "wifi1", + SSID: 'wifi1', } }, { Connectable: true, @@ -454,10 +454,10 @@ WiFi: { BSSID: '', Frequency: 5000, - HexSSID: "77696669325F50534B", + HexSSID: '77696669325F50534B', Security: 'WPA-PSK', SignalStrength: 80, - SSID: "wifi2_PSK", + SSID: 'wifi2_PSK', } }], result); })); @@ -465,7 +465,7 @@ function enabledNetworkTypesDisable() { chrome.networkingPrivate.getEnabledNetworkTypes(function(types) { assertTrue(types.indexOf('WiFi') >= 0); - var listener = callbackPass(function() { + const listener = callbackPass(function() { chrome.networkingPrivate.onDeviceStateListChanged.removeListener( listener); chrome.networkingPrivate.getEnabledNetworkTypes( @@ -481,7 +481,7 @@ function enabledNetworkTypesEnable() { chrome.networkingPrivate.getEnabledNetworkTypes(function(types) { assertFalse(types.indexOf('WiFi') >= 0); - var listener = callbackPass(function() { + const listener = callbackPass(function() { chrome.networkingPrivate.onDeviceStateListChanged.removeListener( listener); chrome.networkingPrivate.getEnabledNetworkTypes( @@ -510,22 +510,22 @@ function requestNetworkScan() { // Connected or Connecting networks should be listed first, sorted by type. - var expected = ['stub_ethernet_guid', - 'stub_wifi1_guid', - 'stub_vpn1_guid', - 'stub_vpn2_guid', - 'stub_wifi2_guid']; - var done = chrome.test.callbackAdded(); - var listener = + const expected = ['stub_ethernet_guid', + 'stub_wifi1_guid', + 'stub_vpn1_guid', + 'stub_vpn2_guid', + 'stub_wifi2_guid']; + const done = chrome.test.callbackAdded(); + const listener = new privateHelpers.networkListChangedListener(expected, done); listener.start(); chrome.networkingPrivate.requestNetworkScan(); }, function requestNetworkScanCellular() { - var done = chrome.test.callbackAdded(); - var listener = new privateHelpers.networksChangedListener( - kCellularGuid, function(result) { - var cellular = result.Cellular; + const done = chrome.test.callbackAdded(); + const listener = new privateHelpers.networksChangedListener( + CELLULAR_GUID, function(result) { + const cellular = result.Cellular; return cellular && cellular.FoundNetworks && cellular.FoundNetworks[0].Status == 'available'; }, done); @@ -572,7 +572,7 @@ }, function getPropertiesCellular() { chrome.networkingPrivate.getProperties( - kCellularGuid, + CELLULAR_GUID, callbackPass(function(result) { assertEq({ Cellular: { @@ -585,30 +585,30 @@ Country: 'us', Name: 'Cellular1_Provider' }, - ESN: "test_esn", - ICCID: "test_iccid", - IMEI: "test_imei", - MDN: "test_mdn", - MEID: "test_meid", - MIN: "test_min", - ModelID:"test_model_id", + ESN: 'test_esn', + ICCID: 'test_iccid', + IMEI: 'test_imei', + MDN: 'test_mdn', + MEID: 'test_meid', + MIN: 'test_min', + ModelID:'test_model_id', NetworkTechnology: 'GSM', RoamingState: 'Home', SIMLockStatus: {LockEnabled: true, LockType: '', RetriesLeft: 3}, Scanning: false, LastGoodAPN: { - AccessPointName: "default_apn", - ApnTypes: ["Default"], - Authentication: "CHAP", - LocalizedName: "localized test apn", - Name: "default_apn", - Username: "user name", - Password: "password", - Source: "Modb", + AccessPointName: 'default_apn', + ApnTypes: ['Default'], + Authentication: 'CHAP', + LocalizedName: 'localized test apn', + Name: 'default_apn', + Username: 'user name', + Password: 'password', + Source: 'Modb', }, }, ConnectionState: ConnectionStateType.NOT_CONNECTED, - GUID: kCellularGuid, + GUID: CELLULAR_GUID, IPAddressConfigType: chrome.networkingPrivate.IPConfigType.DHCP, Metered: true, TrafficCounterResetTime: 0.0, @@ -624,25 +624,25 @@ chrome.networkingPrivate.getNetworks( filter, callbackPass(function(networks) { assertEq(1, networks.length); - var guid = networks[0].GUID; + const guid = networks[0].GUID; chrome.networkingPrivate.getProperties( guid, callbackPass(function(result) { assertEq({ Cellular: { AllowRoaming: false, - ESN: "test_esn", + ESN: 'test_esn', Family: 'GSM', HomeProvider: { Code: '000000', Country: 'us', Name: 'Cellular1_Provider', }, - ICCID: "test_iccid", - IMEI: "test_imei", - MDN: "test_mdn", - MEID: "test_meid", - MIN: "test_min", - ModelID:"test_model_id", + ICCID: 'test_iccid', + IMEI: 'test_imei', + MDN: 'test_mdn', + MEID: 'test_meid', + MIN: 'test_min', + ModelID:'test_model_id', SIMLockStatus: { LockEnabled: true, LockType: '', @@ -731,23 +731,23 @@ })); }, function setCellularProperties() { - var network_guid = kCellularGuid; + const networkGuid = CELLULAR_GUID; chrome.networkingPrivate.getProperties( - network_guid, + networkGuid, callbackPass(function(result) { - assertEq(network_guid, result.GUID); - var new_properties = { + assertEq(networkGuid, result.GUID); + const newProperties = { Priority: 1 }; chrome.networkingPrivate.setProperties( - network_guid, - new_properties, + networkGuid, + newProperties, callbackPass(function() { chrome.networkingPrivate.getProperties( - network_guid, + networkGuid, callbackPass(function(result) { // Ensure that the GUID doesn't change. - assertEq(network_guid, result.GUID); + assertEq(networkGuid, result.GUID); // Ensure that the properties were set. assertEq(1, result['Priority']); })); @@ -755,12 +755,12 @@ })); }, function setWiFiProperties() { - var network_guid = 'stub_wifi1_guid'; + const networkGuid = 'stub_wifi1_guid'; chrome.networkingPrivate.getProperties( - network_guid, + networkGuid, callbackPass(function(result) { - assertEq(network_guid, result.GUID); - var new_properties = { + assertEq(networkGuid, result.GUID); + const newProperties = { Priority: 1, WiFi: { AutoConnect: true @@ -773,14 +773,14 @@ } }; chrome.networkingPrivate.setProperties( - network_guid, - new_properties, + networkGuid, + newProperties, callbackPass(function() { chrome.networkingPrivate.getProperties( - network_guid, + networkGuid, callbackPass(function(result) { // Ensure that the GUID doesn't change. - assertEq(network_guid, result.GUID); + assertEq(networkGuid, result.GUID); // Ensure that the properties were set. assertEq(1, result['Priority']); assertTrue('WiFi' in result); @@ -796,12 +796,12 @@ })); }, function setVPNProperties() { - var network_guid = 'stub_vpn1_guid'; + const networkGuid = 'stub_vpn1_guid'; chrome.networkingPrivate.getProperties( - network_guid, + networkGuid, callbackPass(function(result) { - assertEq(network_guid, result.GUID); - var new_properties = { + assertEq(networkGuid, result.GUID); + const newProperties = { Priority: 1, Type: 'VPN', VPN: { @@ -810,11 +810,11 @@ } }; chrome.networkingPrivate.setProperties( - network_guid, - new_properties, + networkGuid, + newProperties, callbackPass(function() { chrome.networkingPrivate.getProperties( - network_guid, + networkGuid, callbackPass(function(result) { // Ensure that the properties were set. assertEq(1, result['Priority']); @@ -822,7 +822,7 @@ assertTrue('Host' in result['VPN']); assertEq('vpn.host1', result['VPN']['Host']); // Ensure that the GUID doesn't change. - assertEq(network_guid, result.GUID); + assertEq(networkGuid, result.GUID); })); })); })); @@ -842,10 +842,10 @@ WiFi: { BSSID: '', Frequency: 5000, - HexSSID: "77696669325F50534B", + HexSSID: '77696669325F50534B', Security: 'WPA-PSK', SignalStrength: 80, - SSID: "wifi2_PSK", + SSID: 'wifi2_PSK', } }, result); })); @@ -867,9 +867,9 @@ })); }, function onNetworksChangedEventConnect() { - var network = 'stub_wifi2_guid'; - var done = chrome.test.callbackAdded(); - var listener = new privateHelpers.watchForStateChanges( + const network = 'stub_wifi2_guid'; + const done = chrome.test.callbackAdded(); + const listener = new privateHelpers.watchForStateChanges( new Map([ ['stub_wifi1_guid', [ConnectionStateType.NOT_CONNECTED]], [network, [ConnectionStateType.CONNECTED]] @@ -878,29 +878,29 @@ chrome.networkingPrivate.startConnect(network, networkCallbackPass()); }, function onNetworksChangedEventDisconnect() { - var network = 'stub_wifi1_guid'; - var done = chrome.test.callbackAdded(); - var listener = new privateHelpers.watchForStateChanges( + const network = 'stub_wifi1_guid'; + const done = chrome.test.callbackAdded(); + const listener = new privateHelpers.watchForStateChanges( new Map([[network, [ConnectionStateType.NOT_CONNECTED]]]), done); chrome.networkingPrivate.startDisconnect(network, networkCallbackPass()); }, function onNetworkListChangedEvent() { // Connecting to wifi2 should set wifi1 to offline. Connected or Connecting // networks should be listed first, sorted by type. - var expected = ['stub_ethernet_guid', - 'stub_vpn1_guid', - 'stub_wifi2_guid', - 'stub_wifi1_guid', - 'stub_vpn2_guid']; - var done = chrome.test.callbackAdded(); - var listener = + const expected = ['stub_ethernet_guid', + 'stub_vpn1_guid', + 'stub_wifi2_guid', + 'stub_wifi1_guid', + 'stub_vpn2_guid']; + const done = chrome.test.callbackAdded(); + const listener = new privateHelpers.networkListChangedListener(expected, done); listener.start(); - var network = 'stub_wifi2_guid'; + const network = 'stub_wifi2_guid'; chrome.networkingPrivate.startConnect(network, networkCallbackPass()); }, function onDeviceStateListChangedEvent() { - var listener = callbackPass(function() { + const listener = callbackPass(function() { chrome.networkingPrivate.onDeviceStateListChanged.removeListener( listener); }); @@ -910,7 +910,7 @@ function onDeviceScanningChangedEvent() { // Requesting a scan should trigger a device state list changed event when // the scan completes. - var listener = callbackPass(function() { + const listener = callbackPass(function() { chrome.networkingPrivate.onDeviceStateListChanged.removeListener( listener); }); @@ -923,12 +923,12 @@ chrome.test.sendMessage('eventListenerReady'); }, function getCaptivePortalStatus() { - var networks = [['stub_ethernet_guid', 'Online'], - ['stub_wifi1_guid', 'Offline'], - ['stub_wifi2_guid', 'Portal']]; + const networks = [['stub_ethernet_guid', 'Online'], + ['stub_wifi1_guid', 'Offline'], + ['stub_wifi2_guid', 'Portal']]; networks.forEach(function(network) { - var guid = network[0]; - var expectedStatus = network[1]; + const guid = network[0]; + const expectedStatus = network[1]; chrome.networkingPrivate.getCaptivePortalStatus( guid, callbackPass(function(status) { @@ -937,36 +937,37 @@ }); }, function captivePortalNotification() { - var done = chrome.test.callbackAdded(); - var listener = + const done = chrome.test.callbackAdded(); + const listener = new privateHelpers.watchForCaptivePortalState( 'stub_wifi1_guid', 'Portal', done); chrome.test.sendMessage('notifyPortalDetectorObservers'); }, function unlockCellularSim() { - var incorrectPin = '2222'; + const incorrectPin = '2222'; // Try with incorrect PIN, expect failure. chrome.networkingPrivate.unlockCellularSim( - kCellularGuid, incorrectPin, '', + CELLULAR_GUID, incorrectPin, '', callbackFail('incorrect-pin', function() { // Try with correct PIN, expect success. chrome.networkingPrivate.unlockCellularSim( - kCellularGuid, kDefaultPin, '', networkCallbackPass()); + CELLULAR_GUID, DEFAULT_PIN, '', networkCallbackPass()); })); }, function setCellularSimState() { - var newPin = '6666'; - var simState = {requirePin: true, currentPin: kDefaultPin, newPin: newPin}; + let newPin = '6666'; + const simState = + {requirePin: true, currentPin: DEFAULT_PIN, newPin: newPin}; // Test setting 'requirePin' and 'newPin'. chrome.networkingPrivate.getProperties( - kCellularGuid, callbackPass(function(result) { + CELLULAR_GUID, callbackPass(function(result) { // Ensure the SIM is initially unlocked. assertTrue(result.Cellular.SIMLockStatus == undefined || result.Cellular.SIMLockStatus.LockType == ''); chrome.networkingPrivate.setCellularSimState( - kCellularGuid, simState, callbackPass(function() { + CELLULAR_GUID, simState, callbackPass(function() { chrome.networkingPrivate.getProperties( - kCellularGuid, callbackPass(function(result) { + CELLULAR_GUID, callbackPass(function(result) { // The SIM should still be unlocked. assertEq('', result.Cellular.SIMLockStatus.LockType); // Ensure SIM locking is enabled. @@ -974,27 +975,27 @@ // Ensure the new pin is set by using the new PIN // to change the PIN back. simState.currentPin = newPin; - simState.newPin = kDefaultPin; + simState.newPin = DEFAULT_PIN; chrome.networkingPrivate.setCellularSimState( - kCellularGuid, simState, networkCallbackPass()); + CELLULAR_GUID, simState, networkCallbackPass()); })); })); })); }, function selectCellularMobileNetwork() { chrome.networkingPrivate.getProperties( - kCellularGuid, callbackPass(function(result) { + CELLULAR_GUID, callbackPass(function(result) { // Ensure that there are two found networks and the first is selected. assertTrue(!!result.Cellular.FoundNetworks); assertTrue(result.Cellular.FoundNetworks.length >= 2); assertTrue(result.Cellular.FoundNetworks[0].Status == 'current'); assertTrue(result.Cellular.FoundNetworks[1].Status == 'available'); // Select the second network - var secondNetworkId = result.Cellular.FoundNetworks[1].NetworkId; + const secondNetworkId = result.Cellular.FoundNetworks[1].NetworkId; chrome.networkingPrivate.selectCellularMobileNetwork( - kCellularGuid, secondNetworkId, callbackPass(function() { + CELLULAR_GUID, secondNetworkId, callbackPass(function() { chrome.networkingPrivate.getProperties( - kCellularGuid, callbackPass(function(result) { + CELLULAR_GUID, callbackPass(function(result) { // Ensure that the second network is selected. assertTrue(!!result.Cellular.FoundNetworks); assertTrue(result.Cellular.FoundNetworks.length >= 2); @@ -1007,32 +1008,32 @@ })); }, function cellularSimPuk() { - var newPin = '6666'; - var incorrectPin = '2222'; - var incorrectPuk = '22222222'; - var unlockFailFunc = function(nextFunc) { + const newPin = '6666'; + const incorrectPin = '2222'; + const incorrectPuk = '22222222'; + const unlockFailFunc = function(nextFunc) { chrome.networkingPrivate.unlockCellularSim( - kCellularGuid, incorrectPin, '', + CELLULAR_GUID, incorrectPin, '', callbackFail('incorrect-pin', nextFunc)); }; // Try with incorrect PIN three times, SIM should become PUK locked. unlockFailFunc(unlockFailFunc(unlockFailFunc(function() { // Ensure the SIM is PUK locked. chrome.networkingPrivate.getProperties( - kCellularGuid, callbackPass(function(result) { + CELLULAR_GUID, callbackPass(function(result) { assertEq('sim-puk', result.Cellular.SIMLockStatus.LockType); // Try to unlock with an incorrect PUK, expect failure. chrome.networkingPrivate.unlockCellularSim( - kCellularGuid, newPin, incorrectPuk, + CELLULAR_GUID, newPin, incorrectPuk, callbackFail('incorrect-pin', function() { // Try with the correct PUK, expect success. chrome.networkingPrivate.unlockCellularSim( - kCellularGuid, newPin, kDefaultPuk, + CELLULAR_GUID, newPin, DEFAULT_PUK, callbackPass(function() { // Set state with the new PIN, expect success. - var simState = {requirePin: true, currentPin: newPin}; + const simState = {requirePin: true, currentPin: newPin}; chrome.networkingPrivate.setCellularSimState( - kCellularGuid, simState, networkCallbackPass()); + CELLULAR_GUID, simState, networkCallbackPass()); })); })); })); @@ -1091,12 +1092,12 @@ ]; chrome.test.getConfig(function(config) { - var args = JSON.parse(config.customArg); - var tests = availableTests.filter(function(op) { + const args = JSON.parse(config.customArg); + const tests = availableTests.filter(function(op) { return args.test == op.name; }); if (tests.length !== 1) { - chrome.test.notifyFail('Test not found ' + args.test); + chrome.test.notifyFail(`Test not found ${args.test}`); return; }
diff --git a/chrome/test/data/extensions/api_test/networking_private/service_client/test.js b/chrome/test/data/extensions/api_test/networking_private/service_client/test.js index 2ef5f42..e0af074 100644 --- a/chrome/test/data/extensions/api_test/networking_private/service_client/test.js +++ b/chrome/test/data/extensions/api_test/networking_private/service_client/test.js
@@ -6,26 +6,26 @@ // Note: ServiceClient currently only implements WiFi networks. See // networking_private_service_client_apitest.cc for more info. -var callbackPass = chrome.test.callbackPass; -var callbackFail = chrome.test.callbackFail; -var assertTrue = chrome.test.assertTrue; -var assertFalse = chrome.test.assertFalse; -var assertEq = chrome.test.assertEq; +const callbackPass = chrome.test.callbackPass; +const callbackFail = chrome.test.callbackFail; +const assertTrue = chrome.test.assertTrue; +const assertFalse = chrome.test.assertFalse; +const assertEq = chrome.test.assertEq; -var privateHelpers = { +const privateHelpers = { // Watches for the states |expectedStates| in reverse order. If all states // were observed in the right order, succeeds and calls |done|. If any // unexpected state is observed, fails. watchForStateChanges: function(network, expectedStates, done) { - var self = this; - var collectProperties = function(properties) { - var finishTest = function() { + const self = this; + const collectProperties = function(properties) { + const finishTest = function() { chrome.networkingPrivate.onNetworksChanged.removeListener( self.onNetworkChange); done(); }; if (expectedStates.length > 0) { - var expectedState = expectedStates.pop(); + const expectedState = expectedStates.pop(); assertEq(expectedState, properties.ConnectionState); if (expectedStates.length == 0) finishTest(); @@ -41,7 +41,7 @@ this.onNetworkChange); }, listListener: function(expected, done) { - var self = this; + const self = this; this.listenForChanges = function(list) { assertEq(expected, list); chrome.networkingPrivate.onNetworkListChanged.removeListener( @@ -52,7 +52,7 @@ watchForCaptivePortalState: function(expectedGuid, expectedState, done) { - var self = this; + const self = this; this.onPortalDetectionCompleted = function(guid, state) { assertEq(expectedGuid, guid); assertEq(expectedState, state); @@ -65,96 +65,96 @@ } }; -var availableTests = [ +const availableTests = [ function startConnect() { - chrome.networkingPrivate.startConnect("stub_wifi2_guid", callbackPass()); + chrome.networkingPrivate.startConnect('stub_wifi2_guid', callbackPass()); }, function startDisconnect() { // Must connect to a network before we can disconnect from it. - chrome.networkingPrivate.startConnect("stub_wifi2_guid", callbackPass( + chrome.networkingPrivate.startConnect('stub_wifi2_guid', callbackPass( function() { - chrome.networkingPrivate.startDisconnect("stub_wifi2_guid", + chrome.networkingPrivate.startDisconnect('stub_wifi2_guid', callbackPass()); })); }, function startConnectNonexistent() { chrome.networkingPrivate.startConnect( - "nonexistent_path", - callbackFail("Error.InvalidNetworkGuid")); + 'nonexistent_path', + callbackFail('Error.InvalidNetworkGuid')); }, function startDisconnectNonexistent() { chrome.networkingPrivate.startDisconnect( - "nonexistent_path", - callbackFail("Error.InvalidNetworkGuid")); + 'nonexistent_path', + callbackFail('Error.InvalidNetworkGuid')); }, function startGetPropertiesNonexistent() { chrome.networkingPrivate.getProperties( - "nonexistent_path", - callbackFail("Error.InvalidNetworkGuid")); + 'nonexistent_path', + callbackFail('Error.InvalidNetworkGuid')); }, function createNetwork() { chrome.networkingPrivate.createNetwork( false, // shared - { "Type": "WiFi", - "GUID": "ignored_guid", - "WiFi": { - "SSID": "wifi_created", - "Security": "WEP-PSK" + { Type: 'WiFi', + GUID: 'ignored_guid', + WiFi: { + SSID: 'wifi_created', + Security: 'WEP-PSK' } }, callbackPass(function(guid) { - assertFalse(guid == ""); - assertFalse(guid == "ignored_guid"); + assertFalse(guid == ''); + assertFalse(guid == 'ignored_guid'); chrome.networkingPrivate.getProperties( guid, callbackPass(function(properties) { - assertEq("WiFi", properties.Type); + assertEq('WiFi', properties.Type); assertEq(guid, properties.GUID); - assertEq("wifi_created", properties.WiFi.SSID); - assertEq("WEP-PSK", properties.WiFi.Security); + assertEq('wifi_created', properties.WiFi.SSID); + assertEq('WEP-PSK', properties.WiFi.Security); })); })); }, function getNetworks() { // Test 'type' and 'configured'. chrome.networkingPrivate.getNetworks( - { "networkType": "WiFi", "configured": true }, + { networkType: 'WiFi', configured: true }, callbackPass(function(result) { assertEq([{ - "Connectable": true, - "ConnectionState": "Connected", - "GUID": "stub_wifi1_guid", - "Name": "wifi1", - "Type": "WiFi", - "WiFi": { - "Security": "WEP-PSK", - "SignalStrength": 40 + Connectable: true, + ConnectionState: 'Connected', + GUID: 'stub_wifi1_guid', + Name: 'wifi1', + Type: 'WiFi', + WiFi: { + Security: 'WEP-PSK', + SignalStrength: 40 } }, { - "Connectable": true, - "ConnectionState": "NotConnected", - "GUID": "stub_wifi2_guid", - "Name": "wifi2_PSK", - "Type": "WiFi", - "WiFi": { - "Security": "WPA-PSK", - "SignalStrength": 80 + Connectable: true, + ConnectionState: 'NotConnected', + GUID: 'stub_wifi2_guid', + Name: 'wifi2_PSK', + Type: 'WiFi', + WiFi: { + Security: 'WPA-PSK', + SignalStrength: 80 } }], result); // Test 'limit'. chrome.networkingPrivate.getNetworks( - { "networkType": "All", "limit": 1 }, + { networkType: 'All', limit: 1 }, callbackPass(function(result) { assertEq([{ - "Connectable": true, - "ConnectionState": "Connected", - "GUID": "stub_wifi1_guid", - "Name": "wifi1", - "Type": "WiFi", - "WiFi": { - "Security": "WEP-PSK", - "SignalStrength": 40 + Connectable: true, + ConnectionState: 'Connected', + GUID: 'stub_wifi1_guid', + Name: 'wifi1', + Type: 'WiFi', + WiFi: { + Security: 'WEP-PSK', + SignalStrength: 40 } }], result); })); @@ -162,56 +162,56 @@ }, function getVisibleNetworks() { chrome.networkingPrivate.getVisibleNetworks( - "All", + 'All', callbackPass(function(result) { assertEq([{ - "Connectable": true, - "ConnectionState": "Connected", - "GUID": "stub_wifi1_guid", - "Name": "wifi1", - "Type": "WiFi", - "WiFi": { - "Security": "WEP-PSK", - "SignalStrength": 40 + Connectable: true, + ConnectionState: 'Connected', + GUID: 'stub_wifi1_guid', + Name: 'wifi1', + Type: 'WiFi', + WiFi: { + Security: 'WEP-PSK', + SignalStrength: 40 } }, { - "Connectable": true, - "ConnectionState": "NotConnected", - "GUID": "stub_wifi2_guid", - "Name": "wifi2_PSK", - "Type": "WiFi", - "WiFi": { - "Security": "WPA-PSK", - "SignalStrength": 80 + Connectable: true, + ConnectionState: 'NotConnected', + GUID: 'stub_wifi2_guid', + Name: 'wifi2_PSK', + Type: 'WiFi', + WiFi: { + Security: 'WPA-PSK', + SignalStrength: 80 } }], result); })); }, function getVisibleNetworksWifi() { chrome.networkingPrivate.getVisibleNetworks( - "WiFi", + 'WiFi', callbackPass(function(result) { assertEq([{ - "Connectable": true, - "ConnectionState": "Connected", - "GUID": "stub_wifi1_guid", - "Name": "wifi1", - "Type": "WiFi", - "WiFi": { - "Security": "WEP-PSK", - "SignalStrength": 40 + Connectable: true, + ConnectionState: 'Connected', + GUID: 'stub_wifi1_guid', + Name: 'wifi1', + Type: 'WiFi', + WiFi: { + Security: 'WEP-PSK', + SignalStrength: 40 } }, { - "Connectable": true, - "ConnectionState": "NotConnected", - "GUID": "stub_wifi2_guid", - "Name": "wifi2_PSK", - "Type": "WiFi", - "WiFi": { - "Security": "WPA-PSK", - "SignalStrength": 80 + Connectable: true, + ConnectionState: 'NotConnected', + GUID: 'stub_wifi2_guid', + Name: 'wifi2_PSK', + Type: 'WiFi', + WiFi: { + Security: 'WPA-PSK', + SignalStrength: 80 } } ], result); @@ -219,86 +219,86 @@ }, function requestNetworkScan() { // Connected or Connecting networks should be listed first, sorted by type. - var expected = ["stub_wifi1_guid", - "stub_wifi2_guid"]; - var done = chrome.test.callbackAdded(); - var listener = new privateHelpers.listListener(expected, done); + const expected = ['stub_wifi1_guid', + 'stub_wifi2_guid']; + const done = chrome.test.callbackAdded(); + const listener = new privateHelpers.listListener(expected, done); chrome.networkingPrivate.onNetworkListChanged.addListener( listener.listenForChanges); chrome.networkingPrivate.requestNetworkScan(); }, function getProperties() { chrome.networkingPrivate.getProperties( - "stub_wifi1_guid", + 'stub_wifi1_guid', callbackPass(function(result) { - assertEq({ "Connectable": true, - "ConnectionState": "Connected", - "GUID": "stub_wifi1_guid", - "Name": "wifi1", - "Type": "WiFi", - "WiFi": { - "HexSSID": "7769666931", // "wifi1" - "SSID": "wifi1", - "Security": "WEP-PSK", - "SignalStrength": 40 + assertEq({ Connectable: true, + ConnectionState: 'Connected', + GUID: 'stub_wifi1_guid', + Name: 'wifi1', + Type: 'WiFi', + WiFi: { + HexSSID: '7769666931', // 'wifi1' + 'SSID': 'wifi1', + Security: 'WEP-PSK', + SignalStrength: 40 } }, result); })); }, function getManagedProperties() { chrome.networkingPrivate.getManagedProperties( - "stub_wifi2", + 'stub_wifi2', callbackPass(function(result) { assertEq({ - "Connectable": true, - "ConnectionState": "NotConnected", - "GUID": "stub_wifi2", - "Name": { - "Active": "wifi2_PSK", - "Effective": "UserPolicy", - "UserPolicy": "My WiFi Network" + Connectable: true, + ConnectionState: 'NotConnected', + GUID: 'stub_wifi2', + Name: { + Active: 'wifi2_PSK', + Effective: 'UserPolicy', + UserPolicy: 'My WiFi Network' }, - "Source": "UserPolicy", - "Type": "WiFi", - "WiFi": { - "AutoConnect": { - "Active": false, - "UserEditable": true + Source: 'UserPolicy', + Type: 'WiFi', + WiFi: { + AutoConnect: { + Active: false, + UserEditable: true }, - "HexSSID": { - "Active": "77696669325F50534B", // "wifi2_PSK" - "Effective": "UserPolicy", - "UserPolicy": "77696669325F50534B" + HexSSID: { + Active: '77696669325F50534B', // 'wifi2_PSK' + 'Effective': 'UserPolicy', + UserPolicy: '77696669325F50534B' }, - "Frequency" : 5000, - "FrequencyList" : [2400, 5000], - "Passphrase": { - "Effective": "UserSetting", - "UserEditable": true, - "UserSetting": "FAKE_CREDENTIAL_VPaJDV9x" + Frequency: 5000, + FrequencyList: [2400, 5000], + Passphrase: { + Effective: 'UserSetting', + UserEditable: true, + UserSetting: 'FAKE_CREDENTIAL_VPaJDV9x' }, - "SSID": { - "Active": "wifi2_PSK", - "Effective": "UserPolicy", + SSID: { + Active: 'wifi2_PSK', + Effective: 'UserPolicy', }, - "Security": { - "Active": "WPA-PSK", - "Effective": "UserPolicy", - "UserPolicy": "WPA-PSK" + Security: { + Active: 'WPA-PSK', + Effective: 'UserPolicy', + UserPolicy: 'WPA-PSK' }, - "SignalStrength": 80, + SignalStrength: 80, } }, result); })); }, function setWiFiProperties() { - var done = chrome.test.callbackAdded(); - var network_guid = "stub_wifi1_guid"; + const done = chrome.test.callbackAdded(); + const networkGuid = 'stub_wifi1_guid'; chrome.networkingPrivate.getProperties( - network_guid, + networkGuid, callbackPass(function(result) { - assertEq(network_guid, result.GUID); - var new_properties = { + assertEq(networkGuid, result.GUID); + const newProperties = { Priority: 1, WiFi: { AutoConnect: true @@ -311,11 +311,11 @@ } }; chrome.networkingPrivate.setProperties( - network_guid, - new_properties, + networkGuid, + newProperties, callbackPass(function() { chrome.networkingPrivate.getProperties( - network_guid, + networkGuid, callbackPass(function(result) { // Ensure that the GUID doesn't change. assertEq(network_guid, result.GUID); @@ -335,13 +335,13 @@ })); }, function setVPNProperties() { - var done = chrome.test.callbackAdded(); - var network_guid = "stub_vpn1_guid"; + const done = chrome.test.callbackAdded(); + const network_guid = 'stub_vpn1_guid'; chrome.networkingPrivate.getProperties( network_guid, callbackPass(function(result) { assertEq(network_guid, result.GUID); - var new_properties = { + const new_properties = { Priority: 1, VPN: { Host: 'vpn.host1' @@ -360,7 +360,7 @@ assertTrue('Host' in result['VPN']); assertEq('vpn.host1', result['VPN']['Host']); // Ensure that the GUID doesn't change. - assertEq(network_guid, result.GUID); + assertEq(networkGuid, result.GUID); done(); })); })); @@ -368,17 +368,17 @@ }, function getState() { chrome.networkingPrivate.getState( - "stub_wifi2_guid", + 'stub_wifi2_guid', callbackPass(function(result) { assertEq({ - "Connectable": true, - "ConnectionState": "NotConnected", - "GUID": "stub_wifi2_guid", - "Name": "wifi2_PSK", - "Type": "WiFi", - "WiFi": { - "Security": "WPA-PSK", - "SignalStrength": 80 + Connectable: true, + ConnectionState: 'NotConnected', + GUID: 'stub_wifi2_guid', + Name: 'wifi2_PSK', + Type: 'WiFi', + WiFi: { + Security: 'WPA-PSK', + SignalStrength: 80 } }, result); })); @@ -389,39 +389,39 @@ callbackFail('Error.InvalidNetworkGuid')); }, function onNetworksChangedEventConnect() { - var network = "stub_wifi2_guid"; - var done = chrome.test.callbackAdded(); - var expectedStates = ["Connected"]; - var listener = + const network = 'stub_wifi2_guid'; + const done = chrome.test.callbackAdded(); + const expectedStates = ['Connected']; + const listener = new privateHelpers.watchForStateChanges(network, expectedStates, done); chrome.networkingPrivate.startConnect(network, callbackPass()); }, function onNetworksChangedEventDisconnect() { - var network = "stub_wifi1_guid"; - var done = chrome.test.callbackAdded(); - var expectedStates = ["NotConnected"]; - var listener = + const network = 'stub_wifi1_guid'; + const done = chrome.test.callbackAdded(); + const expectedStates = ['NotConnected']; + const listener = new privateHelpers.watchForStateChanges(network, expectedStates, done); chrome.networkingPrivate.startDisconnect(network, callbackPass()); }, function onNetworkListChangedEvent() { // Connecting to wifi2 should set wifi1 to offline. Connected or Connecting // networks should be listed first, sorted by type. - var expected = ["stub_wifi2_guid", - "stub_wifi1_guid"]; - var done = chrome.test.callbackAdded(); - var listener = new privateHelpers.listListener(expected, done); + const expected = ['stub_wifi2_guid', + 'stub_wifi1_guid']; + const done = chrome.test.callbackAdded(); + const listener = new privateHelpers.listListener(expected, done); chrome.networkingPrivate.onNetworkListChanged.addListener( listener.listenForChanges); - var network = "stub_wifi2_guid"; + const network = 'stub_wifi2_guid'; chrome.networkingPrivate.startConnect(network, callbackPass()); }, function getCaptivePortalStatus() { - var networks = [['stub_wifi1_guid', 'Offline'], + const networks = [['stub_wifi1_guid', 'Offline'], ['stub_wifi2_guid', 'Portal']]; networks.forEach(function(network) { - var guid = network[0]; - var expectedStatus = network[1]; + const guid = network[0]; + const expectedStatus = network[1]; chrome.networkingPrivate.getCaptivePortalStatus( guid, callbackPass(function(status) { @@ -430,15 +430,15 @@ }); }, function captivePortalNotification() { - var done = chrome.test.callbackAdded(); - var listener = + const done = chrome.test.callbackAdded(); + const listener = new privateHelpers.watchForCaptivePortalState( 'wifi_guid', 'Online', done); chrome.test.sendMessage('notifyPortalDetectorObservers'); }, ]; -var testToRun = window.location.search.substring(1); +const testToRun = window.location.search.substring(1); chrome.test.runTests(availableTests.filter(function(op) { return op.name == testToRun; }));
diff --git a/chrome/test/data/extensions/api_test/networking_private/test.js b/chrome/test/data/extensions/api_test/networking_private/test.js index 9f36f5f..7532e9d7 100644 --- a/chrome/test/data/extensions/api_test/networking_private/test.js +++ b/chrome/test/data/extensions/api_test/networking_private/test.js
@@ -6,42 +6,42 @@ // that callbacks are correctly invoked, expected parameters are correct, // and failures are detected. -var callbackPass = chrome.test.callbackPass; +const callbackPass = chrome.test.callbackPass; -var kFailure = 'Failure'; -var kGuid = 'SOME_GUID'; +const FAILURE = 'Failure'; +const GUID = 'SOME_GUID'; function callbackResult(result) { if (chrome.runtime.lastError) chrome.test.fail(chrome.runtime.lastError.message); - else if (result == false || result == kFailure) - chrome.test.fail('Failed: ' + result); + else if (result == false || result == FAILURE) + chrome.test.fail(`Failed: ${result}`); } -var availableTests = [ +const availableTests = [ function getProperties() { chrome.networkingPrivate.getProperties( - kGuid, callbackPass(callbackResult)); + GUID, callbackPass(callbackResult)); }, function getManagedProperties() { chrome.networkingPrivate.getManagedProperties( - kGuid, callbackPass(callbackResult)); + GUID, callbackPass(callbackResult)); }, function getState() { chrome.networkingPrivate.getState( - kGuid, callbackPass(callbackResult)); + GUID, callbackPass(callbackResult)); }, function setProperties() { chrome.networkingPrivate.setProperties( - kGuid, { 'GUID': kGuid }, callbackPass(callbackResult)); + GUID, { GUID: GUID }, callbackPass(callbackResult)); }, function createNetwork() { chrome.networkingPrivate.createNetwork( - false, { 'GUID': kGuid }, callbackPass(callbackResult)); + false, { GUID: GUID }, callbackPass(callbackResult)); }, function forgetNetwork() { chrome.networkingPrivate.forgetNetwork( - kGuid, callbackPass(callbackResult)); + GUID, callbackPass(callbackResult)); }, function getNetworks() { chrome.networkingPrivate.getNetworks( @@ -73,39 +73,39 @@ }, function startConnect() { chrome.networkingPrivate.startConnect( - kGuid, callbackPass(callbackResult)); + GUID, callbackPass(callbackResult)); }, function startDisconnect() { chrome.networkingPrivate.startDisconnect( - kGuid, callbackPass(callbackResult)); + GUID, callbackPass(callbackResult)); }, function startActivate() { chrome.networkingPrivate.startActivate( - kGuid, '' /* carrier */, callbackPass(callbackResult)); + GUID, '' /* carrier */, callbackPass(callbackResult)); }, function getCaptivePortalStatus() { chrome.networkingPrivate.getCaptivePortalStatus( - kGuid, callbackPass(callbackResult)); + GUID, callbackPass(callbackResult)); }, function unlockCellularSim() { chrome.networkingPrivate.unlockCellularSim( - kGuid, '1111', callbackPass(callbackResult)); + GUID, '1111', callbackPass(callbackResult)); }, function setCellularSimState() { - var simState = { requirePin: true, currentPin: '1111', newPin: '1234' }; + const simState = { requirePin: true, currentPin: '1111', newPin: '1234' }; chrome.networkingPrivate.setCellularSimState( - kGuid, simState, callbackPass(callbackResult)); + GUID, simState, callbackPass(callbackResult)); }, function selectCellularMobileNetwork() { chrome.networkingPrivate.selectCellularMobileNetwork( - kGuid, 'fakeId', callbackPass(callbackResult)); + GUID, 'fakeId', callbackPass(callbackResult)); }, function getGlobalPolicy() { chrome.networkingPrivate.getGlobalPolicy(callbackPass(callbackResult)); } ]; -var testToRun = window.location.search.substring(1); +const testToRun = window.location.search.substring(1); chrome.test.runTests(availableTests.filter(function(op) { return op.name == testToRun; }));
diff --git a/chrome/test/data/extensions/api_test/notifications/api/basic_usage/background.js b/chrome/test/data/extensions/api_test/notifications/api/basic_usage/background.js index cbf6ea1..4527278 100644 --- a/chrome/test/data/extensions/api_test/notifications/api/basic_usage/background.js +++ b/chrome/test/data/extensions/api_test/notifications/api/basic_usage/background.js
@@ -4,51 +4,51 @@ const notifications = chrome.notifications; -const red_dot = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA" + - "AAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO" + - "9TXL0Y4OHwAAAABJRU5ErkJggg=="; +const RED_DOT = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA' + + 'AAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO' + + '9TXL0Y4OHwAAAABJRU5ErkJggg=='; // An image URL larger than the max size allowed for a notification image. // This was generated using the function that follows. Should we increase // the max size of an image, update the function to increase the width and // height and run the function again to log the URL. -const bigImageUrl = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA" + - "AGQAAABkCAYAAABw4pVUAAABZUlEQVR4Xu3TQREAAAiEQK9/aWvsAxMw4O06" + - "ysAommCuINgTFKQgmAEMp4UUBDOA4bSQgmAGMJwWUhDMAIbTQgqCGcBwWkhB" + - "MAMYTgspCGYAw2khBcEMYDgtpCCYAQynhRQEM4DhtJCCYAYwnBZSEMwAhtNC" + - "CoIZwHBaSEEwAxhOCykIZgDDaSEFwQxgOC2kIJgBDKeFFAQzgOG0kIJgBjCc" + - "FlIQzACG00IKghnAcFpIQTADGE4LKQhmAMNpIQXBDGA4LaQgmAEMp4UUBDOA" + - "4bSQgmAGMJwWUhDMAIbTQgqCGcBwWkhBMAMYTgspCGYAw2khBcEMYDgtpCCY" + - "AQynhRQEM4DhtJCCYAYwnBZSEMwAhtNCCoIZwHBaSEEwAxhOCykIZgDDaSEF" + - "wQxgOC2kIJgBDKeFFAQzgOG0kIJgBjCcFlIQzACG00IKghnAcFpIQTADGE4L" + - "KQhmAMNpIQXBDGA4LQQL8oTPAGUY76lBAAAAAElFTkSuQmCC"; +const BIG_IMAGE_URL = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA' + + 'AGQAAABkCAYAAABw4pVUAAABZUlEQVR4Xu3TQREAAAiEQK9/aWvsAxMw4O06' + + 'ysAommCuINgTFKQgmAEMp4UUBDOA4bSQgmAGMJwWUhDMAIbTQgqCGcBwWkhB' + + 'MAMYTgspCGYAw2khBcEMYDgtpCCYAQynhRQEM4DhtJCCYAYwnBZSEMwAhtNC' + + 'CoIZwHBaSEEwAxhOCykIZgDDaSEFwQxgOC2kIJgBDKeFFAQzgOG0kIJgBjCc' + + 'FlIQzACG00IKghnAcFpIQTADGE4LKQhmAMNpIQXBDGA4LaQgmAEMp4UUBDOA' + + '4bSQgmAGMJwWUhDMAIbTQgqCGcBwWkhBMAMYTgspCGYAw2khBcEMYDgtpCCY' + + 'AQynhRQEM4DhtJCCYAYwnBZSEMwAhtNCCoIZwHBaSEEwAxhOCykIZgDDaSEF' + + 'wQxgOC2kIJgBDKeFFAQzgOG0kIJgBjCcFlIQzACG00IKghnAcFpIQTADGE4L' + + 'KQhmAMNpIQXBDGA4LQQL8oTPAGUY76lBAAAAAElFTkSuQmCC'; // Used to generate a data URL with an image that's too large. This // will not run using a Service Worker-based extension. function logBigImageUrl() { - var canvas = document.createElement('canvas'); + const canvas = document.createElement('canvas'); // This is just enough to be too large for an icon. See // message_center::kNotificationIconSize. canvas.width = 100; canvas.height = 100; - var ctx = canvas.getContext('2d'); - ctx.fillStyle = "rgb(200, 0, 0)"; + const ctx = canvas.getContext('2d'); + ctx.fillStyle = 'rgb(200, 0, 0)'; ctx.fillRect(10, 20, 30, 40); console.log(canvas.toDataURL()); } -var basicNotificationOptions = { - type: "basic", - title: "Basic title", - message: "Basic message", - iconUrl: red_dot +const basicNotificationOptions = { + type: 'basic', + title: 'Basic title', + message: 'Basic message', + iconUrl: RED_DOT }; function create(id, options) { return new Promise(function (resolve, reject) { notifications.create(id, options, function (id) { if (chrome.runtime.lastError) { - reject(new Error("Unable to create notification")); + reject(new Error('Unable to create notification')); return; } resolve(id); @@ -61,7 +61,7 @@ return new Promise(function (resolve, reject) { notifications.update(id, options, function (ok) { if (chrome.runtime.lastError || !ok) { - reject(new Error("Unable to update notification")); + reject(new Error('Unable to update notification')); return; } resolve(ok); @@ -74,7 +74,7 @@ return new Promise(function (resolve, reject) { notifications.clear(id, function (ok) { if (chrome.runtime.lastError || !ok) { - reject(new Error("Unable to clear notification")); + reject(new Error('Unable to clear notification')); return; } resolve(ok); @@ -96,7 +96,7 @@ return } - var id_list = Object.keys(ids); + const id_list = Object.keys(ids); resolve(id_list); }); }); @@ -104,7 +104,7 @@ function clearAll() { return getAll().then(function (ids) { - var idPromises = ids.map(function (id) { return clear(id); }); + const idPromises = ids.map(function (id) { return clear(id); }); return Promise.all(idPromises); }); } @@ -114,7 +114,7 @@ return clearAll().then( function () { chrome.test.succeed(testName); }, function (error) { - console.log("Unknown error in clearAll: " + + console.log('Unknown error in clearAll: ' + JSON.stringify(arguments)); }); }; @@ -125,111 +125,111 @@ return clearAll().then( function () { chrome.test.fail(testName); }, function (error) { - console.log("Unknown error in clearAll: " + + console.log('Unknown error in clearAll: ' + JSON.stringify(error.message)); }); }; } function testIdUsage() { - var testName = "testIdUsage"; - console.log("Starting testIdUsage."); - var succeed = succeedTest(testName); - var fail = failTest(testName); + const testName = 'testIdUsage'; + console.log('Starting testIdUsage.'); + const succeed = succeedTest(testName); + const fail = failTest(testName); - var createNotification = function (idString) { - var options = { - type: "basic", - iconUrl: red_dot, - title: "Attention!", - message: "Check out Cirque du Soleil" + const createNotification = function (idString) { + const options = { + type: 'basic', + iconUrl: RED_DOT, + title: 'Attention!', + message: 'Check out Cirque du Soleil' }; return create(idString, options); }; - var updateNotification = function (idString) { - var options = { title: "!", message: "!" }; + const updateNotification = function (idString) { + const options = { title: '!', message: '!' }; return update(idString, options); }; // Should successfully create the notification - createNotification("foo") + createNotification('foo') // And update it. .then(updateNotification) .catch(fail) // Next try to update a non-existent notification. - .then(function () { return updateNotification("foo2"); }) + .then(function () { return updateNotification('foo2'); }) // And fail if it returns true. .then(fail) // Next try to clear a non-existent notification. - .catch(function () { return clear("foo2"); }) + .catch(function () { return clear('foo2'); }) .then(fail) // And finally clear the original notification. - .catch(function () { return clear("foo"); }) + .catch(function () { return clear('foo'); }) .catch(fail) .then(succeed); }; function testIdLimit() { - var testName = "testIdLimit"; - console.log("Starting " + testName); - var succeed = succeedTest(testName); - var fail = failTest(testName); + const testName = 'testIdLimit'; + console.log(`Starting ${testName}`); + const succeed = succeedTest(testName); + const fail = failTest(testName); // Notification Ids are limited to 500 characters in length. - var id = 'a'.repeat(501); + const id = 'a'.repeat(501); create(id, { type: 'basic', - iconUrl: red_dot, + iconUrl: RED_DOT, title: 'My title', message: 'My message' }).then(fail, succeed); } function testBaseFormat() { - var testName = "testBaseFormat"; - console.log("Starting " + testName); - var succeed = succeedTest(testName); - var fail = failTest(testName); + const testName = 'testBaseFormat'; + console.log(`Starting ${testName}`); + const succeed = succeedTest(testName); + const fail = failTest(testName); - var createNotificationWithout = function(toDelete) { - var options = { - type: "basic", - iconUrl: red_dot, - title: "Attention!", - message: "Check out Cirque du Soleil", - contextMessage: "Foobar.", + const createNotificationWithout = function(toDelete) { + const options = { + type: 'basic', + iconUrl: RED_DOT, + title: 'Attention!', + message: 'Check out Cirque du Soleil', + contextMessage: 'Foobar.', priority: 1, eventTime: 123457896.12389, - expandedMessage: "This is a longer expanded message.", + expandedMessage: 'This is a longer expanded message.', }; - for (var i = 0; i < toDelete.length; i++) { + for (let i = 0; i < toDelete.length; i++) { delete options[toDelete[i]]; } - return create("", options); + return create('', options); }; // Construct some exclusion lists. The |createNotificationWithout| function // starts with a complex notification and then deletes items in this list. - var basicNotification= [ - "buttons", - "items", - "progress", - "imageUrl" + const basicNotification= [ + 'buttons', + 'items', + 'progress', + 'imageUrl' ]; - var bareNotification = basicNotification.concat([ - "priority", - "eventTime", - "expandedMessage", + const bareNotification = basicNotification.concat([ + 'priority', + 'eventTime', + 'expandedMessage', ]); - var basicNoType = basicNotification.concat(["type"]); - var basicNoIcon = basicNotification.concat(["iconUrl"]); - var basicNoTitle = basicNotification.concat(["title"]); - var basicNoMessage = basicNotification.concat(["message"]); + const basicNoType = basicNotification.concat(['type']); + const basicNoIcon = basicNotification.concat(['iconUrl']); + const basicNoTitle = basicNotification.concat(['title']); + const basicNoMessage = basicNotification.concat(['message']); // Try creating a basic notification with just some of the fields. createNotificationWithout(basicNotification) @@ -252,23 +252,23 @@ }; function testListItem() { - var testName = "testListItem"; - console.log("Starting " + testName); - var succeed = succeedTest(testName); - var fail = failTest(testName); + const testName = 'testListItem'; + console.log(`Starting ${testName}`); + const succeed = succeedTest(testName); + const fail = failTest(testName); - var item = { title: "Item title.", message: "Item message." }; - var options = { - type: "list", - iconUrl: red_dot, - title: "Attention!", - message: "Check out Cirque du Soleil", - contextMessage: "Foobar.", + const item = { title: 'Item title.', message: 'Item message.' }; + const options = { + type: 'list', + iconUrl: RED_DOT, + title: 'Attention!', + message: 'Check out Cirque du Soleil', + contextMessage: 'Foobar.', priority: 1, eventTime: 123457896.12389, items: [item, item, item, item, item], }; - create("id", options).then(succeed, fail); + create('id', options).then(succeed, fail); }; function arrayEquals(a, b) { @@ -276,18 +276,18 @@ if (a == null || b == null) return false; if (a.length !== b.length) return false; - for (var i = 0; i < a.length; i++) { + for (let i = 0; i < a.length; i++) { if (a[i] !== b[i]) return false; } return true; }; function testGetAll() { - var testName = "testGetAll"; - console.log("Starting " + testName); - var succeed = succeedTest(testName); - var fail = failTest(testName); - var in_ids = ["a", "b", "c", "d"]; + const testName = 'testGetAll'; + console.log(`Starting ${testName}`); + const succeed = succeedTest(testName); + const fail = failTest(testName); + const in_ids = ['a', 'b', 'c', 'd']; // First do a get all, make sure the list is empty. getAll() @@ -296,7 +296,7 @@ }) // Then create a bunch of notifications. .then(function () { - var newNotifications = in_ids.map(function (id) { + const newNotifications = in_ids.map(function (id) { return create(id, basicNotificationOptions); }); return Promise.all(newNotifications); @@ -312,60 +312,60 @@ } function testProgress() { - var testName = "testProgress"; - console.log("Starting " + testName); - var succeed = succeedTest(testName); - var fail = failTest(testName); - var progressOptions = { - type: "progress", - title: "Basic title", - message: "Basic message", - iconUrl: red_dot, + const testName = 'testProgress'; + console.log(`Starting ${testName}`); + const succeed = succeedTest(testName); + const fail = failTest(testName); + const progressOptions = { + type: 'progress', + title: 'Basic title', + message: 'Basic message', + iconUrl: RED_DOT, progress: 30 }; // First, create a basic progress notification. - create("progress", progressOptions) + create('progress', progressOptions) // and update it to have a different progress level. - .then(function () { return update("progress", { progress: 60 }); }) + .then(function () { return update('progress', { progress: 60 }); }) // If either of the above failed, the test fails. .catch(fail) // Now the following parts should all cause an error: // First update the progress to a low value, out-of-range - .then(function () { return update("progress", { progress: -10 }); }) + .then(function () { return update('progress', { progress: -10 }); }) // First update the progress to a high value, out-of-range - .then(fail, function () { return update("progress", { progress: 101 }); }) - .then(function () { return clear("progress"); }) + .then(fail, function () { return update('progress', { progress: 101 }); }) + .then(function () { return clear('progress'); }) // Finally try to create a notification that has a progress value but not // progress type. .then(fail, function () { - progressOptions.type = "basic"; - return create("progress", progressOptions); + progressOptions.type = 'basic'; + return create('progress', progressOptions); }).then(fail, succeed); } function testLargeImage() { - var testName = "testLargeImage"; - console.log("Starting " + testName); - var succeed = succeedTest(testName); - var fail = failTest(testName); - var options = { - type: "basic", - title: "Basic title", - message: "Basic message", - iconUrl: bigImageUrl, + const testName = 'testLargeImage'; + console.log(`Starting ${testName}`); + const succeed = succeedTest(testName); + const fail = failTest(testName); + const options = { + type: 'basic', + title: 'Basic title', + message: 'Basic message', + iconUrl: BIG_IMAGE_URL, }; - create("largeImage", options).then(succeed, fail); + create('largeImage', options).then(succeed, fail); } function testOptionalParameters() { - var testName = "testOptionalParameters"; - var succeed = succeedTest(testName); - var fail = failTest(testName); + const testName = 'testOptionalParameters'; + const succeed = succeedTest(testName); + const fail = failTest(testName); function createCallback(notificationId) { new Promise(function() { chrome.test.assertNoLastError(); - chrome.test.assertEq("string", typeof notificationId); + chrome.test.assertEq('string', typeof notificationId); // Optional callback - should run without problems chrome.notifications.clear(notificationId); // Note: The point of the previous line is to show that a callback can be
diff --git a/chrome/test/data/extensions/api_test/notifications/api/by_user/background.js b/chrome/test/data/extensions/api_test/notifications/api/by_user/background.js index bf389519..0a0761b4 100644 --- a/chrome/test/data/extensions/api_test/notifications/api/by_user/background.js +++ b/chrome/test/data/extensions/api_test/notifications/api/by_user/background.js
@@ -3,18 +3,18 @@ // found in the LICENSE file. const notifications = chrome.notifications; -var theOnlyTestDone = null; +let theOnlyTestDone = null; -var notificationData = { - type: "basic", - iconUrl: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAA" + - "CNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHw" + - "AAAABJRU5ErkJggg==", - title: "Attention!", - message: "Check out Cirque du Soleil" +const notificationData = { + type: 'basic', + iconUrl: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAA' + + 'CNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHw' + + 'AAAABJRU5ErkJggg==', + title: 'Attention!', + message: 'Check out Cirque du Soleil' }; -var results = { +const results = { FOO: false, BAR: true, BAT: false, @@ -27,39 +27,39 @@ function notifyPass() { chrome.test.notifyPass(); } -var onClosedHooks = { +const onClosedHooks = { FOO: notifyPass, BAR: notifyPass, BIFF: function() { - notifications.create("BLAT", notificationData, function () { + notifications.create('BLAT', notificationData, function () { if (chrome.runtime.lastError) { chrome.test.notifyFail(lastError.message); return; } - notifications.create("BLOT", notificationData, function () { + notifications.create('BLOT', notificationData, function () { if (chrome.runtime.lastError) { chrome.test.notifyFail(lastError.message); return; } - chrome.test.notifyPass("Created the new notifications."); + chrome.test.notifyPass('Created the new notifications.'); }); }); }, }; -function onClosedListener(id, by_user) { - if (results[id] !== by_user) { - chrome.test.notifyFail("Notification " + id + - " closed with bad by_user param ( "+ by_user +" )"); +function onClosedListener(id, byUser) { + if (results[id] !== byUser) { + chrome.test.notifyFail( + `Notification ${id} closed with bad byUser param ( ${byUser} )`); return; } delete results[id]; - if (typeof onClosedHooks[id] === "function") + if (typeof onClosedHooks[id] === 'function') onClosedHooks[id](); if (Object.keys(results).length === 0) { - chrome.test.notifyPass("Done!"); + chrome.test.notifyPass('Done!'); theOnlyTestDone(); } } @@ -69,15 +69,15 @@ function theOnlyTest() { // This test coordinates with the browser test. First, 4 notifications are // created. Then 2 are manually cancelled in C++. Then clearAll is called - // with false |by_user|. Then once the BIFF notification is cleared, we + // with false |byUser|. Then once the BIFF notification is cleared, we // create two more notifications in JS, and C++ calls the clearAll with true - // |by_user|. + // |byUser|. theOnlyTestDone = chrome.test.callbackAdded(); - notifications.create("FOO", notificationData, createCallback); - notifications.create("BAR", notificationData, createCallback); - notifications.create("BAT", notificationData, createCallback); - notifications.create("BIFF", notificationData, createCallback); + notifications.create('FOO', notificationData, createCallback); + notifications.create('BAR', notificationData, createCallback); + notifications.create('BAT', notificationData, createCallback); + notifications.create('BIFF', notificationData, createCallback); } chrome.test.runTests([ theOnlyTest ]);
diff --git a/chrome/test/data/extensions/api_test/notifications/api/csp/background.js b/chrome/test/data/extensions/api_test/notifications/api/csp/background.js index 70b16dd..fb9badac 100644 --- a/chrome/test/data/extensions/api_test/notifications/api/csp/background.js +++ b/chrome/test/data/extensions/api_test/notifications/api/csp/background.js
@@ -4,10 +4,10 @@ const notifications = chrome.notifications; -var idString = "foo"; +const idString = 'foo'; -var testCSP = function() { - var onCreateCallback = function(id) { +const testCSP = function() { + const onCreateCallback = function(id) { if (chrome.runtime.lastError) { chrome.test.succeed(); return; @@ -15,145 +15,145 @@ chrome.test.fail(); } - var options = { - type: "basic", - iconUrl: "http://google.com/clearly-a-security-problem.png", - title: "Attention!", - message: "Check out Cirque du Soleil" + const options = { + type: 'basic', + iconUrl: 'http://google.com/clearly-a-security-problem.png', + title: 'Attention!', + message: 'Check out Cirque du Soleil' }; notifications.create(idString, options, onCreateCallback); }; function testDataURL() { chrome.runtime.lastError = undefined; - var onCreateCallback = function(id) { + const onCreateCallback = function(id) { if (chrome.runtime.lastError) { chrome.test.fail(); return; } chrome.test.succeed(); } - var options = { - type: "basic", - iconUrl: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAA" + - "CNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHw" + - "AAAABJRU5ErkJggg==", - title: "Attention!", - message: "Check out Cirque du Soleil" + const options = { + type: 'basic', + iconUrl: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAA' + + 'CNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHw' + + 'AAAABJRU5ErkJggg==', + title: 'Attention!', + message: 'Check out Cirque du Soleil' }; notifications.create(idString, options, onCreateCallback); } function testCSPUpdateIconURL() { - var onUpdateCallback = function(id) { + const onUpdateCallback = function(id) { if (chrome.runtime.lastError) { chrome.test.succeed(); return; } chrome.test.fail(); }; - var onCreateCallback = function(id) { + const onCreateCallback = function(id) { if (chrome.runtime.lastError) { chrome.test.fail(); return; } - var options2 = { - type: "basic", - iconUrl: "http://www.google.com/favicon.ico", - title: "Attention!", - message: "Check out Cirque du Soleil" + const options2 = { + type: 'basic', + iconUrl: 'http://www.google.com/favicon.ico', + title: 'Attention!', + message: 'Check out Cirque du Soleil' }; notifications.update(idString, options2, onUpdateCallback); } - var options = { - type: "basic", - iconUrl: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAA" + - "CNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHw" + - "AAAABJRU5ErkJggg==", - title: "Attention!", - message: "Check out Cirque du Soleil" + const options = { + type: 'basic', + iconUrl: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAA' + + 'CNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHw' + + 'AAAABJRU5ErkJggg==', + title: 'Attention!', + message: 'Check out Cirque du Soleil' }; notifications.create(idString, options, onCreateCallback); } function testCSPUpdateImageURL() { - var onUpdateCallback = function(id) { + const onUpdateCallback = function(id) { if (chrome.runtime.lastError) { chrome.test.succeed(); return; } chrome.test.fail(); }; - var onCreateCallback = function(id) { + const onCreateCallback = function(id) { if (chrome.runtime.lastError) { chrome.test.fail(); return; } - var options2 = { - type: "basic", - iconUrl: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAA" + - "CNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHw" + - "AAAABJRU5ErkJggg==", - imageUrl: "http://www.google.com/favicon.ico", - title: "Attention!", - message: "Check out Cirque du Soleil" + const options2 = { + type: 'basic', + iconUrl: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAA' + + 'CNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHw' + + 'AAAABJRU5ErkJggg==', + imageUrl: 'http://www.google.com/favicon.ico', + title: 'Attention!', + message: 'Check out Cirque du Soleil' }; notifications.update(idString, options2, onUpdateCallback); } - var options = { - type: "image", - iconUrl: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAA" + - "CNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHw" + - "AAAABJRU5ErkJggg==", - imageUrl: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAA" + - "CNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHw" + - "AAAABJRU5ErkJggg==", - title: "Attention!", - message: "Check out Cirque du Soleil" + const options = { + type: 'image', + iconUrl: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAA' + + 'CNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHw' + + 'AAAABJRU5ErkJggg==', + imageUrl: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAA' + + 'CNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHw' + + 'AAAABJRU5ErkJggg==', + title: 'Attention!', + message: 'Check out Cirque du Soleil' }; notifications.create(idString, options, onCreateCallback); } function testCSPUpdateButtonIconURL() { - var onUpdateCallback = function(id) { + const onUpdateCallback = function(id) { if (chrome.runtime.lastError) { chrome.test.succeed(); return; } chrome.test.fail(); }; - var onCreateCallback = function(id) { + const onCreateCallback = function(id) { if (chrome.runtime.lastError) { chrome.test.fail(); return; } - var options2 = { - type: "basic", - iconUrl: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAA" + - "CNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHw" + - "AAAABJRU5ErkJggg==", - title: "Attention!", + const options2 = { + type: 'basic', + iconUrl: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAA' + + 'CNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHw' + + 'AAAABJRU5ErkJggg==', + title: 'Attention!', buttons: [ { - title: "Foo", - iconUrl: "http://www.google.com/favicon.ico" + title: 'Foo', + iconUrl: 'http://www.google.com/favicon.ico' } ], - message: "Check out Cirque du Soleil" + message: 'Check out Cirque du Soleil' }; notifications.update(idString, options2, onUpdateCallback); } - var options = { - type: "basic", - iconUrl: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAA" + - "CNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHw" + - "AAAABJRU5ErkJggg==", - title: "Attention!", + const options = { + type: 'basic', + iconUrl: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAA' + + 'CNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHw' + + 'AAAABJRU5ErkJggg==', + title: 'Attention!', buttons: [ { - title: "Foo", - iconUrl: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAA" + - "CNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHw" + - "AAAABJRU5ErkJggg==" + title: 'Foo', + iconUrl: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAA' + + 'CNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHw' + + 'AAAABJRU5ErkJggg==' } ], - message: "Check out Cirque du Soleil" + message: 'Check out Cirque du Soleil' }; notifications.create(idString, options, onCreateCallback); }
diff --git a/chrome/test/data/extensions/api_test/notifications/api/events/background.js b/chrome/test/data/extensions/api_test/notifications/api/events/background.js index a962d577..31e8a65b 100644 --- a/chrome/test/data/extensions/api_test/notifications/api/events/background.js +++ b/chrome/test/data/extensions/api_test/notifications/api/events/background.js
@@ -4,22 +4,22 @@ const notifications = chrome.notifications; -var idString = "foo"; +const idString = 'foo'; -var testBasicEvents = function() { - var incidents = 0; +const testBasicEvents = function() { + const incidents = 0; - var onCreateCallback = function(id) { + const onCreateCallback = function(id) { chrome.test.assertTrue(id.length > 0); chrome.test.assertEq(idString, id); chrome.test.succeed(); } - var options = { - type: "basic", - iconUrl: "icon.png", - title: "Attention!", - message: "Check out Cirque du Soleil" + const options = { + type: 'basic', + iconUrl: 'icon.png', + title: 'Attention!', + message: 'Check out Cirque du Soleil' }; notifications.create(idString, options, onCreateCallback); };
diff --git a/chrome/test/data/extensions/api_test/notifications/api/partial_update/background.js b/chrome/test/data/extensions/api_test/notifications/api/partial_update/background.js index 562a6de..80253dd 100644 --- a/chrome/test/data/extensions/api_test/notifications/api/partial_update/background.js +++ b/chrome/test/data/extensions/api_test/notifications/api/partial_update/background.js
@@ -9,7 +9,7 @@ if (a == null || b == null) return false; if (a.length !== b.length) return false; - for (var i = 0; i < a.length; i++) { + for (let i = 0; i < a.length; i++) { if (a[i] !== b[i]) return false; } return true; @@ -19,10 +19,10 @@ return new Promise(function (resolve, reject) { notifications.create(id, options, function (id) { if (chrome.runtime.lastError) { - reject(new Error("Unable to create notification")); + reject(new Error('Unable to create notification')); return; } - console.log("Created with id: " + id); + console.log(`Created with id: ${id}`); resolve(id); return; }); @@ -33,10 +33,10 @@ return new Promise(function (resolve, reject) { notifications.update(id, options, function (ok) { if (chrome.runtime.lastError || !ok) { - reject(new Error("Unable to update notification")); + reject(new Error('Unable to update notification')); return; } - console.log("Updated id: ", id); + console.log('Updated id: ', id); resolve(ok); return; }); @@ -47,7 +47,7 @@ return new Promise(function (resolve, reject) { notifications.clear(id, function (ok) { if (chrome.runtime.lastError || !ok) { - reject(new Error("Unable to clear notification")); + reject(new Error('Unable to clear notification')); return; } resolve(ok); @@ -69,15 +69,15 @@ return } - var id_list = Object.keys(ids); - resolve(id_list); + const idList = Object.keys(ids); + resolve(idList); }); }); } function clearAll() { return getAll().then(function (ids) { - var idPromises = ids.map(function (id) { return clear(id); }); + const idPromises = ids.map(function (id) { return clear(id); }); return Promise.all(idPromises); }); } @@ -87,7 +87,7 @@ return clearAll().then( function () { chrome.test.succeed(testName); }, function (error) { - console.log("Unknown error in clearAll: " + + console.log('Unknown error in clearAll: ' + JSON.stringify(arguments)); }); }; @@ -98,44 +98,44 @@ return clearAll().then( function () { chrome.test.fail(testName); }, function (error) { - console.log("Unknown error in clearAll: " + + console.log('Unknown error in clearAll: ' + JSON.stringify(error.message)); }); }; } function testPartialUpdate() { - var testName = "testPartialUpdate"; - console.log("Starting " + testName); - var succeed = succeedTest(testName); - var fail = failTest(testName); + const testName = 'testPartialUpdate'; + console.log(`Starting ${testName}`); + const succeed = succeedTest(testName); + const fail = failTest(testName); - const red_dot = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA" + - "AAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO" + - "9TXL0Y4OHwAAAABJRU5ErkJggg=="; + const redDot = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA' + + 'AAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO' + + '9TXL0Y4OHwAAAABJRU5ErkJggg=='; - var basicNotificationOptions = { - type: "basic", - title: "Basic title", - message: "Basic message", - iconUrl: red_dot, + const basicNotificationOptions = { + type: 'basic', + title: 'Basic title', + message: 'Basic message', + iconUrl: redDot, silent: false, - buttons: [{title: "Button"}] + buttons: [{title: 'Button'}] }; // Create a notification. - create("testId", basicNotificationOptions) + create('testId', basicNotificationOptions) // Then update a few items .then(function() { - return update("testId", { - title: "Changed!", - message: "Too late! The show ended yesterday", + return update('testId', { + title: 'Changed!', + message: 'Too late! The show ended yesterday', silent: true }); }) // Then update a few more items .then(function() { - return update("testId", {priority: 2, buttons: [{title: "NewButton"}]}); + return update('testId', {priority: 2, buttons: [{title: 'NewButton'}]}); }) // The test will continue in C++, checking that all the updates "took" .then(chrome.test.succeed, chrome.test.fail);
diff --git a/chrome/test/data/extensions/api_test/notifications/api/permission/background.js b/chrome/test/data/extensions/api_test/notifications/api/permission/background.js index 4d2372d..2252282 100644 --- a/chrome/test/data/extensions/api_test/notifications/api/permission/background.js +++ b/chrome/test/data/extensions/api_test/notifications/api/permission/background.js
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -var currentPermissionLevel = ""; +let currentPermissionLevel = ''; function onGetPermissionLevel(permissionLevel) { currentPermissionLevel = permissionLevel; @@ -13,15 +13,15 @@ } function onPermissionLevelChangedListener(permissionLevel) { - if (permissionLevel != "denied" && permissionLevel != "granted") { + if (permissionLevel != 'denied' && permissionLevel != 'granted') { chrome.test.notifyFail( - "Unexpected permission level " + permissionLevel + " received"); + `Unexpected permission level ${permissionLevel} received`); return; } if (permissionLevel == currentPermissionLevel) { chrome.test.notifyFail( - "Same permission level " + permissionLevel + " received"); + `Same permission level ${permissionLevel} received`); return; }
diff --git a/chrome/test/data/extensions/api_test/notifications/galore/app/controller.js b/chrome/test/data/extensions/api_test/notifications/galore/app/controller.js index 914c36c..af47711a 100644 --- a/chrome/test/data/extensions/api_test/notifications/galore/app/controller.js +++ b/chrome/test/data/extensions/api_test/notifications/galore/app/controller.js
@@ -2,33 +2,33 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -var STOPPED = "Stopped"; -var RECORDING = "Recording"; -var PAUSED_RECORDING = "Recording Paused"; -var PAUSED_PLAYING = "Playing Paused"; -var PLAYING = "Playing"; +const STOPPED = 'Stopped'; +const RECORDING = 'Recording'; +const PAUSED_RECORDING = 'Recording Paused'; +const PAUSED_PLAYING = 'Playing Paused'; +const PLAYING = 'Playing'; -var recordingState = STOPPED; +let recordingState = STOPPED; // Timestamp when current segment started. -var segmentStart; +let segmentStart; // Segment duration accumulated before pause button was hit. -var pausedDuration; +let pausedDuration; // The array of segments, with delay and action. -var recordingList; +let recordingList; // When this timer fires, the next segment from recordingList should be played. -var playingTimer; -var currentSegmentIndex; +let playingTimer; +let currentSegmentIndex; // A set of web Notifications - used to delete them during playback by id. -var webNotifications = {}; +let webNotifications = {}; -var recorderButtons = [ "play", "record", "pause", "stop"]; -var recorderButtonStates = [ - { state: STOPPED, enabled: "play record" }, - { state: RECORDING, enabled: "pause stop" }, - { state: PAUSED_RECORDING, enabled: "record stop" }, - { state: PAUSED_PLAYING, enabled: "play stop" }, - { state: PLAYING, enabled: "pause stop" } +const recorderButtons = [ 'play', 'record', 'pause', 'stop']; +const recorderButtonStates = [ + { state: STOPPED, enabled: 'play record' }, + { state: RECORDING, enabled: 'pause stop' }, + { state: PAUSED_RECORDING, enabled: 'record stop' }, + { state: PAUSED_PLAYING, enabled: 'play stop' }, + { state: PLAYING, enabled: 'pause stop' } ]; // This function forms 2 selector lists - one that includes enabled buttons @@ -41,24 +41,24 @@ // Found entry with current recorder state. Now compute the sets // of enabled/disabled buttons. // Copy a list of all buttons. - var disabled = recorderButtons.slice(0); + const disabled = recorderButtons.slice(0); // Get an array of enabled buttons for the state. - var enabled = entry.enabled.split(" "); + const enabled = entry.enabled.split(' '); // Remove enabled buttons from disabled list, prefix them with "#" so they // form proper id selectors. - for (var i = 0; i < enabled.length; i++) { + for (let i = 0; i < enabled.length; i++) { disabled.splice(disabled.indexOf(enabled[i]), 1); - enabled[i] = "#" + enabled[i]; + enabled[i] = `#${enabled[i]}`; } // Prefix remaining disabled ids to form proper id selectors. - for (var i = 0; i < disabled.length; i++) { - disabled[i] = "#" + disabled[i]; + for (let i = 0; i < disabled.length; i++) { + disabled[i] = `#${disabled[i]}`; } - getElements(disabled.join(", ")).forEach(function(element) { - element.setAttribute("disabled", "true") + getElements(disabled.join(', ')).forEach(function(element) { + element.setAttribute('disabled', 'true') }) - getElements(enabled.join(", ")).forEach(function(element) { - element.removeAttribute("disabled") + getElements(enabled.join(', ')).forEach(function(element) { + element.removeAttribute('disabled') }) }) } @@ -71,32 +71,32 @@ } function updateRecordingStats(context) { - var length = 0; - var segmentCnt = 0; + let length = 0; + let segmentCnt = 0; recordingList.slice(currentSegmentIndex).forEach(function(segment) { length += segment.delay || 0; segmentCnt++; }) - updateRecordingStatsDisplay(context + ": " + (segmentCnt-1) + " segments, " + - Math.floor(length/1000) + " seconds."); + updateRecordingStatsDisplay(context + ': ' + (segmentCnt-1) + ' segments, ' + + Math.floor(length/1000) + ' seconds.'); } function loadRecording() { - chrome.storage.local.get("recording", function(items) { - recordingList = JSON.parse(items["recording"] || "[]"); + chrome.storage.local.get('recording', function(items) { + recordingList = JSON.parse(items['recording'] || '[]'); setRecordingState(STOPPED); - updateRecordingStats("Loaded record"); + updateRecordingStats('Loaded record'); }) } function finalizeRecording() { - chrome.storage.local.set({"recording": JSON.stringify(recordingList)}); - updateRecordingStats("Recorded"); + chrome.storage.local.set({recording: JSON.stringify(recordingList)}); + updateRecordingStats('Recorded'); } function setPreviousSegmentDuration() { - var now = new Date().getTime(); - var delay = now - segmentStart; + const now = new Date().getTime(); + let delay = now - segmentStart; segmentStart = now; recordingList[recordingList.length - 1].delay = delay; } @@ -105,8 +105,8 @@ if(obj == null || typeof(obj) != 'object') return obj; - var temp = {}; - for(var key in obj) + const temp = {}; + for(let key in obj) temp[key] = cloneOptions(obj[key]); return temp; } @@ -116,8 +116,8 @@ return; setPreviousSegmentDuration(); recordingList.push( - { type: "create", kind: kind, id: id, options: cloneOptions(options) }); - updateRecordingStats("Recording"); + { type: 'create', kind: kind, id: id, options: cloneOptions(options) }); + updateRecordingStats('Recording'); } function recordUpdate(kind, id, options) { @@ -125,16 +125,16 @@ return; setPreviousSegmentDuration(); recordingList.push( - { type: "update", kind: kind, id: id, options: cloneOptions(options) }); - updateRecordingStats("Recording"); + { type: 'update', kind: kind, id: id, options: cloneOptions(options) }); + updateRecordingStats('Recording'); } function recordDelete(kind, id) { if (recordingState != RECORDING) return; setPreviousSegmentDuration(); - recordingList.push({ type: "delete", kind: kind, id: id }); - updateRecordingStats("Recording"); + recordingList.push({ type: 'delete', kind: kind, id: id }); + updateRecordingStats('Recording'); } function startPlaying() { @@ -150,28 +150,28 @@ currentSegmentIndex = 0; playingTimer = setTimeout(playNextSegment, recordingList[currentSegmentIndex].delay); - updateRecordingStats("Playing"); + updateRecordingStats('Playing'); } function playNextSegment() { currentSegmentIndex++; - var segment = recordingList[currentSegmentIndex]; + const segment = recordingList[currentSegmentIndex]; if (!segment) { stopPlaying(); return; } - if (segment.type == "create") { + if (segment.type == 'create') { createNotificationForPlay(segment.kind, segment.id, segment.options); - } else if (segment.type == "update") { + } else if (segment.type == 'update') { updateNotificationForPlay(segment.kind, segment.id, segment.options); - } else { // type == "delete" + } else { // type == 'delete' deleteNotificationForPlay(segment.kind, segment.id); } playingTimer = setTimeout(playNextSegment, recordingList[currentSegmentIndex].delay); segmentStart = new Date().getTime(); - updateRecordingStats("Playing"); + updateRecordingStats('Playing'); } function deleteNotificationForPlay(kind, id) { @@ -188,8 +188,8 @@ if (kind == 'web') { webNotifications[id] = createWebNotification(id, options); } else { - var type = options.type; - var priority = options.priority; + let type = options.type; + const priority = options.priority; createRichNotification(id, type, priority, options); } } @@ -198,8 +198,8 @@ if (kind == 'web') { // TODO: implement update. } else { - var type = options.type; - var priority = options.priority; + let type = options.type; + const priority = options.priority; updateRichNotification(id, type, priority, options); } } @@ -207,7 +207,7 @@ function stopPlaying() { currentSegmentIndex = 0; clearTimeout(playingTimer); - updateRecordingStats("Record"); + updateRecordingStats('Record'); setRecordingState(STOPPED); } @@ -218,7 +218,7 @@ } function unpausePlaying() { - var remainingInSegment = + let remainingInSegment = recordingList[currentSegmentIndex].delay - pausedDuration; if (remainingInSegment < 0) remainingInSegment = 0; @@ -232,14 +232,14 @@ pausedDuration = 0; // This item is only needed to keep a duration of the delay between start // and first action. - recordingList = [ { type:"start" } ]; + recordingList = [ { type:'start' } ]; } else if (recordingState == PAUSED_RECORDING) { segmentStart = new Date().getTime() - pausedDuration; pausedDuration = 0; } else { return; } - updateRecordingStats("Recording"); + updateRecordingStats('Recording'); setRecordingState(RECORDING); } @@ -291,8 +291,8 @@ function onSettingsFetched(items) { settings = items.settings || settings; - var request = new XMLHttpRequest(); - var source = '/data/data.json'; + const request = new XMLHttpRequest(); + const source = '/data/data.json'; request.open('GET', source, true); request.responseType = 'text'; request.onload = onDataFetched; @@ -300,12 +300,12 @@ } function onDataFetched() { - var data = JSON.parse(this.response); + const data = JSON.parse(this.response); createAppWindow(function() { // Create notification buttons. data.forEach(function(section) { - var type = section.notificationType; - if (type == "progress") { + let type = section.notificationType; + if (type == 'progress') { addProgressControl(section.sectionName); } (section.notificationOptions || []).forEach(function(options) { @@ -326,17 +326,17 @@ } function scheduleNextProgress(id, priority, options, progress, step, timeout) { - var new_progress = progress + step; - if (new_progress > 100) - new_progress = 100; - setTimeout(nextProgress(id, priority, options, new_progress, step, timeout), + let newProgress = progress + step; + if (newProgress > 100) + newProgress = 100; + setTimeout(nextProgress(id, priority, options, newProgress, step, timeout), timeout); } function nextProgress(id, priority, options, progress, step, timeout) { return (function() { - options["progress"] = progress; - updateRichNotification(id, "progress", priority, options); + options['progress'] = progress; + updateRichNotification(id, 'progress', priority, options); if (progress >= 100) return; scheduleNextProgress(id, priority, options, progress, step, timeout) @@ -344,19 +344,19 @@ } function createNotification(type, options) { - var id = getNextId(); - var priority = Number(settings.priority || 0); + const id = getNextId(); + const priority = Number(settings.priority || 0); if (type == 'web') createWebNotification(id, options); else { - if (type == "progress") { + if (type == 'progress') { if (getElement('#progress-oneshot').checked) { - options["progress"] = Number(getElement('#progress').value); + options['progress'] = Number(getElement('#progress').value); } else { - var step = Number(getElement('#progress-step').value); - options["progress"] = step; - if (options["progress"] < 100) { - scheduleNextProgress(id, priority, options, options["progress"], step, + const step = Number(getElement('#progress-step').value); + options['progress'] = step; + if (options['progress'] < 100) { + scheduleNextProgress(id, priority, options, options['progress'], step, Number(getElement('#progress-sec').value) * 1000); } } @@ -366,18 +366,18 @@ } function createWebNotification(id, options) { - var iconUrl = options.iconUrl; - var title = options.title; - var message = options.message; - var n = new Notification(title, { + const iconUrl = options.iconUrl; + const title = options.title; + const message = options.message; + const n = new Notification(title, { body: message, icon: iconUrl, tag: id }); - n.onshow = function() { logEvent('WebNotification #' + id + ': onshow'); } - n.onclick = function() { logEvent('WebNotification #' + id + ': onclick'); } + n.onshow = function() { logEvent(`WebNotification #${id}: onshow`); } + n.onclick = function() { logEvent(`WebNotification #${id}: onclick`); } n.onclose = function() { - logEvent('WebNotification #' + id + ': onclose'); + logEvent(`WebNotification #${id}: onclose`); recordDelete('web', id); } logMethodCall('created', 'Web', id, 'title: "' + title + '"'); @@ -386,30 +386,30 @@ } function createRichNotification(id, type, priority, options) { - options["type"] = type; - options["priority"] = priority; + options['type'] = type; + options['priority'] = priority; chrome.notifications.create(id, options, function() { - var argument1 = 'type: "' + type + '"'; - var argument2 = 'priority: ' + priority; - var argument3 = 'title: "' + options.title + '"'; + const argument1 = 'type: "' + type + '"'; + const argument2 = `priority: ${priority}`; + const argument3 = 'title: "' + options.title + '"'; logMethodCall('created', 'Rich', id, argument1, argument2, argument3); }); recordCreate('rich', id, options); } function updateRichNotification(id, type, priority, options) { - options["type"] = type; - options["priority"] = priority; + options['type'] = type; + options['priority'] = priority; chrome.notifications.update(id, options, function() { - var argument1 = 'type: "' + type + '"'; - var argument2 = 'priority: ' + priority; - var argument3 = 'title: "' + options.title + '"'; + const argument1 = 'type: "' + type + '"'; + const argument2 = `priority: ${priority}`; + const argument3 = 'title: "' + options.title + '"'; logMethodCall('updated', 'Rich', id, argument1, argument2, argument3); }); recordUpdate('rich', id, options); } -var counter = 0; +let counter = 0; function getNextId() { return String(counter++); } @@ -420,20 +420,20 @@ chrome.notifications.onButtonClicked.addListener(onButtonClicked); } -function logMethodCall(method, kind, id, var_args) { - logEvent(kind + ' Notification #' + id + ': ' + method + ' (' + - Array.prototype.slice.call(arguments, 2).join(', ') + ')'); +function logMethodCall(method, kind, id, varArgs) { + logEvent(`${kind} Notification #${id}: ${method} ` + + `(${Array.prototype.slice.call(arguments, 2).join(', ')})`); } function onClosed(id) { - logEvent('Notification #' + id + ': onClosed'); + logEvent(`Notification #${id}: onClosed`); recordDelete('rich', id); } function onClicked(id) { - logEvent('Notification #' + id + ': onClicked'); + logEvent(`Notification #${id}: onClicked`); } function onButtonClicked(id, index) { - logEvent('Notification #' + id + ': onButtonClicked, btn: ' + index); + logEvent(`Notification #${id}: onButtonClicked, btn: ${index}`); }
diff --git a/chrome/test/data/extensions/api_test/notifications/galore/app/view.js b/chrome/test/data/extensions/api_test/notifications/galore/app/view.js index d6dd169..d9ca95b 100644 --- a/chrome/test/data/extensions/api_test/notifications/galore/app/view.js +++ b/chrome/test/data/extensions/api_test/notifications/galore/app/view.js
@@ -2,15 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -var mainWindow; -var sections = []; +let mainWindow; +let sections = []; -var settings = {} +const settings = {} // Initial values. -settings.priority = "0"; +settings.priority = '0'; settings.progress = 10; -settings.progress_sec = 2; -settings.progress_step = 20; +settings.progressSec = 2; +settings.progressStep = 20; function onMainWindowClosed() { mainWindow = null; @@ -27,7 +27,7 @@ mainWindow = w; mainWindow.contentWindow.onload = function() { setButtonHandlers(); - getElement("body").dataset.priority = settings.priority; + getElement('body').dataset.priority = settings.priority; onLoad(); }; mainWindow.onClosed.addListener(onMainWindowClosed) @@ -35,14 +35,14 @@ } function resovleImageUrl(imageUrl, callback) { - if (imageUrl.substr(0,4) != "http") { + if (imageUrl.substr(0,4) != 'http') { callback(imageUrl); return; } - var xhr = new XMLHttpRequest(); - xhr.open("GET", imageUrl); - xhr.responseType = "blob"; + const xhr = new XMLHttpRequest(); + xhr.open('GET', imageUrl); + xhr.responseType = 'blob'; xhr.onload = function() { callback(URL.createObjectURL(this.response)); } @@ -53,8 +53,8 @@ buttonTitle, iconUrl, onClickHandler) { - var button = getElement('#templates .notification').cloneNode(true); - var image = button.querySelector('img'); + const button = getElement('#templates .notification').cloneNode(true); + const image = button.querySelector('img'); resovleImageUrl(iconUrl, function(url) { image.src = url }); image.src = iconUrl; image.alt = buttonTitle; @@ -64,24 +64,24 @@ } function addProgressControl(sectionTitle) { - var control = getElement('#templates .progress-control').cloneNode(true); + const control = getElement('#templates .progress-control').cloneNode(true); getSection(sectionTitle).appendChild(control) - var progress = control.querySelector('.progress'); - progress.id = "progress" + const progress = control.querySelector('.progress'); + progress.id = 'progress' progress.value = settings.progress; - var progress_oneshot = control.querySelector('.progress-oneshot'); - progress_oneshot.id = 'progress-oneshot'; - progress_oneshot.checked = true; + const progressOneshot = control.querySelector('.progress-oneshot'); + progressOneshot.id = 'progress-oneshot'; + progressOneshot.checked = true; - var progress_sec = control.querySelector('.progress-sec'); - progress_sec.id = "progress-sec" - progress_sec.value = settings.progress_sec; + const progressSec = control.querySelector('.progress-sec'); + progressSec.id = 'progress-sec' + progressSec.value = settings.progressSec; - var progress_step = control.querySelector('.progress-step'); - progress_step.id = "progress-step" - progress_step.value = settings.progress_step; + const progressStep = control.querySelector('.progress-step'); + progressStep.id = 'progress-step' + progressStep.value = settings.progressStep; } function showWindow() { @@ -90,14 +90,14 @@ } function logEvent(message) { - var event = getElement('#templates .event').cloneNode(true); + const event = getElement('#templates .event').cloneNode(true); event.textContent = message; getElement('#events').appendChild(event).scrollIntoView(); } function logError(message) { - var events = getElement('#events'); - var error = getElement('#templates .error').cloneNode(true); + const events = getElement('#events'); + const error = getElement('#templates .error').cloneNode(true); error.textContent = message; events.appendChild(error).scrollIntoView(); } @@ -111,15 +111,15 @@ } function setRecorderStatusText(text) { - getElement("#recording-status").innerText = text; + getElement('#recording-status').innerText = text; } function updateRecordingStatsDisplay(text) { - getElement("#recording-stats").innerText = text; + getElement('#recording-stats').innerText = text; } function clearEvents() { - var events = getElement('#events'); + const events = getElement('#events'); while (events.lastChild) events.removeChild(events.lastChild); } @@ -130,7 +130,7 @@ } function makeSection(title) { - var section = getElement('#templates .section').cloneNode(true); + const section = getElement('#templates .section').cloneNode(true); section.querySelector('span').textContent = title; return getElement('#notifications').appendChild(section); }
diff --git a/chrome/test/data/extensions/api_test/offscreen/basic_document_management/background.js b/chrome/test/data/extensions/api_test/offscreen/basic_document_management/background.js index 4e0575e..28397f2 100644 --- a/chrome/test/data/extensions/api_test/offscreen/basic_document_management/background.js +++ b/chrome/test/data/extensions/api_test/offscreen/basic_document_management/background.js
@@ -19,7 +19,7 @@ } self.addEventListener('fetch', (e) => { - var url = new URL(e.request.url); + const url = new URL(e.request.url); if (url.pathname == '/request_handled_by_sw.html') { e.respondWith(new Response('<html>Hello, world!</html>')); }
diff --git a/chrome/test/data/extensions/api_test/offscreen/tab_capture_streams/background.js b/chrome/test/data/extensions/api_test/offscreen/tab_capture_streams/background.js index 7d2a718..df3dd55 100644 --- a/chrome/test/data/extensions/api_test/offscreen/tab_capture_streams/background.js +++ b/chrome/test/data/extensions/api_test/offscreen/tab_capture_streams/background.js
@@ -5,7 +5,7 @@ let didCapture = false; let didStopCapture = false; let onStoppedCapture; -let captureStopped = new Promise((resolve) => { +const captureStopped = new Promise((resolve) => { onStoppedCapture = resolve; });
diff --git a/chrome/test/data/extensions/api_test/omnibox/test.js b/chrome/test/data/extensions/api_test/omnibox/test.js index cce49d4..f9449ad 100644 --- a/chrome/test/data/extensions/api_test/omnibox/test.js +++ b/chrome/test/data/extensions/api_test/omnibox/test.js
@@ -2,46 +2,46 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -var incognito = chrome.extension.inIncognitoContext; -var incognitoSuffix = incognito ? " incognito" : ""; +const incognito = chrome.extension.inIncognitoContext; +const incognitoSuffix = incognito ? ' incognito' : ''; chrome.omnibox.onInputChanged.addListener( function(text, suggest) { - chrome.test.log("onInputChanged: " + text); - if (text == "suggestio") { - // First test, complete "suggestio" - var desc = 'Description with style: <match><match></match>, ' + + chrome.test.log(`onInputChanged: ${text}`); + if (text == 'suggestio') { + // First test, complete 'suggestio' + const desc = 'Description with style: <match><match></match>, ' + '<dim>[dim]</dim>, <url>(url till end)</url>'; suggest([ - {content: text + "n1", description: desc}, - {content: text + "n2", description: "description2"}, - {content: text + "n3" + incognitoSuffix, description: "description3"}, + {content: `${text}n1`, description: desc}, + {content: `${text}n2`, description: 'description2'}, + {content: `${text}n3${incognitoSuffix}`, description: 'description3'}, ]); - } else if("d") { + } else if('d') { suggest([ - {content: "n1", description: "des1", deletable: true}, - {content: "n2", description: "des2", deletable: false}, + {content: 'n1', description: 'des1', deletable: true}, + {content: 'n2', description: 'des2', deletable: false}, ]); } else { // Other tests, just provide a simple suggestion. - suggest([{content: text + " 1", description: "description"}]); + suggest([{content: `${text} 1`, description: 'description'}]); } }); chrome.omnibox.onInputEntered.addListener( function(text, disposition) { - if (disposition == "newForegroundTab") { - chrome.test.assertEq("newtab" + incognitoSuffix, text); + if (disposition == 'newForegroundTab') { + chrome.test.assertEq(`newtab${incognitoSuffix}`, text); chrome.test.notifyPass(); } else { - chrome.test.assertEq("command" + incognitoSuffix, text); + chrome.test.assertEq(`command${incognitoSuffix}`, text); chrome.test.notifyPass(); } }); chrome.omnibox.onDeleteSuggestion.addListener( function(text) { - chrome.test.sendMessage("onDeleteSuggestion: " + text); + chrome.test.sendMessage(`onDeleteSuggestion: ${text}`); }); // Now we wait for the input events to fire.
diff --git a/chrome/test/data/extensions/api_test/page_action/basics/update.js b/chrome/test/data/extensions/api_test/page_action/basics/update.js index 013790d..ae20e17 100644 --- a/chrome/test/data/extensions/api_test/page_action/basics/update.js +++ b/chrome/test/data/extensions/api_test/page_action/basics/update.js
@@ -7,7 +7,7 @@ chrome.tabs.query({active: true}, function(tabs) { const tab = tabs[0]; chrome.pageAction.show(tab.id); - chrome.pageAction.setTitle({title: "Modified", tabId: tab.id}); + chrome.pageAction.setTitle({title: 'Modified', tabId: tab.id}); chrome.test.notifyPass(); });
diff --git a/chrome/test/data/extensions/api_test/page_action/basics/update2.js b/chrome/test/data/extensions/api_test/page_action/basics/update2.js index ee14360..e2629c0 100644 --- a/chrome/test/data/extensions/api_test/page_action/basics/update2.js +++ b/chrome/test/data/extensions/api_test/page_action/basics/update2.js
@@ -7,7 +7,7 @@ const tab = tabs[0]; chrome.pageAction.show(tab.id); chrome.pageAction.setIcon({tabId: tab.id, - imageData:document.getElementById("canvas") + imageData:document.getElementById('canvas') .getContext('2d').getImageData(0, 0, 16, 16)}); chrome.test.notifyPass(); });
diff --git a/chrome/test/data/extensions/api_test/page_action/getters/update.js b/chrome/test/data/extensions/api_test/page_action/getters/update.js index ebad0de8..3d6cfe7 100644 --- a/chrome/test/data/extensions/api_test/page_action/getters/update.js +++ b/chrome/test/data/extensions/api_test/page_action/getters/update.js
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -var pass = chrome.test.callbackPass; +const pass = chrome.test.callbackPass; chrome.tabs.query({active: true}, function(tabs) { const tab = tabs[0]; @@ -16,7 +16,7 @@ function getTitle() { chrome.pageAction.getTitle({tabId: tab.id}, pass(function(result) { - chrome.test.assertEq("Title", result); + chrome.test.assertEq('Title', result); })); } ]);
diff --git a/chrome/test/data/extensions/api_test/page_action/hash_change/background.js b/chrome/test/data/extensions/api_test/page_action/hash_change/background.js index 68d6d63..d4c55c86 100644 --- a/chrome/test/data/extensions/api_test/page_action/hash_change/background.js +++ b/chrome/test/data/extensions/api_test/page_action/hash_change/background.js
@@ -3,25 +3,25 @@ // found in the LICENSE file. // This makes sure we only enable the page action once per tab. -var hasEnabled = {}; +const hasEnabled = {}; chrome.runtime.onMessage.addListener(function(request, sender) { - if (request.msg == "feedIcon") { - console.log('url: ' + sender.tab.url); + if (request.msg == 'feedIcon') { + console.log(`url: ${sender.tab.url}`); if (!hasEnabled[sender.tab.id]) { - console.log('Enabling for ' + sender.tab.id); + console.log(`Enabling for ${sender.tab.id}`); // We have received a list of feed urls found on the page. // Enable the page action icon. - chrome.pageAction.setTitle({ tabId: sender.tab.id, - title: "Page action..."}); + chrome.pageAction.setTitle( + {tabId: sender.tab.id, title: 'Page action...'}); chrome.pageAction.show(sender.tab.id); hasEnabled[sender.tab.id] = true; hasEnabledLastTabId = sender.tab.id; } else { - console.log('We are not doing this more than once (for ' + - sender.tab.id + ')'); + console.log( + `We are not doing this more than once (for ${sender.tab.id})`); } } });
diff --git a/chrome/test/data/extensions/api_test/page_action/hash_change/script.js b/chrome/test/data/extensions/api_test/page_action/hash_change/script.js index 184f390..b1cb4c7 100644 --- a/chrome/test/data/extensions/api_test/page_action/hash_change/script.js +++ b/chrome/test/data/extensions/api_test/page_action/hash_change/script.js
@@ -4,4 +4,4 @@ // Notify the extension needs to show the page action icon. -chrome.runtime.sendMessage({msg: "feedIcon"}); +chrome.runtime.sendMessage({msg: 'feedIcon'});
diff --git a/chrome/test/data/extensions/api_test/page_action/popup/popup.js b/chrome/test/data/extensions/api_test/page_action/popup/popup.js index 05e147cd..0e244d4 100644 --- a/chrome/test/data/extensions/api_test/page_action/popup/popup.js +++ b/chrome/test/data/extensions/api_test/page_action/popup/popup.js
@@ -4,8 +4,8 @@ // Wait to be resized by the browser once before indicating pass. function onResize() { - window.removeEventListener("resize", onResize); + window.removeEventListener('resize', onResize); chrome.test.notifyPass(); } -window.addEventListener("resize", onResize); +window.addEventListener('resize', onResize);
diff --git a/chrome/test/data/extensions/api_test/page_action/simple/background.js b/chrome/test/data/extensions/api_test/page_action/simple/background.js index a9ddd7b..33b2b7e 100644 --- a/chrome/test/data/extensions/api_test/page_action/simple/background.js +++ b/chrome/test/data/extensions/api_test/page_action/simple/background.js
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -var tabId = -1; +let tabId = -1; chrome.pageAction.onClicked.addListener(function(tab) { chrome.pageAction.hide(tabId);
diff --git a/chrome/test/data/extensions/api_test/page_capture/test.js b/chrome/test/data/extensions/api_test/page_capture/test.js index fd162123..ecb7e91 100644 --- a/chrome/test/data/extensions/api_test/page_capture/test.js +++ b/chrome/test/data/extensions/api_test/page_capture/test.js
@@ -8,7 +8,7 @@ const assertEq = chrome.test.assertEq; const assertTrue = chrome.test.assertTrue; -var testUrl = 'http://www.a.com:PORT' + +let testUrl = 'http://www.a.com:PORT' + '/extensions/api_test/page_capture/google.html'; function verifyPageCapture(data, isFile) { @@ -16,10 +16,10 @@ assertTrue(data != null); // It should contain few KBs of data. assertTrue(data.size > 100); - var reader = new FileReader(); + const reader = new FileReader(); // Let's make sure it contains some well known strings. reader.onload = function(e) { - var text = e.target.result; + const text = e.target.result; if (!isFile) { assertTrue(text.indexOf(testUrl) != -1); assertTrue(text.indexOf('logo.png') != -1); @@ -56,7 +56,7 @@ }, function saveAsMHTML_FileAccessRequiredForFileUrls() { - var captureUrl = config.testDataDirectory + '/'; + const captureUrl = `${config.testDataDirectory}/`; chrome.tabs.onUpdated.addListener(function listener( tabId, changeInfo, tab) { if (tab.status == 'complete' && tab.url == captureUrl) {
diff --git a/chrome/test/data/extensions/api_test/panels/focus_change_on_minimize/test.js b/chrome/test/data/extensions/api_test/panels/focus_change_on_minimize/test.js index c742f3fd..679376e 100644 --- a/chrome/test/data/extensions/api_test/panels/focus_change_on_minimize/test.js +++ b/chrome/test/data/extensions/api_test/panels/focus_change_on_minimize/test.js
@@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -var waitingForFocus = true; -var panelWinId = chrome.windows.WINDOW_ID_NONE; -var focusedWinId = chrome.windows.WINDOW_ID_NONE; -var listenDoneCallback; +let waitingForFocus = true; +let panelWinId = chrome.windows.WINDOW_ID_NONE; +let focusedWinId = chrome.windows.WINDOW_ID_NONE; +let listenDoneCallback; // Focus change event handler to watch for created panel to gain focus. // Then minimize the panel and wait for it to lose focus by watching @@ -31,7 +31,7 @@ function minimizePanel() { chrome.test.assertEq(focusedWinId, panelWinId); waitingForFocus = false; - chrome.windows.update(panelWinId, {'state': 'minimized'}, + chrome.windows.update(panelWinId, {state: 'minimized'}, chrome.test.callbackPass(function(win) { chrome.test.assertEq('minimized', win.state); })); @@ -39,7 +39,7 @@ // Activate panel so we can minimize it. function activatePanel() { - chrome.windows.update(panelWinId, {'focused': true}, + chrome.windows.update(panelWinId, {focused: true}, chrome.test.callbackPass(function(win) { })); } @@ -49,7 +49,7 @@ listenDoneCallback = chrome.test.listenForever( chrome.windows.onFocusChanged, onFocusChanged); chrome.windows.create( - {'url': 'about:blank','type': 'panel'}, + {url: 'about:blank',type: 'panel'}, chrome.test.callbackPass(function(win) { chrome.test.assertEq('panel', win.type); chrome.test.assertEq(true, win.alwaysOnTop);
diff --git a/chrome/test/data/extensions/api_test/parent_target_permissions/background.js b/chrome/test/data/extensions/api_test/parent_target_permissions/background.js index 857d60f..5d6ccf80 100644 --- a/chrome/test/data/extensions/api_test/parent_target_permissions/background.js +++ b/chrome/test/data/extensions/api_test/parent_target_permissions/background.js
@@ -7,9 +7,9 @@ chrome.test.getConfig(config => chrome.test.runTests([ async function testParentTargetPermissions() { const fileFrameURL = - config.testDataDirectory + '/parent_target_permissions/top_page.html'; + `${config.testDataDirectory}/parent_target_permissions/top_page.html`; const subframeURL = chrome.runtime.getURL('subframe.html'); - chrome.test.openFileUrl(fileFrameURL + '?' + subframeURL); + chrome.test.openFileUrl(`${fileFrameURL}?${subframeURL}`); await new Promise(resolve => { chrome.runtime.onMessage.addListener(message => { if (message === 'ready')
diff --git a/chrome/test/data/extensions/api_test/passwords_private/test.js b/chrome/test/data/extensions/api_test/passwords_private/test.js index 097404cd..a7cec0f 100644 --- a/chrome/test/data/extensions/api_test/passwords_private/test.js +++ b/chrome/test/data/extensions/api_test/passwords_private/test.js
@@ -14,7 +14,7 @@ 'is not authenticated or no matching password could be found for the ' + 'id.'; -var availableTests = [ +const availableTests = [ function getUrlCollectionWhenUrlValidSucceeds() { chrome.passwordsPrivate.getUrlCollection( 'https://example.com', urlCollection => { @@ -141,9 +141,9 @@ }, function removeAndUndoRemoveSavedPassword() { - var numCalls = 0; - var numSavedPasswords; - var callback = function(savedPasswordsList) { + let numCalls = 0; + let numSavedPasswords; + const callback = function(savedPasswordsList) { numCalls++; if (numCalls == 1) { @@ -166,14 +166,14 @@ }, function removePasskey() { - var numCalls = 0; - var numSavedCredentials; - var callback = function(credentials) { + let numCalls = 0; + let numSavedCredentials; + const callback = function(credentials) { numCalls++; if (numCalls == 1) { numSavedCredentials = credentials.length; - var passkey = credentials[numSavedCredentials - 1]; + const passkey = credentials[numSavedCredentials - 1]; chrome.test.assertTrue(passkey.isPasskey); chrome.passwordsPrivate.removeCredential(passkey.id, passkey.storedIn); @@ -190,9 +190,9 @@ }, function removeAndUndoRemovePasswordException() { - var numCalls = 0; - var numPasswordExceptions; - var callback = function(passwordExceptionsList) { + let numCalls = 0; + let numPasswordExceptions; + const callback = function(passwordExceptionsList) { numCalls++; if (numCalls == 1) { @@ -263,13 +263,13 @@ }, function getSavedPasswordList() { - var callback = function(list) { + const callback = function(list) { chrome.test.assertTrue(!!list); chrome.test.assertTrue(list.length > 0); - var idSet = new Set(); - for (var i = 0; i < list.length; ++i) { - var entry = list[i]; + const idSet = new Set(); + for (let i = 0; i < list.length; ++i) { + const entry = list[i]; chrome.test.assertTrue(!!entry); chrome.test.assertEq(1, entry.affiliatedDomains.length); idSet.add(entry.id); @@ -285,13 +285,13 @@ }, function getPasswordExceptionList() { - var callback = function(list) { + const callback = function(list) { chrome.test.assertTrue(!!list); chrome.test.assertTrue(list.length > 0); - var idSet = new Set(); - for (var i = 0; i < list.length; ++i) { - var exception = list[i]; + const idSet = new Set(); + for (let i = 0; i < list.length; ++i) { + const exception = list[i]; chrome.test.assertTrue(!!exception.urls.signonRealm); chrome.test.assertTrue(!!exception.urls.shown); chrome.test.assertTrue(!!exception.urls.link); @@ -308,7 +308,7 @@ }, function fetchFamilyMembers() { - let callback = function(familyFetchResults) { + const callback = function(familyFetchResults) { chrome.test.assertNoLastError(); chrome.test.assertTrue(!!familyFetchResults); chrome.test.assertEq( @@ -339,7 +339,7 @@ }, function importPasswords() { - let callback = function(importResults) { + const callback = function(importResults) { chrome.test.assertNoLastError(); chrome.test.assertTrue(!!importResults); chrome.test.assertEq( @@ -365,7 +365,7 @@ }, function continueImport() { - let callback = function(importResults) { + const callback = function(importResults) { chrome.test.assertNoLastError(); chrome.test.assertTrue(!!importResults); chrome.test.assertEq( @@ -386,7 +386,7 @@ }, function exportPasswords() { - let callback = function() { + const callback = function() { chrome.test.assertNoLastError(); // Ensure that the callback is invoked. @@ -397,7 +397,7 @@ }, function requestExportProgressStatus() { - let callback = function(status) { + const callback = function(status) { chrome.test.assertEq( chrome.passwordsPrivate.ExportProgressStatus.IN_PROGRESS, status); @@ -409,7 +409,7 @@ }, function accountStorageIsInactive() { - var callback = function(active) { + const callback = function(active) { chrome.test.assertEq(active, false); // Ensure that the callback is invoked. chrome.test.succeed(); @@ -419,7 +419,7 @@ }, function accountStorageIsActive() { - var callback = function(active) { + const callback = function(active) { chrome.test.assertEq(active, true); // Ensure that the callback is invoked. chrome.test.succeed(); @@ -449,7 +449,7 @@ insecureCredentials => { chrome.test.assertEq(2, insecureCredentials.length); - var compromisedCredential = insecureCredentials[0]; + const compromisedCredential = insecureCredentials[0]; chrome.test.assertEq( 1, compromisedCredential.affiliatedDomains.length); chrome.test.assertEq( @@ -472,7 +472,7 @@ ['LEAKED'], compromisedCredential.compromisedInfo.compromiseTypes); - var weakredential = insecureCredentials[1]; + const weakredential = insecureCredentials[1]; chrome.test.assertEq(1, weakredential.affiliatedDomains.length); chrome.test.assertEq( 'example.com', weakredential.affiliatedDomains[0].name); @@ -655,7 +655,7 @@ }, function getCredentialGroups() { - var callback = function(list) { + const callback = function(list) { chrome.test.assertTrue(!!list); chrome.test.assertEq(list.length, 1); @@ -663,16 +663,16 @@ chrome.test.assertTrue(!!group); chrome.test.assertTrue(group.entries.length > 0); - var idSet = new Set(); - for (var i = 0; i < group.entries.length; ++i) { - var entry = group.entries[i]; + const idSet = new Set(); + for (let i = 0; i < group.entries.length; ++i) { + const entry = group.entries[i]; chrome.test.assertTrue(!!entry); chrome.test.assertEq(1, entry.affiliatedDomains.length); idSet.add(entry.id); } // The last entry should be a passkey. - var passkey = group.entries[group.entries.length - 1]; + const passkey = group.entries[group.entries.length - 1]; chrome.test.assertTrue(passkey.isPasskey); chrome.test.assertEq(passkey.displayName, 'displayName'); chrome.test.assertEq(passkey.creationTime, 1000); @@ -691,10 +691,10 @@ credentialsGroupedByPassword => { chrome.test.assertEq(1, credentialsGroupedByPassword.length); - var credentialsWithReusedPassword = credentialsGroupedByPassword[0]; + const credentialsWithReusedPassword = credentialsGroupedByPassword[0]; chrome.test.assertEq(2, credentialsWithReusedPassword.entries.length); - var firstCredentials = credentialsWithReusedPassword.entries[0]; + const firstCredentials = credentialsWithReusedPassword.entries[0]; chrome.test.assertEq(1, firstCredentials.affiliatedDomains.length); chrome.test.assertEq( 'example.com', firstCredentials.affiliatedDomains[0].name); @@ -708,7 +708,7 @@ ['REUSED'], firstCredentials.compromisedInfo.compromiseTypes); - var secondCredential = credentialsWithReusedPassword.entries[1]; + const secondCredential = credentialsWithReusedPassword.entries[1]; chrome.test.assertEq(1, secondCredential.affiliatedDomains.length); chrome.test.assertEq( 'test.com', secondCredential.affiliatedDomains[0].name); @@ -738,7 +738,7 @@ }, function isPasswordManagerPinAvailable() { - var callback = function(available) { + const callback = function(available) { chrome.test.assertFalse(available); chrome.test.succeed(); }; @@ -763,7 +763,7 @@ }, function isConnectedToCloudAuthenticator() { - var callback = function(connected) { + const callback = function(connected) { chrome.test.assertFalse(connected); chrome.test.succeed(); }; @@ -772,7 +772,7 @@ } ]; -var testToRun = window.location.search.substring(1); +const testToRun = window.location.search.substring(1); chrome.test.runTests(availableTests.filter(function(op) { return op.name == testToRun; }));
diff --git a/chrome/test/data/extensions/api_test/permissions/add_host_access_request/worker.js b/chrome/test/data/extensions/api_test/permissions/add_host_access_request/worker.js index f9a49c87..12dd3ca 100644 --- a/chrome/test/data/extensions/api_test/permissions/add_host_access_request/worker.js +++ b/chrome/test/data/extensions/api_test/permissions/add_host_access_request/worker.js
@@ -8,7 +8,7 @@ async function navigateTo(origin) { const config = await chrome.test.getConfig(); const url = `http://${origin}:${config.testServer.port}/simple.html`; - let tab = await openTab(url); + const tab = await openTab(url); return tab; } @@ -69,7 +69,7 @@ chrome.test.succeed(); return; } - let tab = await navigateTo('requested.com'); + const tab = await navigateTo('requested.com'); const request = {tabId: tab.id}; await chrome.test.assertPromiseRejects( @@ -83,8 +83,9 @@ // Tests that an error is returned when the extension adds a request for a // documentId that it can already access its current web contents. async function accessAlreadyGrantedForDocumentId() { - let tab = await navigateTo('requested.com'); - let frame = await chrome.webNavigation.getFrame({frameId: 0, tabId: tab.id}) + const tab = await navigateTo('requested.com'); + const frame = + await chrome.webNavigation.getFrame({frameId: 0, tabId: tab.id}) const request = {documentId: frame.documentId}; await chrome.test.assertPromiseRejects( @@ -98,7 +99,7 @@ // Tests that an error is returned when the extension adds a request with an // invalid pattern. async function invalidPattern() { - let tab = await navigateTo('requested.com'); + const tab = await navigateTo('requested.com'); const request = {tabId: tab.id, pattern: 'invalid pattern'}; await chrome.test.assertPromiseRejects(
diff --git a/chrome/test/data/extensions/api_test/permissions/always_allowed/background.js b/chrome/test/data/extensions/api_test/permissions/always_allowed/background.js index d021671..b0c99a4 100644 --- a/chrome/test/data/extensions/api_test/permissions/always_allowed/background.js +++ b/chrome/test/data/extensions/api_test/permissions/always_allowed/background.js
@@ -10,8 +10,8 @@ // Test the tabs API. function tabs() { try { - chrome.tabs.create({url: "404_is_enough.html"}, function(tab1) { - chrome.tabs.update(tab1.id, {url: "404_again.html"}, function(tab2) { + chrome.tabs.create({url: '404_is_enough.html'}, function(tab1) { + chrome.tabs.update(tab1.id, {url: '404_again.html'}, function(tab2) { chrome.tabs.onRemoved.addListener(function(tabId, removeInfo) { chrome.test.assertEq(tab1.id, tabId); chrome.test.succeed(); @@ -27,7 +27,7 @@ // Negative test for the tabs API. function tabsNegative() { try { - var tab = chrome.tabs.query(); + const tab = chrome.tabs.query(); chrome.test.fail(); } catch (e) { chrome.test.succeed();
diff --git a/chrome/test/data/extensions/api_test/permissions/disabled/background.js b/chrome/test/data/extensions/api_test/permissions/disabled/background.js index f2b402c..a21357d 100644 --- a/chrome/test/data/extensions/api_test/permissions/disabled/background.js +++ b/chrome/test/data/extensions/api_test/permissions/disabled/background.js
@@ -8,7 +8,7 @@ chrome.test.runTests([ function history() { try { - var query = { 'text': '', 'maxResults': 1 }; + const query = { text: '', maxResults: 1 }; chrome.history.search(query, function(results) { chrome.test.fail(); }); @@ -43,7 +43,7 @@ return; } else { try { - chrome.tabs.create({'url': '1'}, function(tab) { + chrome.tabs.create({url: '1'}, function(tab) { // Tabs strip sensitive data without permissions. chrome.test.assertFalse('url' in tab); chrome.test.succeed();
diff --git a/chrome/test/data/extensions/api_test/permissions/enabled/background.js b/chrome/test/data/extensions/api_test/permissions/enabled/background.js index 34aa3f3..1af8929d 100644 --- a/chrome/test/data/extensions/api_test/permissions/enabled/background.js +++ b/chrome/test/data/extensions/api_test/permissions/enabled/background.js
@@ -5,12 +5,12 @@ // All of the calls to chrome.* functions should succeed, since this extension // has requested all required permissions. -var pass = chrome.test.callbackPass; +const pass = chrome.test.callbackPass; chrome.test.runTests([ function history() { try { - var query = { 'text': '', 'maxResults': 1 }; + const query = { text: '', maxResults: 1 }; chrome.history.search(query, pass(function(results) {})); } catch (e) { chrome.test.fail();
diff --git a/chrome/test/data/extensions/api_test/permissions/favicon/test.js b/chrome/test/data/extensions/api_test/permissions/favicon/test.js index 01e5740..fce877d2 100644 --- a/chrome/test/data/extensions/api_test/permissions/favicon/test.js +++ b/chrome/test/data/extensions/api_test/permissions/favicon/test.js
@@ -7,14 +7,14 @@ chrome.test.runTests([ function favicon() { - var img = document.getElementById('favicon'); + const img = document.getElementById('favicon'); chrome.test.assertEq(16, img.naturalWidth); chrome.test.assertEq(16, img.naturalHeight); chrome.test.succeed(); }, function theme() { - var img = document.getElementById('theme'); + const img = document.getElementById('theme'); chrome.test.assertEq(0, img.naturalWidth); chrome.test.assertEq(0, img.naturalHeight); chrome.test.succeed();
diff --git a/chrome/test/data/extensions/api_test/permissions/file_access_no/background.js b/chrome/test/data/extensions/api_test/permissions/file_access_no/background.js index 308fbde..eece3c9 100644 --- a/chrome/test/data/extensions/api_test/permissions/file_access_no/background.js +++ b/chrome/test/data/extensions/api_test/permissions/file_access_no/background.js
@@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -var callbackFail = chrome.test.callbackFail; -var callbackPass = chrome.test.callbackPass; -var expectedError = - "Extension must have file access enabled to request 'file:///*'."; +const callbackFail = chrome.test.callbackFail; +const callbackPass = chrome.test.callbackPass; +const expectedError = + `Extension must have file access enabled to request 'file:///*'.`; function test() { - chrome.permissions.request({"origins": ["file:///*"]}, + chrome.permissions.request({origins: ['file:///*']}, callbackFail(expectedError, function(granted) { chrome.test.assertFalse(!!granted); chrome.permissions.getAll(callbackPass(function(permissions) {
diff --git a/chrome/test/data/extensions/api_test/permissions/file_access_yes/background.js b/chrome/test/data/extensions/api_test/permissions/file_access_yes/background.js index a46880db..67ffdea0 100644 --- a/chrome/test/data/extensions/api_test/permissions/file_access_yes/background.js +++ b/chrome/test/data/extensions/api_test/permissions/file_access_yes/background.js
@@ -2,14 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -var callbackPass = chrome.test.callbackPass; +const callbackPass = chrome.test.callbackPass; function test() { - chrome.permissions.request({"origins": ["file:///*"]}, + chrome.permissions.request({origins: ['file:///*']}, callbackPass(function(granted) { chrome.test.assertTrue(granted); chrome.permissions.getAll(callbackPass(function(permissions) { - chrome.test.assertEq(["file:///*"], permissions.origins); + chrome.test.assertEq(['file:///*'], permissions.origins); chrome.test.succeed(); })); }));
diff --git a/chrome/test/data/extensions/api_test/permissions/file_load/background.js b/chrome/test/data/extensions/api_test/permissions/file_load/background.js index 7c4b510..fd9eaf00 100644 --- a/chrome/test/data/extensions/api_test/permissions/file_load/background.js +++ b/chrome/test/data/extensions/api_test/permissions/file_load/background.js
@@ -2,29 +2,29 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -var callbackPass = chrome.test.callbackPass; +const callbackPass = chrome.test.callbackPass; -var test_dir; +let testDir; function requestListener() { chrome.test.succeed(); } -var tests = [ +const tests = [ function testDirectoryListing() { - fetch(test_dir).then(requestListener).catch(function(err) { + fetch(testDir).then(requestListener).catch(function(err) { chrome.test.fail(err.toString()); }); }, function testFile() { - fetch(test_dir + "/empty.html").then(requestListener).catch(function(err) { + fetch(`${testDir}/empty.html`).then(requestListener).catch(function(err) { chrome.test.fail(err.toString()); }); } ]; chrome.test.getConfig(function(config) { - test_dir = "file://" + config.customArg; + testDir = `file://${config.customArg}`; chrome.test.runTests(tests); })
diff --git a/chrome/test/data/extensions/api_test/permissions/host_subsets/background.js b/chrome/test/data/extensions/api_test/permissions/host_subsets/background.js index e0998b8a..7849c69 100644 --- a/chrome/test/data/extensions/api_test/permissions/host_subsets/background.js +++ b/chrome/test/data/extensions/api_test/permissions/host_subsets/background.js
@@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -var ERROR = 'Only permissions specified in the manifest may be requested.'; -var test = chrome.test; +const ERROR = 'Only permissions specified in the manifest may be requested.'; +const test = chrome.test; // The URL patterns that we've supposedly been granted access to so far. Use // this to verify queried hosts for each test. -var grantedHosts = []; +const grantedHosts = []; // Pushes a value onto an array, asserting that it's unique in the array. function pushUniqueValue(array, value) { @@ -17,7 +17,7 @@ // Removes a value from an array, asserting that it's unique in the array. function removeUniqueValue(array, value) { - var indexOfValue = array.indexOf(value); + const indexOfValue = array.indexOf(value); test.assertTrue(indexOfValue >= 0); array.splice(indexOfValue, 1); test.assertEq(-1, array.indexOf(value)); @@ -35,7 +35,7 @@ function checkGrantedHosts(callback) { chrome.permissions.getAll(test.callbackPass(function(permissions) { assertSetEq(grantedHosts, permissions.origins); - var countDown = grantedHosts.length; + let countDown = grantedHosts.length; if (countDown == 0) { callback(); return; @@ -62,11 +62,11 @@ if (expectedGranted) { test.assertTrue( granted, - "Access to " + host + " was not granted, but should have been"); + `Access to ${host} was not granted, but should have been`); } else { test.assertFalse( !!granted, - "Access to " + host + " was granted, but should not have been"); + `Access to ${host} was granted, but should not have been`); } checkGrantedHosts(callback); }, expectedError)); @@ -80,10 +80,10 @@ chrome.permissions.remove({origins: [host]}, test.callbackPass(function(removed) { if (removed) { - test.assertTrue(expectedRemoved, "Access to " + host + " removed"); + test.assertTrue(expectedRemoved, `Access to ${host} removed`); removeUniqueValue(grantedHosts, host); } else { - test.assertFalse(expectedRemoved, "Access to " + host + " not removed"); + test.assertFalse(expectedRemoved, `Access to ${host} not removed`); } checkGrantedHosts(callback); })); @@ -108,12 +108,12 @@ // // The test is kept alive until all callbacks in the chain have been run. function chain(callbacks) { - var head = callbacks[0], tail = callbacks.slice(1); + const head = callbacks[0], tail = callbacks.slice(1); if (tail.length == 0) { head(); return; } - var callbackCompleted = chrome.test.callbackAdded(); + const callbackCompleted = chrome.test.callbackAdded(); head(function() { try { chain(tail);
diff --git a/chrome/test/data/extensions/api_test/permissions/optional/background.js b/chrome/test/data/extensions/api_test/permissions/optional/background.js index cdd5c7b3..c8dda38 100644 --- a/chrome/test/data/extensions/api_test/permissions/optional/background.js +++ b/chrome/test/data/extensions/api_test/permissions/optional/background.js
@@ -2,36 +2,36 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -var assertEq = chrome.test.assertEq; -var assertFalse = chrome.test.assertFalse; -var assertTrue = chrome.test.assertTrue; -var assertThrows = chrome.test.assertThrows; -var fail = chrome.test.callbackFail; -var pass = chrome.test.callbackPass; -var listenOnce = chrome.test.listenOnce; +const assertEq = chrome.test.assertEq; +const assertFalse = chrome.test.assertFalse; +const assertTrue = chrome.test.assertTrue; +const assertThrows = chrome.test.assertThrows; +const fail = chrome.test.callbackFail; +const pass = chrome.test.callbackPass; +const listenOnce = chrome.test.listenOnce; -var NOT_OPTIONAL_ERROR = - "Only permissions specified in the manifest may be requested."; +const NOT_OPTIONAL_ERROR = + 'Only permissions specified in the manifest may be requested.'; -var REQUIRED_ERROR = - "You cannot remove required permissions."; +const REQUIRED_ERROR = + 'You cannot remove required permissions.'; -var UNKNOWN_PERMISSIONS_ERROR = +const UNKNOWN_PERMISSIONS_ERROR = "'*' is not a recognized permission."; -var emptyPermissions = {permissions: [], origins: []}; +const emptyPermissions = {permissions: [], origins: []}; -var initialPermissions = { +const initialPermissions = { permissions: ['management'], origins: ['http://a.com/*', "http://contentscript.com/*"] }; -var permissionsWithBookmarks = { +const permissionsWithBookmarks = { permissions: ['management', 'bookmarks'], origins: ['http://a.com/*', "http://contentscript.com/*"] } -var permissionsWithOrigin = { +const permissionsWithOrigin = { permissions: ['management'], origins: ['http://a.com/*', 'http://*.c.com/*', "http://contentscript.com/*"] } @@ -40,7 +40,7 @@ if (set1.length != set2.length) return false; - for (var x = 0; x < set1.length; x++) { + for (let x = 0; x < set1.length; x++) { if (!set2.some(function(v) { return v == set1[x]; })) return false; } @@ -58,7 +58,7 @@ assertEq(200, response.status); return response; } - var error = new Error(response.statusText); + const error = new Error(response.statusText); error.response = response; throw error; } @@ -66,7 +66,7 @@ chrome.test.getConfig(function(config) { function doReq(domain, callback) { - var url = domain + ":PORT/extensions/test_file.txt"; + let url = domain + ":PORT/extensions/test_file.txt"; url = url.replace(/PORT/, config.testServer.port); chrome.test.log("Requesting url: " + url); @@ -201,7 +201,7 @@ }, function unknownPermission() { - var error_msg = UNKNOWN_PERMISSIONS_ERROR.replace('*', 'asdf'); + const error_msg = UNKNOWN_PERMISSIONS_ERROR.replace('*', 'asdf'); chrome.permissions.request( {permissions: ['asdf']}, fail(error_msg)); }, @@ -263,7 +263,7 @@ // Tests that the changed permissions have taken effect from inside the // onAdded and onRemoved event listeners. function eventListenerPermissions() { - var isInstanceOfServiceWorkerGlobalScope = + const isInstanceOfServiceWorkerGlobalScope = ('ServiceWorkerGlobalScope' in self) && (self instanceof ServiceWorkerGlobalScope); if (isInstanceOfServiceWorkerGlobalScope) {
diff --git a/chrome/test/data/extensions/api_test/permissions/optional_deny/background.js b/chrome/test/data/extensions/api_test/permissions/optional_deny/background.js index 339a900..04002115 100644 --- a/chrome/test/data/extensions/api_test/permissions/optional_deny/background.js +++ b/chrome/test/data/extensions/api_test/permissions/optional_deny/background.js
@@ -2,26 +2,26 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -var assertFalse = chrome.test.assertFalse; -var assertTrue = chrome.test.assertTrue; -var assertEq = chrome.test.assertEq; -var pass = chrome.test.callbackPass; +const assertFalse = chrome.test.assertFalse; +const assertTrue = chrome.test.assertTrue; +const assertEq = chrome.test.assertEq; +const pass = chrome.test.callbackPass; -var NO_BOOKMARKS_PERMISSION = +const NO_BOOKMARKS_PERMISSION = "You do not have permission to use 'bookmarks.getTree'."; chrome.test.getConfig(function(config) { function doReq(domain, callback) { - var url = domain + ":PORT/extensions/test_file.txt"; + let url = `${domain}:PORT/extensions/test_file.txt`; url = url.replace(/PORT/, config.testServer.port); - chrome.test.log("Requesting url: " + url); + chrome.test.log(`Requesting url: ${url}`); fetch(url).then(function(response) { assertEq(200, response.status); return response.text(); }).then(function(text) { - assertEq("Hello!", text); + assertEq('Hello!', text); callback(true); }).catch(function(error) { chrome.test.log(error.toString());
diff --git a/chrome/test/data/extensions/api_test/permissions/optional_gesture/background.js b/chrome/test/data/extensions/api_test/permissions/optional_gesture/background.js index abb6526..b3bb541 100644 --- a/chrome/test/data/extensions/api_test/permissions/optional_gesture/background.js +++ b/chrome/test/data/extensions/api_test/permissions/optional_gesture/background.js
@@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -var fail = chrome.test.callbackFail; +const fail = chrome.test.callbackFail; -var GESTURE_ERROR = "This function must be called during a user gesture"; +const GESTURE_ERROR = 'This function must be called during a user gesture'; chrome.test.getConfig(function(config) { chrome.test.runTests([
diff --git a/chrome/test/data/extensions/api_test/permissions/optional_policy_blocked/background.js b/chrome/test/data/extensions/api_test/permissions/optional_policy_blocked/background.js index db643f1..f5994177 100644 --- a/chrome/test/data/extensions/api_test/permissions/optional_policy_blocked/background.js +++ b/chrome/test/data/extensions/api_test/permissions/optional_policy_blocked/background.js
@@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -var assertTrue = chrome.test.assertTrue; -var fail = chrome.test.callbackFail; -var pass = chrome.test.callbackPass; +const assertTrue = chrome.test.assertTrue; +const fail = chrome.test.callbackFail; +const pass = chrome.test.callbackPass; -var BLOCKED_BY_ENTERPRISE_ERROR = - "Permissions are blocked by enterprise policy."; +const BLOCKED_BY_ENTERPRISE_ERROR = + 'Permissions are blocked by enterprise policy.'; chrome.test.getConfig(function(config) {
diff --git a/chrome/test/data/extensions/api_test/permissions/optional_retain_gesture/background.js b/chrome/test/data/extensions/api_test/permissions/optional_retain_gesture/background.js index 776d955..d201383 100644 --- a/chrome/test/data/extensions/api_test/permissions/optional_retain_gesture/background.js +++ b/chrome/test/data/extensions/api_test/permissions/optional_retain_gesture/background.js
@@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -var fail = chrome.test.callbackFail; +const fail = chrome.test.callbackFail; -var GESTURE_ERROR = "This function must be called during a user gesture"; +const GESTURE_ERROR = 'This function must be called during a user gesture'; chrome.test.getConfig(function(config) { chrome.test.runTests([ @@ -30,7 +30,7 @@ ); // Consume the user gesture - window.open("", "", ""); + window.open('', '', ''); } ); });
diff --git a/chrome/test/data/extensions/api_test/permissions/optional_updates_bindings/background.js b/chrome/test/data/extensions/api_test/permissions/optional_updates_bindings/background.js index 8feb871a..dd4c688 100644 --- a/chrome/test/data/extensions/api_test/permissions/optional_updates_bindings/background.js +++ b/chrome/test/data/extensions/api_test/permissions/optional_updates_bindings/background.js
@@ -10,7 +10,7 @@ chrome.test.assertTrue(granted); // Assert that the bindings have been updated on ourselves the background // page, and the tab that was created. - var expectedAlarmsKeys = [ + const expectedAlarmsKeys = [ 'clear', 'clearAll', 'create', 'get', 'getAll', 'onAlarm']; [window, otherWindow].forEach(function(w) { chrome.test.assertEq(expectedAlarmsKeys,
diff --git a/chrome/test/data/extensions/api_test/permissions/remove_host_access_request/worker.js b/chrome/test/data/extensions/api_test/permissions/remove_host_access_request/worker.js index 03d5ba43..d642de0 100644 --- a/chrome/test/data/extensions/api_test/permissions/remove_host_access_request/worker.js +++ b/chrome/test/data/extensions/api_test/permissions/remove_host_access_request/worker.js
@@ -91,7 +91,7 @@ chrome.test.succeed(); return; } - let tab = await navigateTo('requested.com'); + const tab = await navigateTo('requested.com'); const request = {tabId: tab.id, pattern: 'invalid pattern'}; await chrome.test.assertPromiseRejects(
diff --git a/chrome/test/data/extensions/api_test/permissions_test/embedded_into_iframe/has_permissions/content-script.js b/chrome/test/data/extensions/api_test/permissions_test/embedded_into_iframe/has_permissions/content-script.js index cf0d4a07..2ce26a6 100644 --- a/chrome/test/data/extensions/api_test/permissions_test/embedded_into_iframe/has_permissions/content-script.js +++ b/chrome/test/data/extensions/api_test/permissions_test/embedded_into_iframe/has_permissions/content-script.js
@@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -var iframe = document.createElement('iframe'); +const iframe = document.createElement('iframe'); iframe.name = 'iframe_with_embedded_extension'; iframe.src = - chrome.runtime.getURL('iframe_content.html' + document.location.search); -iframe.allow = 'microphone \'src\'; camera \'src\'; geolocation \'src\''; + chrome.runtime.getURL(`iframe_content.html${document.location.search}`); +iframe.allow = `microphone 'src'; camera 'src'; geolocation 'src'`; document.body.appendChild(iframe);
diff --git a/chrome/test/data/extensions/api_test/permissions_test/embedded_into_iframe/no_permissions/content-script.js b/chrome/test/data/extensions/api_test/permissions_test/embedded_into_iframe/no_permissions/content-script.js index cf0d4a07..2ce26a6 100644 --- a/chrome/test/data/extensions/api_test/permissions_test/embedded_into_iframe/no_permissions/content-script.js +++ b/chrome/test/data/extensions/api_test/permissions_test/embedded_into_iframe/no_permissions/content-script.js
@@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -var iframe = document.createElement('iframe'); +const iframe = document.createElement('iframe'); iframe.name = 'iframe_with_embedded_extension'; iframe.src = - chrome.runtime.getURL('iframe_content.html' + document.location.search); -iframe.allow = 'microphone \'src\'; camera \'src\'; geolocation \'src\''; + chrome.runtime.getURL(`iframe_content.html${document.location.search}`); +iframe.allow = `microphone 'src'; camera 'src'; geolocation 'src'`; document.body.appendChild(iframe);
diff --git a/chrome/test/data/extensions/api_test/permissions_test/request_from_background_v2/has_permissions/background.js b/chrome/test/data/extensions/api_test/permissions_test/request_from_background_v2/has_permissions/background.js index 91c61ac7..992c5bd 100644 --- a/chrome/test/data/extensions/api_test/permissions_test/request_from_background_v2/has_permissions/background.js +++ b/chrome/test/data/extensions/api_test/permissions_test/request_from_background_v2/has_permissions/background.js
@@ -50,7 +50,7 @@ }) }, function requestCamera() { - var constraints = {video: true}; + const constraints = {video: true}; navigator.mediaDevices.getUserMedia(constraints) .then(function(stream) { chrome.test.fail(); @@ -70,7 +70,7 @@ }) }, function requestMicrophone() { - var constraints = {audio: true}; + const constraints = {audio: true}; navigator.mediaDevices.getUserMedia(constraints) .then(function(stream) { chrome.test.fail();
diff --git a/chrome/test/data/extensions/api_test/permissions_test/request_from_background_v2/no_permissions/background.js b/chrome/test/data/extensions/api_test/permissions_test/request_from_background_v2/no_permissions/background.js index 4e7c9089..ea383f43 100644 --- a/chrome/test/data/extensions/api_test/permissions_test/request_from_background_v2/no_permissions/background.js +++ b/chrome/test/data/extensions/api_test/permissions_test/request_from_background_v2/no_permissions/background.js
@@ -40,7 +40,7 @@ }) }, function requestCamera() { - var constraints = {video: true}; + const constraints = {video: true}; navigator.mediaDevices.getUserMedia(constraints) .then(function(stream) { chrome.test.fail(); @@ -60,7 +60,7 @@ }) }, function requestMicrophone() { - var constraints = {audio: true}; + const constraints = {audio: true}; navigator.mediaDevices.getUserMedia(constraints) .then(function(stream) { chrome.test.fail();
diff --git a/chrome/test/data/extensions/api_test/permissions_test/request_from_options_v2/has_permissions/options.js b/chrome/test/data/extensions/api_test/permissions_test/request_from_options_v2/has_permissions/options.js index 0f975b4..b0e1546 100644 --- a/chrome/test/data/extensions/api_test/permissions_test/request_from_options_v2/has_permissions/options.js +++ b/chrome/test/data/extensions/api_test/permissions_test/request_from_options_v2/has_permissions/options.js
@@ -49,7 +49,7 @@ }) }, function requestCamera() { - var constraints = { video: true }; + const constraints = { video: true }; navigator.mediaDevices.getUserMedia(constraints) .then(function (stream) { chrome.test.succeed(); @@ -69,7 +69,7 @@ }) }, function requestMicrophone() { - var constraints = { audio: true }; + const constraints = { audio: true }; navigator.mediaDevices.getUserMedia(constraints) .then(function (stream) { chrome.test.succeed();
diff --git a/chrome/test/data/extensions/api_test/permissions_test/request_from_options_v2/no_permissions/options.js b/chrome/test/data/extensions/api_test/permissions_test/request_from_options_v2/no_permissions/options.js index c53b65d7..f35f4a7a 100644 --- a/chrome/test/data/extensions/api_test/permissions_test/request_from_options_v2/no_permissions/options.js +++ b/chrome/test/data/extensions/api_test/permissions_test/request_from_options_v2/no_permissions/options.js
@@ -49,7 +49,7 @@ }) }, function requestCamera() { - var constraints = {video: true}; + const constraints = {video: true}; navigator.mediaDevices.getUserMedia(constraints) .then(function(stream) { chrome.test.succeed(); @@ -69,7 +69,7 @@ }) }, function requestMicrophone() { - var constraints = {audio: true}; + const constraints = {audio: true}; navigator.mediaDevices.getUserMedia(constraints) .then(function(stream) { chrome.test.succeed();
diff --git a/chrome/test/data/extensions/api_test/permissions_test/request_from_options_v3/has_permissions/options.js b/chrome/test/data/extensions/api_test/permissions_test/request_from_options_v3/has_permissions/options.js index 0f975b4..b0e1546 100644 --- a/chrome/test/data/extensions/api_test/permissions_test/request_from_options_v3/has_permissions/options.js +++ b/chrome/test/data/extensions/api_test/permissions_test/request_from_options_v3/has_permissions/options.js
@@ -49,7 +49,7 @@ }) }, function requestCamera() { - var constraints = { video: true }; + const constraints = { video: true }; navigator.mediaDevices.getUserMedia(constraints) .then(function (stream) { chrome.test.succeed(); @@ -69,7 +69,7 @@ }) }, function requestMicrophone() { - var constraints = { audio: true }; + const constraints = { audio: true }; navigator.mediaDevices.getUserMedia(constraints) .then(function (stream) { chrome.test.succeed();
diff --git a/chrome/test/data/extensions/api_test/permissions_test/request_from_options_v3/has_permissions_negative/options.js b/chrome/test/data/extensions/api_test/permissions_test/request_from_options_v3/has_permissions_negative/options.js index 52cf5b3..c72ba251 100644 --- a/chrome/test/data/extensions/api_test/permissions_test/request_from_options_v3/has_permissions_negative/options.js +++ b/chrome/test/data/extensions/api_test/permissions_test/request_from_options_v3/has_permissions_negative/options.js
@@ -49,7 +49,7 @@ }) }, function requestCamera() { - var constraints = { video: true }; + const constraints = { video: true }; navigator.mediaDevices.getUserMedia(constraints) .then(function (stream) { chrome.test.fail(); @@ -69,7 +69,7 @@ }) }, function requestMicrophone() { - var constraints = { audio: true }; + const constraints = { audio: true }; navigator.mediaDevices.getUserMedia(constraints) .then(function (stream) { chrome.test.fail();
diff --git a/chrome/test/data/extensions/api_test/permissions_test/request_from_options_v3/no_permissions/options.js b/chrome/test/data/extensions/api_test/permissions_test/request_from_options_v3/no_permissions/options.js index c53b65d7..f35f4a7a 100644 --- a/chrome/test/data/extensions/api_test/permissions_test/request_from_options_v3/no_permissions/options.js +++ b/chrome/test/data/extensions/api_test/permissions_test/request_from_options_v3/no_permissions/options.js
@@ -49,7 +49,7 @@ }) }, function requestCamera() { - var constraints = {video: true}; + const constraints = {video: true}; navigator.mediaDevices.getUserMedia(constraints) .then(function(stream) { chrome.test.succeed(); @@ -69,7 +69,7 @@ }) }, function requestMicrophone() { - var constraints = {audio: true}; + const constraints = {audio: true}; navigator.mediaDevices.getUserMedia(constraints) .then(function(stream) { chrome.test.succeed();
diff --git a/chrome/test/data/extensions/api_test/permissions_test/request_from_popup_v2/has_permissions/popup.js b/chrome/test/data/extensions/api_test/permissions_test/request_from_popup_v2/has_permissions/popup.js index 3ff2769a..0326f9c 100644 --- a/chrome/test/data/extensions/api_test/permissions_test/request_from_popup_v2/has_permissions/popup.js +++ b/chrome/test/data/extensions/api_test/permissions_test/request_from_popup_v2/has_permissions/popup.js
@@ -40,7 +40,7 @@ }) }, function requestCamera() { - var constraints = {video: true}; + const constraints = {video: true}; navigator.mediaDevices.getUserMedia(constraints) .then(function(stream) { chrome.test.fail(); @@ -60,7 +60,7 @@ }) }, function requestMicrophone() { - var constraints = {audio: true}; + const constraints = {audio: true}; navigator.mediaDevices.getUserMedia(constraints) .then(function(stream) { chrome.test.fail();
diff --git a/chrome/test/data/extensions/api_test/permissions_test/request_from_popup_v2/no_permissions/popup.js b/chrome/test/data/extensions/api_test/permissions_test/request_from_popup_v2/no_permissions/popup.js index 6d8c706..a72c177 100644 --- a/chrome/test/data/extensions/api_test/permissions_test/request_from_popup_v2/no_permissions/popup.js +++ b/chrome/test/data/extensions/api_test/permissions_test/request_from_popup_v2/no_permissions/popup.js
@@ -40,7 +40,7 @@ }) }, function requestCamera() { - var constraints = {video: true}; + const constraints = {video: true}; navigator.mediaDevices.getUserMedia(constraints) .then(function(stream) { chrome.test.fail(); @@ -60,7 +60,7 @@ }) }, function requestMicrophone() { - var constraints = {audio: true}; + const constraints = {audio: true}; navigator.mediaDevices.getUserMedia(constraints) .then(function(stream) { chrome.test.fail();
diff --git a/chrome/test/data/extensions/api_test/permissions_test/request_from_popup_v3/has_permissions/popup.js b/chrome/test/data/extensions/api_test/permissions_test/request_from_popup_v3/has_permissions/popup.js index 3ff2769a..0326f9c 100644 --- a/chrome/test/data/extensions/api_test/permissions_test/request_from_popup_v3/has_permissions/popup.js +++ b/chrome/test/data/extensions/api_test/permissions_test/request_from_popup_v3/has_permissions/popup.js
@@ -40,7 +40,7 @@ }) }, function requestCamera() { - var constraints = {video: true}; + const constraints = {video: true}; navigator.mediaDevices.getUserMedia(constraints) .then(function(stream) { chrome.test.fail(); @@ -60,7 +60,7 @@ }) }, function requestMicrophone() { - var constraints = {audio: true}; + const constraints = {audio: true}; navigator.mediaDevices.getUserMedia(constraints) .then(function(stream) { chrome.test.fail();
diff --git a/chrome/test/data/extensions/api_test/permissions_test/request_from_popup_v3/no_permissions/popup.js b/chrome/test/data/extensions/api_test/permissions_test/request_from_popup_v3/no_permissions/popup.js index 6d8c706..a72c177 100644 --- a/chrome/test/data/extensions/api_test/permissions_test/request_from_popup_v3/no_permissions/popup.js +++ b/chrome/test/data/extensions/api_test/permissions_test/request_from_popup_v3/no_permissions/popup.js
@@ -40,7 +40,7 @@ }) }, function requestCamera() { - var constraints = {video: true}; + const constraints = {video: true}; navigator.mediaDevices.getUserMedia(constraints) .then(function(stream) { chrome.test.fail(); @@ -60,7 +60,7 @@ }) }, function requestMicrophone() { - var constraints = {audio: true}; + const constraints = {audio: true}; navigator.mediaDevices.getUserMedia(constraints) .then(function(stream) { chrome.test.fail();
diff --git a/chrome/test/data/webui/chromeos/settings/os_people_page/OWNERS b/chrome/test/data/webui/chromeos/settings/os_people_page/OWNERS new file mode 100644 index 0000000..eb0f72b --- /dev/null +++ b/chrome/test/data/webui/chromeos/settings/os_people_page/OWNERS
@@ -0,0 +1,2 @@ +per-file *_api.test-mojom=file://ash/login/LOGIN_LOCK_OWNERS +per-file *_api.ts=file://ash/login/LOGIN_LOCK_OWNERS
diff --git a/chrome/test/data/webui/contextual_tasks/composebox_misc_inputs_test.ts b/chrome/test/data/webui/contextual_tasks/composebox_misc_inputs_test.ts index 15d5e69..c051b6c 100644 --- a/chrome/test/data/webui/contextual_tasks/composebox_misc_inputs_test.ts +++ b/chrome/test/data/webui/contextual_tasks/composebox_misc_inputs_test.ts
@@ -18,7 +18,8 @@ import {WindowProxy} from 'chrome://resources/cr_components/composebox/window_proxy.js'; import {GlowAnimationState} from 'chrome://resources/cr_components/search/constants.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; -import {PageCallbackRouter as SearchboxPageCallbackRouter, PageHandlerRemote as SearchboxPageHandlerRemote, type PageRemote as SearchboxPageRemote} from 'chrome://resources/mojo/components/omnibox/browser/searchbox.mojom-webui.js'; +import {PageCallbackRouter as SearchboxPageCallbackRouter, PageHandlerRemote as SearchboxPageHandlerRemote} from 'chrome://resources/mojo/components/omnibox/browser/searchbox.mojom-webui.js'; +import type {PageRemote as SearchboxPageRemote} from 'chrome://resources/mojo/components/omnibox/browser/searchbox.mojom-webui.js'; import {assertEquals, assertFalse, assertNotEquals, assertTrue} from 'chrome://webui-test/chai_assert.js'; import type {MetricsTracker} from 'chrome://webui-test/metrics_test_support.js'; import {fakeMetricsPrivate} from 'chrome://webui-test/metrics_test_support.js'; @@ -420,7 +421,7 @@ 'Voice search transcript should be updated with voice result'); assertEquals( - '', composebox.input_, + '', composebox.input, 'Composebox input should be empty if not final result'); assertEquals( @@ -450,7 +451,7 @@ assertEquals( - 'hellogoodbye', composebox.input_, + 'hellogoodbye', composebox.input, 'Composebox input should be updated with final result'); assertEquals( @@ -523,7 +524,7 @@ 'Transcript should be updated immediately on result'); assertEquals( - '', composebox.input_, + '', composebox.input, 'Input should not be updated in composebox without final result'); callback(); @@ -539,7 +540,7 @@ assertEquals( composebox.animationState, GlowAnimationState.SUBMITTING, 'Query is submitted via submitQuery_()'); - assertEquals(composebox.input_, '', 'Input should be cleared after submit'); + assertEquals(composebox.input, '', 'Input should be cleared after submit'); assertEquals( '', voiceSearchInput.value,
diff --git a/chrome/test/data/webui/contextual_tasks/composebox_submit_test.ts b/chrome/test/data/webui/contextual_tasks/composebox_submit_test.ts index 83c9d25..6e125f710 100644 --- a/chrome/test/data/webui/contextual_tasks/composebox_submit_test.ts +++ b/chrome/test/data/webui/contextual_tasks/composebox_submit_test.ts
@@ -14,7 +14,8 @@ import {WindowProxy} from 'chrome://resources/cr_components/composebox/window_proxy.js'; import {GlowAnimationState} from 'chrome://resources/cr_components/search/constants.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; -import {PageCallbackRouter as SearchboxPageCallbackRouter, PageHandlerRemote as SearchboxPageHandlerRemote, type PageRemote as SearchboxPageRemote} from 'chrome://resources/mojo/components/omnibox/browser/searchbox.mojom-webui.js'; +import {PageCallbackRouter as SearchboxPageCallbackRouter, PageHandlerRemote as SearchboxPageHandlerRemote} from 'chrome://resources/mojo/components/omnibox/browser/searchbox.mojom-webui.js'; +import type {PageRemote as SearchboxPageRemote} from 'chrome://resources/mojo/components/omnibox/browser/searchbox.mojom-webui.js'; import {assertEquals, assertFalse, assertNotEquals, assertTrue} from 'chrome://webui-test/chai_assert.js'; import {MockTimer} from 'chrome://webui-test/mock_timer.js'; import {TestMock} from 'chrome://webui-test/test_mock.js'; @@ -463,7 +464,7 @@ await composebox.updateComplete; await microtasksFinished(); - assertEquals(0, composebox.files_.size); + assertEquals(0, composebox.files.size); // Should be no longer `EXPANDING` after successful upload and submit click. assertNotEquals(composebox.animationState, GlowAnimationState.EXPANDING); @@ -479,7 +480,7 @@ ContextUploadStatus.kProcessingSuggestSignalsReady, /*error_type=*/ null, ); - composebox.input_ = 'test'; + composebox.input = 'test'; await searchboxCallbackRouterRemote.$.flushForTesting(); await microtasksFinished(); await composebox.updateComplete; @@ -666,7 +667,7 @@ await composebox.updateComplete; await microtasksFinished(); - assertEquals(0, composebox.files_.size); + assertEquals(0, composebox.files.size); // Should be no longer `EXPANDING` after successful upload and submit click. assertNotEquals(composebox.animationState, GlowAnimationState.EXPANDING); @@ -674,7 +675,7 @@ test('Composebox submit button disabled when uploading tabs', async () => { const callback = (file: ComposeboxFile) => { - composebox.files_.set(file.uuid, file); + composebox.files.set(file.uuid, file); composebox.contextFilesSize_ += 1; composebox.submitEnabled_ = composebox.computeSubmitEnabled_(); composebox.requestUpdate(); @@ -765,7 +766,7 @@ await composebox.updateComplete; await microtasksFinished(); - assertEquals(0, composebox.files_.size); + assertEquals(0, composebox.files.size); // Should be no longer `EXPANDING` after successful upload and submit click. assertNotEquals(composebox.animationState, GlowAnimationState.EXPANDING); @@ -824,12 +825,12 @@ composebox.animationState, GlowAnimationState.SUBMITTING, 'Query is submitted via submitQuery_()'); - assertEquals(0, composebox.files_.size); + assertEquals(0, composebox.files.size); }); test('delayed tabs do not delay submission', async () => { const callback = (file: any) => { - composebox.files_.set(file.uuid, file); + composebox.files.set(file.uuid, file); composebox.contextFilesSize_ = 1; composebox.submitEnabled_ = composebox.computeSubmitEnabled_(); composebox.requestUpdate(); @@ -1099,7 +1100,7 @@ /*supportsUnimodal=*/ false); searchboxCallbackRouterRemote.onContextualInputStatusChanged( FAKE_TOKEN_STRING, ContextUploadStatus.kUploadSuccessful, null); - composebox.input_ = 'test'; + composebox.input = 'test'; // Multiple calls needed to avoid flaking. // TODO(crbug.com/490496860): Investigate removing.
diff --git a/chrome/test/data/webui/contextual_tasks/composebox_test.ts b/chrome/test/data/webui/contextual_tasks/composebox_test.ts index 9da19c8..73e333ea 100644 --- a/chrome/test/data/webui/contextual_tasks/composebox_test.ts +++ b/chrome/test/data/webui/contextual_tasks/composebox_test.ts
@@ -12,7 +12,8 @@ import {ContextUploadStatus, ToolMode} from 'chrome://resources/cr_components/composebox/composebox_query.mojom-webui.js'; import {createAutocompleteMatch, createAutocompleteResultForTesting} from 'chrome://resources/cr_components/searchbox/searchbox_browser_proxy.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; -import {PageCallbackRouter as SearchboxPageCallbackRouter, PageHandlerRemote as SearchboxPageHandlerRemote, type PageRemote as SearchboxPageRemote} from 'chrome://resources/mojo/components/omnibox/browser/searchbox.mojom-webui.js'; +import {PageCallbackRouter as SearchboxPageCallbackRouter, PageHandlerRemote as SearchboxPageHandlerRemote} from 'chrome://resources/mojo/components/omnibox/browser/searchbox.mojom-webui.js'; +import type {PageRemote as SearchboxPageRemote} from 'chrome://resources/mojo/components/omnibox/browser/searchbox.mojom-webui.js'; import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; import {MockTimer} from 'chrome://webui-test/mock_timer.js'; import {TestMock} from 'chrome://webui-test/test_mock.js'; @@ -229,7 +230,7 @@ microtasksFinished(), ]); - assertEquals(0, composebox.files_.size); + assertEquals(0, composebox.files.size); const submitButton: HTMLButtonElement|null = getSubmitButton(composebox); assertTrue(!!submitButton, 'Submit button should exist'); @@ -257,7 +258,7 @@ token1, new File(['foo'], 'foo.jpg', {type: 'image/jpeg'}), composebox, mockSearchboxPageHandler); - const currentFiles = composebox.files_; + const currentFiles = composebox.files; currentFiles.forEach((file: ComposeboxFile) => { file.isDeletable = false; }); @@ -320,7 +321,7 @@ await composebox.updateComplete; await microtasksFinished(); - const currentFiles2 = composebox.files_; + const currentFiles2 = composebox.files; currentFiles2.forEach((file: ComposeboxFile) => { file.isDeletable = false; });
diff --git a/chrome/test/data/webui/contextual_tasks/composebox_zero_state_test.ts b/chrome/test/data/webui/contextual_tasks/composebox_zero_state_test.ts index 85de32e..100d72e5 100644 --- a/chrome/test/data/webui/contextual_tasks/composebox_zero_state_test.ts +++ b/chrome/test/data/webui/contextual_tasks/composebox_zero_state_test.ts
@@ -14,7 +14,8 @@ import {WindowProxy} from 'chrome://resources/cr_components/composebox/window_proxy.js'; import {GlowAnimationState} from 'chrome://resources/cr_components/search/constants.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; -import {PageCallbackRouter as SearchboxPageCallbackRouter, PageHandlerRemote as SearchboxPageHandlerRemote, type PageRemote as SearchboxPageRemote} from 'chrome://resources/mojo/components/omnibox/browser/searchbox.mojom-webui.js'; +import {PageCallbackRouter as SearchboxPageCallbackRouter, PageHandlerRemote as SearchboxPageHandlerRemote} from 'chrome://resources/mojo/components/omnibox/browser/searchbox.mojom-webui.js'; +import type {PageRemote as SearchboxPageRemote} from 'chrome://resources/mojo/components/omnibox/browser/searchbox.mojom-webui.js'; import {assertEquals, assertFalse, assertNotEquals, assertTrue} from 'chrome://webui-test/chai_assert.js'; import {MockTimer} from 'chrome://webui-test/mock_timer.js'; import {TestMock} from 'chrome://webui-test/test_mock.js'; @@ -712,7 +713,7 @@ await composebox.updateComplete; await microtasksFinished(); - assertEquals(0, composebox.files_.size); + assertEquals(0, composebox.files.size); // Should be no longer `EXPANDING` after successful upload and submit // click. @@ -761,7 +762,7 @@ await microtasksFinished(); toolChip = composebox.shadowRoot.querySelector('cr-composebox-tool-chip'); - assertFalse(!!composebox.input_, 'Input value should be cleared'); + assertFalse(!!composebox.input, 'Input value should be cleared'); assertTrue( composebox.fileUploadsComplete, 'File uploads should be complete'); assertFalse(
diff --git a/chrome/test/data/webui/cr_components/searchbox/searchbox_focus_test.ts b/chrome/test/data/webui/cr_components/searchbox/searchbox_focus_test.ts index aaaf469..9335b294 100644 --- a/chrome/test/data/webui/cr_components/searchbox/searchbox_focus_test.ts +++ b/chrome/test/data/webui/cr_components/searchbox/searchbox_focus_test.ts
@@ -60,7 +60,7 @@ // Force a synchronous render. await testProxy.callbackRouterRemote.$.flushForTesting(); await microtasksFinished(); - return window.getComputedStyle(realbox.getSuggestionsElement()).display !== + return window.getComputedStyle(realbox.getDropdownElement()).display !== 'none'; }
diff --git a/chrome/test/data/webui/cr_components/searchbox/searchbox_lens_test.ts b/chrome/test/data/webui/cr_components/searchbox/searchbox_lens_test.ts index a6174b8..09ea9a86 100644 --- a/chrome/test/data/webui/cr_components/searchbox/searchbox_lens_test.ts +++ b/chrome/test/data/webui/cr_components/searchbox/searchbox_lens_test.ts
@@ -25,7 +25,7 @@ async function areMatchesShowing(): Promise<boolean> { await testProxy.callbackRouterRemote.$.flushForTesting(); await microtasksFinished(); - return window.getComputedStyle(realbox.getSuggestionsElement()).display !== + return window.getComputedStyle(realbox.getDropdownElement()).display !== 'none'; }
diff --git a/chrome/test/data/webui/cr_components/searchbox/searchbox_test.ts b/chrome/test/data/webui/cr_components/searchbox/searchbox_test.ts index 3716c5b1..cfcad6b 100644 --- a/chrome/test/data/webui/cr_components/searchbox/searchbox_test.ts +++ b/chrome/test/data/webui/cr_components/searchbox/searchbox_test.ts
@@ -207,7 +207,7 @@ // Force a synchronous render. await testProxy.callbackRouterRemote.$.flushForTesting(); await microtasksFinished(); - return window.getComputedStyle(realbox.getSuggestionsElement()).display !== + return window.getComputedStyle(realbox.getDropdownElement()).display !== 'none'; } @@ -551,9 +551,8 @@ })); assertTrue(await areMatchesShowing()); - const matchEls = - realbox.getSuggestionsElement().shadowRoot.querySelectorAll( - 'cr-searchbox-match'); + const matchEls = realbox.getDropdownElement().shadowRoot.querySelectorAll( + 'cr-searchbox-match'); assertEquals(2, matchEls.length); // Left click does not query autocomplete when matches are showing. @@ -620,9 +619,8 @@ })); assertTrue(await areMatchesShowing()); - const matchEls = - realbox.getSuggestionsElement().shadowRoot.querySelectorAll( - 'cr-searchbox-match'); + const matchEls = realbox.getDropdownElement().shadowRoot.querySelectorAll( + 'cr-searchbox-match'); assertEquals(2, matchEls.length, 'match count'); // Tabbing into input does not query autocomplete when matches are @@ -693,9 +691,8 @@ })); assertTrue(await areMatchesShowing()); - const matchEls = - realbox.getSuggestionsElement().shadowRoot.querySelectorAll( - 'cr-searchbox-match'); + const matchEls = realbox.getDropdownElement().shadowRoot.querySelectorAll( + 'cr-searchbox-match'); assertEquals(2, matchEls.length); // Arrow up/down keys do not query autocomplete when matches are showing. @@ -755,9 +752,8 @@ })); assertTrue(await areMatchesShowing(), 'matches showing'); - const matchEls = - realbox.getSuggestionsElement().shadowRoot.querySelectorAll( - 'cr-searchbox-match'); + const matchEls = realbox.getDropdownElement().shadowRoot.querySelectorAll( + 'cr-searchbox-match'); assertEquals(2, matchEls.length); // Arrow up/down keys do not query autocomplete when matches are showing. @@ -964,11 +960,9 @@ })); assertTrue(await areMatchesShowing()); - assertEquals( - 'listbox', realbox.getSuggestionsElement().getAttribute('role')); - const matchEls = - realbox.getSuggestionsElement().shadowRoot.querySelectorAll( - 'cr-searchbox-match'); + assertEquals('listbox', realbox.getDropdownElement().getAttribute('role')); + const matchEls = realbox.getDropdownElement().shadowRoot.querySelectorAll( + 'cr-searchbox-match'); assertEquals(2, matchEls.length); verifyMatch(matches[0]!, matchEls[0]!); verifyMatch(matches[1]!, matchEls[1]!); @@ -1003,9 +997,8 @@ })); assertTrue(await areMatchesShowing()); - const matchEls = - realbox.getSuggestionsElement().shadowRoot.querySelectorAll( - 'cr-searchbox-match'); + const matchEls = realbox.getDropdownElement().shadowRoot.querySelectorAll( + 'cr-searchbox-match'); assertEquals(1, matchEls.length); verifyMatch(matches[0]!, matchEls[0]!); @@ -1091,9 +1084,8 @@ })); assertFalse(await areMatchesShowing()); - const matchEls = - realbox.getSuggestionsElement().shadowRoot.querySelectorAll( - 'cr-searchbox-match'); + const matchEls = realbox.getDropdownElement().shadowRoot.querySelectorAll( + 'cr-searchbox-match'); assertEquals(0, matchEls.length); }); @@ -1109,7 +1101,7 @@ })); assertTrue(await areMatchesShowing()); - let matchEls = realbox.getSuggestionsElement().shadowRoot.querySelectorAll( + let matchEls = realbox.getDropdownElement().shadowRoot.querySelectorAll( 'cr-searchbox-match'); assertEquals(2, matchEls.length); @@ -1122,7 +1114,7 @@ })); assertFalse(await areMatchesShowing()); - matchEls = realbox.getSuggestionsElement().shadowRoot.querySelectorAll( + matchEls = realbox.getDropdownElement().shadowRoot.querySelectorAll( 'cr-searchbox-match'); assertEquals(0, matchEls.length); @@ -1136,7 +1128,7 @@ })); assertTrue(await areMatchesShowing()); - matchEls = realbox.getSuggestionsElement().shadowRoot.querySelectorAll( + matchEls = realbox.getDropdownElement().shadowRoot.querySelectorAll( 'cr-searchbox-match'); assertEquals(2, matchEls.length); }); @@ -1307,9 +1299,8 @@ })); assertTrue(await areMatchesShowing()); - const matchEls = - realbox.getSuggestionsElement().shadowRoot.querySelectorAll( - 'cr-searchbox-match'); + const matchEls = realbox.getDropdownElement().shadowRoot.querySelectorAll( + 'cr-searchbox-match'); assertEquals(2, matchEls.length); // First match is selected. @@ -1372,9 +1363,8 @@ })); assertTrue(await areMatchesShowing()); - let matchEls = - realbox.getSuggestionsElement().shadowRoot.querySelectorAll( - 'cr-searchbox-match'); + let matchEls = realbox.getDropdownElement().shadowRoot.querySelectorAll( + 'cr-searchbox-match'); assertEquals(2, matchEls.length); // Select the first match. @@ -1404,7 +1394,7 @@ assertFalse(await areMatchesShowing()); // First match is still selected. - matchEls = realbox.getSuggestionsElement().shadowRoot.querySelectorAll( + matchEls = realbox.getDropdownElement().shadowRoot.querySelectorAll( 'cr-searchbox-match'); assertEquals(2, matchEls.length); assertTrue(matchEls[0]!.hasAttribute(Attributes.SELECTED)); @@ -1450,9 +1440,8 @@ })); assertTrue(await areMatchesShowing()); - const matchEls = - realbox.getSuggestionsElement().shadowRoot.querySelectorAll( - 'cr-searchbox-match'); + const matchEls = realbox.getDropdownElement().shadowRoot.querySelectorAll( + 'cr-searchbox-match'); assertEquals(2, matchEls.length); // First match is not selected. @@ -1490,9 +1479,8 @@ })); assertTrue(await areMatchesShowing()); - let matchEls = - realbox.getSuggestionsElement().shadowRoot.querySelectorAll( - 'cr-searchbox-match'); + let matchEls = realbox.getDropdownElement().shadowRoot.querySelectorAll( + 'cr-searchbox-match'); assertEquals(2, matchEls.length); // Select the first match. @@ -1522,7 +1510,7 @@ assertFalse(await areMatchesShowing()); // Matches are cleared. - matchEls = realbox.getSuggestionsElement().shadowRoot.querySelectorAll( + matchEls = realbox.getDropdownElement().shadowRoot.querySelectorAll( 'cr-searchbox-match'); assertEquals(0, matchEls.length); // Input is cleared (zero-prefix case). @@ -1566,9 +1554,8 @@ })); assertTrue(await areMatchesShowing()); - const matchEls = - realbox.getSuggestionsElement().shadowRoot.querySelectorAll( - 'cr-searchbox-match'); + const matchEls = realbox.getDropdownElement().shadowRoot.querySelectorAll( + 'cr-searchbox-match'); assertEquals(2, matchEls.length); // First match is selected. @@ -1634,9 +1621,8 @@ })); assertTrue(await areMatchesShowing()); - const matchEls = - realbox.getSuggestionsElement().shadowRoot.querySelectorAll( - 'cr-searchbox-match'); + const matchEls = realbox.getDropdownElement().shadowRoot.querySelectorAll( + 'cr-searchbox-match'); assertEquals(2, matchEls.length); // First match is selected. @@ -1680,9 +1666,8 @@ })); assertTrue(await areMatchesShowing()); - const matchEls = - realbox.getSuggestionsElement().shadowRoot.querySelectorAll( - 'cr-searchbox-match'); + const matchEls = realbox.getDropdownElement().shadowRoot.querySelectorAll( + 'cr-searchbox-match'); assertEquals(2, matchEls.length); assertEquals( @@ -1716,9 +1701,8 @@ })); assertTrue(await areMatchesShowing()); - const matchEls = - realbox.getSuggestionsElement().shadowRoot.querySelectorAll( - 'cr-searchbox-match'); + const matchEls = realbox.getDropdownElement().shadowRoot.querySelectorAll( + 'cr-searchbox-match'); assertEquals(2, matchEls.length); // First match is selected. assertTrue(matchEls[0]!.hasAttribute(Attributes.SELECTED)); @@ -1776,7 +1760,7 @@ })); assertTrue(await areMatchesShowing()); - let matchEls = realbox.getSuggestionsElement().shadowRoot.querySelectorAll( + let matchEls = realbox.getDropdownElement().shadowRoot.querySelectorAll( 'cr-searchbox-match'); assertEquals(1, matchEls.length); @@ -1799,7 +1783,7 @@ })); assertTrue(await areMatchesShowing()); - matchEls = realbox.getSuggestionsElement().shadowRoot.querySelectorAll( + matchEls = realbox.getDropdownElement().shadowRoot.querySelectorAll( 'cr-searchbox-match'); assertEquals(1, matchEls.length); @@ -1836,7 +1820,7 @@ })); assertTrue(await areMatchesShowing()); - matchEls = realbox.getSuggestionsElement().shadowRoot.querySelectorAll( + matchEls = realbox.getDropdownElement().shadowRoot.querySelectorAll( 'cr-searchbox-match'); assertEquals(1, matchEls.length); @@ -1863,9 +1847,8 @@ })); assertTrue(await areMatchesShowing()); - let matchEls = - realbox.getSuggestionsElement().shadowRoot.querySelectorAll( - 'cr-searchbox-match'); + let matchEls = realbox.getDropdownElement().shadowRoot.querySelectorAll( + 'cr-searchbox-match'); assertEquals(2, matchEls.length); // Select the second match. @@ -1881,8 +1864,7 @@ assertEquals( 'https://helloworld.com', realbox.$.input.inputElement.value); assertEquals( - matchEls[1], - realbox.getSuggestionsElement().shadowRoot.activeElement); + matchEls[1], realbox.getDropdownElement().shadowRoot.activeElement); let escapeEvent = new KeyboardEvent('keydown', { bubbles: true, @@ -1898,8 +1880,7 @@ assertTrue(matchEls[0]!.hasAttribute(Attributes.SELECTED)); assertEquals('hello world', realbox.$.input.inputElement.value); assertEquals( - matchEls[0], - realbox.getSuggestionsElement().shadowRoot.activeElement); + matchEls[0], realbox.getDropdownElement().shadowRoot.activeElement); escapeEvent = new KeyboardEvent('keydown', { bubbles: true, @@ -1914,7 +1895,7 @@ assertFalse(await areMatchesShowing()); // Matches are cleared. - matchEls = realbox.getSuggestionsElement().shadowRoot.querySelectorAll( + matchEls = realbox.getDropdownElement().shadowRoot.querySelectorAll( 'cr-searchbox-match'); assertEquals(0, matchEls.length); // Input is cleared. @@ -1929,7 +1910,7 @@ })); assertTrue(await areMatchesShowing()); - matchEls = realbox.getSuggestionsElement().shadowRoot.querySelectorAll( + matchEls = realbox.getDropdownElement().shadowRoot.querySelectorAll( 'cr-searchbox-match'); assertEquals(2, matchEls.length); @@ -1947,7 +1928,7 @@ assertFalse(await areMatchesShowing()); // Matches are cleared. - matchEls = realbox.getSuggestionsElement().shadowRoot.querySelectorAll( + matchEls = realbox.getDropdownElement().shadowRoot.querySelectorAll( 'cr-searchbox-match'); assertEquals(0, matchEls.length); }); @@ -1968,9 +1949,8 @@ })); assertTrue(await areMatchesShowing()); - const matchEls = - realbox.getSuggestionsElement().shadowRoot.querySelectorAll( - 'cr-searchbox-match'); + const matchEls = realbox.getDropdownElement().shadowRoot.querySelectorAll( + 'cr-searchbox-match'); assertEquals(2, matchEls.length); let arrowDownEvent = arrowDown(realbox); @@ -2023,7 +2003,7 @@ assertTrue(matchEls[1]!.hasAttribute(Attributes.SELECTED)); assertEquals('https://helloworld.com', realbox.$.input.inputElement.value); assertEquals( - matchEls[1], realbox.getSuggestionsElement().shadowRoot.activeElement); + matchEls[1], realbox.getDropdownElement().shadowRoot.activeElement); const arrowUpEvent = new KeyboardEvent('keydown', { bubbles: true, @@ -2039,7 +2019,7 @@ assertTrue(matchEls[0]!.hasAttribute(Attributes.SELECTED)); assertEquals('hello world', realbox.$.input.inputElement.value); assertEquals( - matchEls[0], realbox.getSuggestionsElement().shadowRoot.activeElement); + matchEls[0], realbox.getDropdownElement().shadowRoot.activeElement); // Changing match selection doesn't result in another onFocusChanged call // because focus is for the whole realbox (including input container). @@ -2070,9 +2050,8 @@ })); assertTrue(await areMatchesShowing()); - const matchEls = - realbox.getSuggestionsElement().shadowRoot.querySelectorAll( - 'cr-searchbox-match'); + const matchEls = realbox.getDropdownElement().shadowRoot.querySelectorAll( + 'cr-searchbox-match'); const focusIndicator = matchEls[0]!.$.focusIndicator; @@ -2206,7 +2185,7 @@ assertTrue(await areMatchesShowing()); const matchEls = - realbox.getSuggestionsElement().shadowRoot.querySelectorAll( + realbox.getDropdownElement().shadowRoot.querySelectorAll( 'cr-searchbox-match'); assertEquals(2, matchEls.length); assertIconMaskImageUrl(matchEls[0]!.$.icon, 'clock.svg'); @@ -2314,7 +2293,7 @@ assertTrue(await areMatchesShowing()); const matchEls = - realbox.getSuggestionsElement().shadowRoot.querySelectorAll( + realbox.getDropdownElement().shadowRoot.querySelectorAll( 'cr-searchbox-match'); assertEquals(2, matchEls.length); // TODO(crbug.com/328270499): Uncomment once flakiness is fixed. @@ -2472,7 +2451,7 @@ assertTrue(await areMatchesShowing()); const matchEls = - realbox.getSuggestionsElement().shadowRoot.querySelectorAll( + realbox.getDropdownElement().shadowRoot.querySelectorAll( 'cr-searchbox-match'); assertEquals(2, matchEls.length); @@ -2599,9 +2578,8 @@ })); assertTrue(await areMatchesShowing()); - const matchEls = - realbox.getSuggestionsElement().shadowRoot.querySelectorAll( - 'cr-searchbox-match'); + const matchEls = realbox.getDropdownElement().shadowRoot.querySelectorAll( + 'cr-searchbox-match'); assertEquals(2, matchEls.length); let faviconImage = matchEls[0]!.$.icon.$.faviconImage; @@ -2718,9 +2696,8 @@ })); assertTrue(await areMatchesShowing()); - const matchEls = - realbox.getSuggestionsElement().shadowRoot.querySelectorAll( - 'cr-searchbox-match'); + const matchEls = realbox.getDropdownElement().shadowRoot.querySelectorAll( + 'cr-searchbox-match'); assertEquals(1, matchEls.length); // Select the first match. @@ -2787,9 +2764,8 @@ })); assertTrue(await areMatchesShowing()); - const matchEls = - realbox.getSuggestionsElement().shadowRoot.querySelectorAll( - 'cr-searchbox-match'); + const matchEls = realbox.getDropdownElement().shadowRoot.querySelectorAll( + 'cr-searchbox-match'); assertEquals(1, matchEls.length); verifyMatch(matches[0]!, matchEls[0]!); @@ -2832,9 +2808,8 @@ })); assertTrue(await areMatchesShowing()); - const matchEls = - realbox.getSuggestionsElement().shadowRoot.querySelectorAll( - 'cr-searchbox-match'); + const matchEls = realbox.getDropdownElement().shadowRoot.querySelectorAll( + 'cr-searchbox-match'); verifyMatch(matches[0]!, matchEls[0]!); // Separator is not displayed @@ -2883,9 +2858,8 @@ })); assertTrue(await areMatchesShowing()); - const matchEls = - realbox.getSuggestionsElement().shadowRoot.querySelectorAll( - 'cr-searchbox-match'); + const matchEls = realbox.getDropdownElement().shadowRoot.querySelectorAll( + 'cr-searchbox-match'); verifyMatch(matches[0]!, matchEls[0]!); verifyMatch(matches[1]!, matchEls[1]!); @@ -2931,7 +2905,7 @@ })); assertTrue(await areMatchesShowing()); - const matchEl = $$(realbox.getSuggestionsElement(), 'cr-searchbox-match')!; + const matchEl = $$(realbox.getDropdownElement(), 'cr-searchbox-match')!; verifyMatch(matches[0]!, matchEl); const pedalEl = $$($$(matchEl, 'cr-searchbox-action')!, '.contents')!; @@ -2984,9 +2958,8 @@ })); assertTrue(await areMatchesShowing()); - const matchEls = - realbox.getSuggestionsElement().shadowRoot.querySelectorAll( - 'cr-searchbox-match'); + const matchEls = realbox.getDropdownElement().shadowRoot.querySelectorAll( + 'cr-searchbox-match'); verifyMatch(matches[0]!, matchEls[0]!); verifyMatch(matches[1]!, matchEls[1]!);
diff --git a/chrome/test/data/webui/cr_components/searchbox/test_searchbox_browser_proxy.ts b/chrome/test/data/webui/cr_components/searchbox/test_searchbox_browser_proxy.ts index 2503649..8564a3b 100644 --- a/chrome/test/data/webui/cr_components/searchbox/test_searchbox_browser_proxy.ts +++ b/chrome/test/data/webui/cr_components/searchbox/test_searchbox_browser_proxy.ts
@@ -48,7 +48,9 @@ 'submitQuery', 'openLensSearch', 'setActiveToolMode', + 'recordToolSelectionAction', 'setActiveModelMode', + 'recordModelSelectionAction', 'setPage', 'getInputState', 'activateMetricsFunnel', @@ -235,10 +237,18 @@ this.methodCalled('setActiveToolMode', tool); } + recordToolSelectionAction(tool: ToolMode) { + this.methodCalled('recordToolSelectionAction', tool); + } + setActiveModelMode(model: ModelMode) { this.methodCalled('setActiveModelMode', model); } + recordModelSelectionAction(model: ModelMode) { + this.methodCalled('recordModelSelectionAction', model); + } + activateMetricsFunnel(funnelName: string) { this.methodCalled('activateMetricsFunnel', funnelName); }
diff --git a/chrome/test/data/webui/history/test_browser_service.ts b/chrome/test/data/webui/history/test_browser_service.ts index a3c2ce1..34d2439 100644 --- a/chrome/test/data/webui/history/test_browser_service.ts +++ b/chrome/test/data/webui/history/test_browser_service.ts
@@ -7,8 +7,8 @@ import { PageCallbackRouter, PageHandlerRemote, - type PageRemote, } from 'chrome://resources/cr_components/history/history.mojom-webui.js'; +import type {PageRemote} from 'chrome://resources/cr_components/history/history.mojom-webui.js'; import {assertTrue} from 'chrome://webui-test/chai_assert.js'; import {TestBrowserProxy} from 'chrome://webui-test/test_browser_proxy.js'; import {TestMock} from 'chrome://webui-test/test_mock.js';
diff --git a/chrome/test/data/webui/js/icon_test.ts b/chrome/test/data/webui/js/icon_test.ts index 9fa0ed2..1ffbd2d 100644 --- a/chrome/test/data/webui/js/icon_test.ts +++ b/chrome/test/data/webui/js/icon_test.ts
@@ -2,7 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import {getFavicon, getFaviconForPageURL, getFaviconUrl, type GetFaviconUrlParams, getFileIconUrl} from 'chrome://resources/js/icon.js'; +import {getFavicon, getFaviconForPageURL, getFaviconUrl, getFileIconUrl} from 'chrome://resources/js/icon.js'; +import type {GetFaviconUrlParams} from 'chrome://resources/js/icon.js'; import {isAndroid, isChromeOS, isLinux, isMac, isWindows} from 'chrome://resources/js/platform.js'; import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
diff --git a/chrome/test/data/webui/lens/ghost_loader/test_ghost_loader_browser_proxy.ts b/chrome/test/data/webui/lens/ghost_loader/test_ghost_loader_browser_proxy.ts index 66c47e6..abc4c5031 100644 --- a/chrome/test/data/webui/lens/ghost_loader/test_ghost_loader_browser_proxy.ts +++ b/chrome/test/data/webui/lens/ghost_loader/test_ghost_loader_browser_proxy.ts
@@ -2,7 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import {LensGhostLoaderPageCallbackRouter, type LensGhostLoaderPageRemote} from 'chrome-untrusted://lens/lens/shared/lens_ghost_loader.mojom-webui.js'; +import {LensGhostLoaderPageCallbackRouter} from 'chrome-untrusted://lens/lens/shared/lens_ghost_loader.mojom-webui.js'; +import type {LensGhostLoaderPageRemote} from 'chrome-untrusted://lens/lens/shared/lens_ghost_loader.mojom-webui.js'; import type {BrowserProxy} from 'chrome-untrusted://lens/lens/shared/searchbox_ghost_loader_browser_proxy.js'; import {TestBrowserProxy} from 'chrome-untrusted://webui-test/test_browser_proxy.js';
diff --git a/chrome/test/data/webui/lens/side_panel/composebox_test.ts b/chrome/test/data/webui/lens/side_panel/composebox_test.ts index 8ce0019e..fefee614 100644 --- a/chrome/test/data/webui/lens/side_panel/composebox_test.ts +++ b/chrome/test/data/webui/lens/side_panel/composebox_test.ts
@@ -10,7 +10,8 @@ import {ComposeboxProxyImpl} from 'chrome-untrusted://resources/cr_components/composebox/composebox_proxy.js'; import {createAutocompleteResultForTesting, createSearchMatchForTesting} from 'chrome-untrusted://resources/cr_components/searchbox/searchbox_browser_proxy.js'; import {loadTimeData} from 'chrome-untrusted://resources/js/load_time_data.js'; -import {PageCallbackRouter as SearchboxPageCallbackRouter, PageHandlerRemote as SearchboxPageHandlerRemote, type PageRemote as SearchboxPageRemote} from 'chrome-untrusted://resources/mojo/components/omnibox/browser/searchbox.mojom-webui.js'; +import {PageCallbackRouter as SearchboxPageCallbackRouter, PageHandlerRemote as SearchboxPageHandlerRemote} from 'chrome-untrusted://resources/mojo/components/omnibox/browser/searchbox.mojom-webui.js'; +import type {PageRemote as SearchboxPageRemote} from 'chrome-untrusted://resources/mojo/components/omnibox/browser/searchbox.mojom-webui.js'; import {assertEquals, assertFalse, assertNotEquals, assertTrue} from 'chrome-untrusted://webui-test/chai_assert.js'; import {waitAfterNextRender} from 'chrome-untrusted://webui-test/polymer_test_util.js'; import {TestMock} from 'chrome-untrusted://webui-test/test_mock.js';
diff --git a/chrome/test/data/webui/lens/side_panel/test_side_panel_browser_proxy.ts b/chrome/test/data/webui/lens/side_panel/test_side_panel_browser_proxy.ts index 58e1fc2b..2ba75954 100644 --- a/chrome/test/data/webui/lens/side_panel/test_side_panel_browser_proxy.ts +++ b/chrome/test/data/webui/lens/side_panel/test_side_panel_browser_proxy.ts
@@ -2,7 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import {LensSidePanelPageCallbackRouter, type LensSidePanelPageHandlerInterface, type LensSidePanelPageRemote} from 'chrome-untrusted://lens/lens_side_panel.mojom-webui.js'; +import {LensSidePanelPageCallbackRouter} from 'chrome-untrusted://lens/lens_side_panel.mojom-webui.js'; +import type {LensSidePanelPageHandlerInterface, LensSidePanelPageRemote} from 'chrome-untrusted://lens/lens_side_panel.mojom-webui.js'; import type {SidePanelBrowserProxy} from 'chrome-untrusted://lens/side_panel/side_panel_browser_proxy.js'; import {TestBrowserProxy} from 'chrome-untrusted://webui-test/test_browser_proxy.js';
diff --git a/chrome/test/data/webui/new_tab_page/composebox/composebox_test.ts b/chrome/test/data/webui/new_tab_page/composebox/composebox_test.ts index a9b86b74..316ea6b 100644 --- a/chrome/test/data/webui/new_tab_page/composebox/composebox_test.ts +++ b/chrome/test/data/webui/new_tab_page/composebox/composebox_test.ts
@@ -818,7 +818,7 @@ } as InputState; testProxy.searchboxCallbackRouterRemote.onInputStateChanged(inputState); await microtasksFinished(); - assertDeepEquals((testProxy.element as any).inputState_, inputState); + assertDeepEquals((testProxy.element as any).inputState, inputState); }); test('setDefaultModel uses activeModel from backend', async () => { @@ -862,7 +862,7 @@ await microtasksFinished(); // Set active tool mode to DeepSearch. - testProxy.element['activeToolMode_'] = ComposeboxToolMode.kDeepSearch; + testProxy.element['activeToolMode'] = ComposeboxToolMode.kDeepSearch; await testProxy.element.updateComplete; // Click on the same tool mode to deselect/delete it. @@ -871,7 +871,7 @@ // Assert tool mode is reset. assertEquals( - testProxy.element['activeToolMode_'], ComposeboxToolMode.kUnspecified); + testProxy.element['activeToolMode'], ComposeboxToolMode.kUnspecified); const metricName = 'ContextualSearch.UserAction.InputStateDeletion.Tool.NewTabPage';
diff --git a/chrome/test/data/webui/new_tab_page/composebox/composebox_upload_test.ts b/chrome/test/data/webui/new_tab_page/composebox/composebox_upload_test.ts index e67e69d..7d62ac3 100644 --- a/chrome/test/data/webui/new_tab_page/composebox/composebox_upload_test.ts +++ b/chrome/test/data/webui/new_tab_page/composebox/composebox_upload_test.ts
@@ -527,12 +527,12 @@ assertFalse(testProxy.element['uploadButtonDisabled_']); // Enter create image mode. - testProxy.element['activeToolMode_'] = ComposeboxToolMode.kImageGen; + testProxy.element['activeToolMode'] = ComposeboxToolMode.kImageGen; await testProxy.element.updateComplete; assertFalse(testProxy.element['uploadButtonDisabled_']); // Exit create image mode. `uploadButtonDisabled` should be false. - testProxy.element['activeToolMode_'] = ComposeboxToolMode.kUnspecified; + testProxy.element['activeToolMode'] = ComposeboxToolMode.kUnspecified; await testProxy.element.updateComplete; assertFalse(testProxy.element['uploadButtonDisabled_']); }); @@ -942,6 +942,13 @@ assertEquals( ComposeboxToolMode.kImageGen, testProxy.searchboxHandler.getArgs('setActiveToolMode')[0]); + assertEquals( + testProxy.searchboxHandler.getCallCount('recordToolSelectionAction'), + 1); + assertEquals( + ComposeboxToolMode.kImageGen, + testProxy.searchboxHandler.getArgs('recordToolSelectionAction')[0]); + }); test('composebox does not open match when only file present', async () => {
diff --git a/chrome/test/data/webui/settings/glic_subpage_test.ts b/chrome/test/data/webui/settings/glic_subpage_test.ts index 6e793f90..6018b9ee 100644 --- a/chrome/test/data/webui/settings/glic_subpage_test.ts +++ b/chrome/test/data/webui/settings/glic_subpage_test.ts
@@ -5,9 +5,10 @@ import 'chrome://settings/settings.js'; import {webUIListenerCallback} from 'chrome://resources/js/cr.js'; -import {AiPageActions, type CrCollapseElement} from 'chrome://settings/lazy_load.js'; -import type {SettingsGlicSubpageElement, SettingsPrefsElement, SettingsToggleButtonElement} from 'chrome://settings/settings.js'; +import {AiPageActions} from 'chrome://settings/lazy_load.js'; +import type {CrCollapseElement} from 'chrome://settings/lazy_load.js'; import {CrSettingsPrefs, GlicBrowserProxyImpl, loadTimeData, MetricsBrowserProxyImpl, OpenWindowProxyImpl, resetRouterForTesting, Router, routes, SettingsGlicPageFeaturePrefName as PrefName} from 'chrome://settings/settings.js'; +import type {SettingsGlicSubpageElement, SettingsPrefsElement, SettingsToggleButtonElement} from 'chrome://settings/settings.js'; import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; import {flushTasks} from 'chrome://webui-test/polymer_test_util.js'; import {TestOpenWindowProxy} from 'chrome://webui-test/test_open_window_proxy.js';
diff --git a/chrome/test/data/webui/settings/system_page_test.ts b/chrome/test/data/webui/settings/system_page_test.ts index ffdc1f9..1f8cb50 100644 --- a/chrome/test/data/webui/settings/system_page_test.ts +++ b/chrome/test/data/webui/settings/system_page_test.ts
@@ -18,6 +18,11 @@ import {MetricsBrowserProxyImpl} from 'chrome://settings/settings.js'; import {TestMetricsBrowserProxy} from './test_metrics_browser_proxy.js'; + +// </if> +// <if expr="is_win"> +import {loadTimeData} from 'chrome://settings/settings.js'; +import type {SettingsToggleButtonElement} from 'chrome://settings/settings.js'; // </if> // clang-format on @@ -49,6 +54,12 @@ setup(function() { document.body.innerHTML = window.trustedTypes!.emptyHTML; + // <if expr="is_win"> + loadTimeData.overrideValues({ + showProcessIsolationSetting: true, + }); + // </if> + lifetimeBrowserProxy = new TestLifetimeBrowserProxy(); LifetimeBrowserProxyImpl.setInstance(lifetimeBrowserProxy); // <if expr="_google_chrome and is_win"> @@ -74,6 +85,15 @@ value: HARDWARE_ACCELERATION_AT_STARTUP, }, }, + // <if expr="is_win"> + isolation_state: { + enabled: { + key: 'isolation_state.enabled', + type: chrome.settingsPrivate.PrefType.BOOLEAN, + value: false, + }, + }, + // </if> proxy: { key: 'proxy', type: chrome.settingsPrivate.PrefType.DICTIONARY, @@ -123,6 +143,30 @@ return lifetimeBrowserProxy.whenCalled('restart'); }); + // <if expr="is_win"> + test('process isolation restart button', function() { + // Toggle is behind a `dom-if`, so retrieve it via `querySelector`. + const control = + systemPage.shadowRoot!.querySelector<SettingsToggleButtonElement>( + '#isolationState'); + assertTrue(!!control); + assertFalse(control.checked); + + // Restart button should be hidden by default. + assertFalse(!!control.querySelector('cr-button')); + + systemPage.setPrefValue('isolation_state.enabled', true); + flush(); + assertTrue(control.checked); + + const restart = control.querySelector('cr-button'); + assertTrue(!!restart); + + restart.click(); + return lifetimeBrowserProxy.whenCalled('restart'); + }); + // </if> + test('proxy row', function() { systemPage.$.proxy.click(); return systemBrowserProxy.whenCalled('showProxySettings');
diff --git a/chrome/test/data/webui/side_panel/read_anything/app_content_test.ts b/chrome/test/data/webui/side_panel/read_anything/app_content_test.ts index ef6181f..51741ad 100644 --- a/chrome/test/data/webui/side_panel/read_anything/app_content_test.ts +++ b/chrome/test/data/webui/side_panel/read_anything/app_content_test.ts
@@ -543,33 +543,52 @@ suite('on image toggle', () => { const altText = 'No man is worth the aggravation'; + const textNodeContent = 'Some text'; setup(() => { - readingMode.getHtmlTag = () => 'img'; + readingMode.rootId = 1; + readingMode.getHtmlTag = (id) => { + if (id === 1) { + return 'div'; + } + if (id === 2) { + return 'img'; + } + return ''; + }; readingMode.getAltText = () => altText; - readingMode.getChildren = () => []; + readingMode.getChildren = (id) => { + if (id === 1) { + return [2, 3]; + } + return []; + }; + readingMode.getTextContent = (id) => id === 3 ? textNodeContent : ''; }); test('shows images when enabled', async () => { readingMode.imagesFeatureEnabled = true; - const expectedHtml = '<canvas dir="ltr" alt="' + altText + - '" class="downloaded-image" lang="en-us" style=""></canvas>'; app.updateContent(); await microtasksFinished(); assertTrue(contentController.hasContent()); readingMode.imagesEnabled = true; + const expectedHtmlWithImage = + '<div dir="ltr" lang="en-us"><canvas dir="ltr" alt="' + altText + + '" class="downloaded-image" lang="en-us" style=""></canvas>' + + textNodeContent + '</div>'; emitEvent(app, ToolbarEvent.IMAGES); await microtasksFinished(); - assertEquals(expectedHtml, app.$.container.innerHTML); + assertEquals(expectedHtmlWithImage, app.$.container.innerHTML); }); test('hides images when disabled', async () => { readingMode.imagesFeatureEnabled = true; - const expectedHtml = '<canvas dir="ltr" alt="' + altText + - '" class="downloaded-image" lang="en-us" style="display: none;">' + - '</canvas>'; + const expectedHtml = + '<div dir="ltr" lang="en-us"><canvas dir="ltr" alt="' + altText + + '" class="downloaded-image" lang="en-us" style="display: none;"></canvas>' + + textNodeContent + '</div>'; app.updateContent(); await microtasksFinished(); assertTrue(contentController.hasContent()); @@ -583,9 +602,10 @@ test('does not show images when feature flag disabled', async () => { readingMode.imagesFeatureEnabled = false; - const expectedHtml = '<canvas dir="ltr" alt="' + altText + - '" class="downloaded-image" lang="en-us" style="display: none;">' + - '</canvas>'; + const expectedHtml = + '<div dir="ltr" lang="en-us"><canvas dir="ltr" alt="' + altText + + '" class="downloaded-image" lang="en-us" style="display: none;"></canvas>' + + textNodeContent + '</div>'; app.updateContent(); await microtasksFinished();
diff --git a/chrome/test/data/webui/side_panel/read_anything/content_controller_test.ts b/chrome/test/data/webui/side_panel/read_anything/content_controller_test.ts index 025e51ce..58aa1811 100644 --- a/chrome/test/data/webui/side_panel/read_anything/content_controller_test.ts +++ b/chrome/test/data/webui/side_panel/read_anything/content_controller_test.ts
@@ -280,6 +280,7 @@ const rootId = 1; const imgId1 = 89; const imgId2 = 88; + const textId = 90; readingMode.imagesFeatureEnabled = true; chrome.readingMode.rootId = rootId; @@ -293,10 +294,17 @@ return ''; }; + readingMode.getTextContent = (id) => { + if (id === textId) { + return 'I don\'t own a motorbike.'; + } + return ''; + }; + // So that nodeStore.addImageToFetch(imgId1) is called in updateContent readingMode.getChildren = (id) => { if (id === rootId) { - return [imgId1]; + return [imgId1, textId]; } return []; }; @@ -307,7 +315,7 @@ // So that nodeStore.addImageToFetch(imgId2) is called in updateContent readingMode.getChildren = (id) => { if (id === rootId) { - return [imgId2]; + return [imgId2, textId]; } return []; }; @@ -1287,4 +1295,47 @@ assertEquals(4, metrics.getCallCount('recordCount')); }); }); + + suite('hidden images empty state', () => { + setup(() => { + readingMode.imagesFeatureEnabled = true; + readingMode.rootId = 1; + readingMode.getHtmlTag = (id) => id === 1 ? 'img' : ''; + readingMode.getChildren = (id) => id === 1 ? [] : []; + readingMode.getTextContent = () => ''; + readingMode.hasValidSelection = false; + }); + + test('Images enabled, images available, no text -> empty state', () => { + readingMode.imagesEnabled = true; + contentController.updateContent(); + assertTrue(contentController.isEmpty()); + }); + + test('Images disabled with images and no text -> empty state', () => { + readingMode.imagesEnabled = false; + contentController.updateContent(); + assertTrue(contentController.isEmpty()); + }); + + test( + 'Images enabled, with images and no text, with selection -> has content', + () => { + readingMode.imagesEnabled = true; + readingMode.hasValidSelection = true; + const root = contentController.updateContent(); + assertFalse(contentController.isEmpty()); + assertTrue(contentController.hasContent()); + assertTrue(root instanceof HTMLCanvasElement); + }); + + test( + 'Images disabled, with images and no text, with selection -> empty state', + () => { + readingMode.imagesEnabled = false; + readingMode.hasValidSelection = true; + contentController.updateContent(); + assertTrue(contentController.isEmpty()); + }); + }); });
diff --git a/chrome/test/data/webui/side_panel/read_anything/fake_reading_mode.ts b/chrome/test/data/webui/side_panel/read_anything/fake_reading_mode.ts index 2ca946a82..3bef4d3 100644 --- a/chrome/test/data/webui/side_panel/read_anything/fake_reading_mode.ts +++ b/chrome/test/data/webui/side_panel/read_anything/fake_reading_mode.ts
@@ -571,4 +571,8 @@ // Called by the Read Anything app to toggle between Side Panel and Immersive // Mode. togglePresentation() {} + + // There has been a long delay between starting speech and speech + // playing. + onSpeechEngineStalled() {} }
diff --git a/chrome/test/data/webui/side_panel/read_anything/selection_controller_test.ts b/chrome/test/data/webui/side_panel/read_anything/selection_controller_test.ts index 950cab07..dbfabb8 100644 --- a/chrome/test/data/webui/side_panel/read_anything/selection_controller_test.ts +++ b/chrome/test/data/webui/side_panel/read_anything/selection_controller_test.ts
@@ -127,48 +127,16 @@ assertFalse(selectionController.hasSelection()); }); - test('current selection start with only anchor node', () => { - const expectedAnchorOffset = 2; - const expectedFocusOffset = 10; - const node = getNodeAt(1); - chrome.readingMode.startNodeId = node.id; - chrome.readingMode.startOffset = expectedAnchorOffset; - chrome.readingMode.endNodeId = 0; - chrome.readingMode.endOffset = expectedFocusOffset; - nodeStore.setDomNode(node.node, node.id); - - selectNodes(node, expectedAnchorOffset, node, expectedFocusOffset); + test('current selection start with no selection', () => { const selectionStart = selectionController.getCurrentSelectionStart(); - - assertEquals(node.id, selectionStart.nodeId); - assertEquals(expectedAnchorOffset, selectionStart.offset); - }); - - test('current selection start with only focus node', () => { - const expectedAnchorOffset = 2; - const expectedFocusOffset = 10; - const node = getNodeAt(1); - chrome.readingMode.endNodeId = node.id; - chrome.readingMode.endOffset = expectedFocusOffset; - chrome.readingMode.startNodeId = 0; - chrome.readingMode.startOffset = expectedAnchorOffset; - nodeStore.setDomNode(node.node, node.id); - - selectNodes(node, expectedAnchorOffset, node, expectedFocusOffset); - const selectionStart = selectionController.getCurrentSelectionStart(); - - assertEquals(node.id, selectionStart.nodeId); - assertEquals(expectedFocusOffset, selectionStart.offset); + assertEquals(0, selectionStart.nodeId); + assertEquals(-1, selectionStart.offset); }); test('current selection start with forward selection in one node', () => { const expectedAnchorOffset = 2; const expectedFocusOffset = 10; const node = getNodeAt(1); - chrome.readingMode.startNodeId = node.id; - chrome.readingMode.startOffset = expectedAnchorOffset; - chrome.readingMode.endNodeId = node.id; - chrome.readingMode.endOffset = expectedFocusOffset; nodeStore.setDomNode(node.node, node.id); selectNodes(node, expectedAnchorOffset, node, expectedFocusOffset); @@ -182,10 +150,6 @@ const expectedAnchorOffset = 10; const expectedFocusOffset = 2; const node = getNodeAt(1); - chrome.readingMode.startNodeId = node.id; - chrome.readingMode.startOffset = expectedAnchorOffset; - chrome.readingMode.endNodeId = node.id; - chrome.readingMode.endOffset = expectedFocusOffset; nodeStore.setDomNode(node.node, node.id); selectNodes(node, expectedAnchorOffset, node, expectedFocusOffset); @@ -200,10 +164,6 @@ const expectedFocusOffset = 2; const node1 = getNodeAt(0); const node2 = getNodeAt(1); - chrome.readingMode.startNodeId = node1.id; - chrome.readingMode.startOffset = expectedAnchorOffset; - chrome.readingMode.endNodeId = node2.id; - chrome.readingMode.endOffset = expectedFocusOffset; nodeStore.setDomNode(node1.node, node1.id); nodeStore.setDomNode(node2.node, node2.id); @@ -219,10 +179,6 @@ const expectedFocusOffset = 2; const node1 = getNodeAt(0); const node2 = getNodeAt(1); - chrome.readingMode.startNodeId = node2.id; - chrome.readingMode.startOffset = expectedFocusOffset; - chrome.readingMode.endNodeId = node1.id; - chrome.readingMode.endOffset = expectedAnchorOffset; nodeStore.setDomNode(node1.node, node1.id); nodeStore.setDomNode(node2.node, node2.id);
diff --git a/chrome/test/data/webui/side_panel/read_anything/simple_action_menu_test.ts b/chrome/test/data/webui/side_panel/read_anything/simple_action_menu_test.ts index c1776ac..08334b1e 100644 --- a/chrome/test/data/webui/side_panel/read_anything/simple_action_menu_test.ts +++ b/chrome/test/data/webui/side_panel/read_anything/simple_action_menu_test.ts
@@ -4,7 +4,8 @@ import 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js'; -import {type SimpleActionMenuElement, ToolbarEvent} from 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js'; +import {ToolbarEvent} from 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js'; +import type {SimpleActionMenuElement} from 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js'; import {assertEquals, assertFalse, assertTrue} from 'chrome-untrusted://webui-test/chai_assert.js'; import {microtasksFinished} from 'chrome-untrusted://webui-test/test_util.js';
diff --git a/chrome/test/data/webui/side_panel/read_anything/speech_controller_content_test.ts b/chrome/test/data/webui/side_panel/read_anything/speech_controller_content_test.ts index efaf3f17..ca74c4f 100644 --- a/chrome/test/data/webui/side_panel/read_anything/speech_controller_content_test.ts +++ b/chrome/test/data/webui/side_panel/read_anything/speech_controller_content_test.ts
@@ -295,16 +295,12 @@ const textNode = document.createTextNode(text1 + text2 + text3); p.appendChild(textNode); document.body.appendChild(p); - chrome.readingMode.startNodeId = id; - chrome.readingMode.startOffset = text1.length + text2.length + 3; - chrome.readingMode.endNodeId = id; - chrome.readingMode.endOffset = text1.length + text2.length + 8; nodeStore.setDomNode(textNode, id); const selection = document.getSelection(); assertTrue(!!selection); const range = new Range(); - range.setStart(textNode, chrome.readingMode.startOffset); - range.setEnd(textNode, chrome.readingMode.endOffset); + range.setStart(textNode, text1.length + text2.length + 3); + range.setEnd(textNode, text1.length + text2.length + 8); selection.addRange(range); selectionController.onSelectionChange(selection); readAloudModel.setInitialized(true); @@ -353,16 +349,12 @@ speechController.onPlayPauseToggle(p); assertTrue(wordBoundaries.hasBoundaries()); // Now select text and play from there. - chrome.readingMode.startNodeId = id; - chrome.readingMode.startOffset = text1.length + text2.length + 3; - chrome.readingMode.endNodeId = id; - chrome.readingMode.endOffset = text1.length + text2.length + 8; nodeStore.setDomNode(textNode, id); const selection = document.getSelection(); assertTrue(!!selection); const range = new Range(); - range.setStart(textNode, chrome.readingMode.startOffset); - range.setEnd(textNode, chrome.readingMode.endOffset); + range.setStart(textNode, text1.length + text2.length + 3); + range.setEnd(textNode, text1.length + text2.length + 8); selection.addRange(range); selectionController.onSelectionChange(selection); readAloudModel.setInitialized(true);
diff --git a/chrome/test/data/webui/side_panel/read_anything/voice_selection_menu_test.ts b/chrome/test/data/webui/side_panel/read_anything/voice_selection_menu_test.ts index e09f0ab..aefeb28 100644 --- a/chrome/test/data/webui/side_panel/read_anything/voice_selection_menu_test.ts +++ b/chrome/test/data/webui/side_panel/read_anything/voice_selection_menu_test.ts
@@ -5,9 +5,8 @@ import 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js'; import type {CrIconButtonElement} from '//resources/cr_elements/cr_icon_button/cr_icon_button.js'; -import type {LanguageMenuElement} from 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js'; -import {type SettingsOption, spinnerDebounceTimeout, ToolbarEvent, VoiceClientSideStatusCode, VoiceNotificationManager} from 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js'; -import type {VoiceSelectionMenuElement} from 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js'; +import {spinnerDebounceTimeout, ToolbarEvent, VoiceClientSideStatusCode, VoiceNotificationManager} from 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js'; +import type {LanguageMenuElement, SettingsOption, VoiceSelectionMenuElement} from 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js'; import {assertEquals, assertFalse, assertStringContains, assertTrue} from 'chrome-untrusted://webui-test/chai_assert.js'; import {keyDownOn} from 'chrome-untrusted://webui-test/keyboard_mock_interactions.js'; import {MockTimer} from 'chrome-untrusted://webui-test/mock_timer.js';
diff --git a/chrome/test/data/webui/signin/BUILD.gn b/chrome/test/data/webui/signin/BUILD.gn index 189a079..9fb0090 100644 --- a/chrome/test/data/webui/signin/BUILD.gn +++ b/chrome/test/data/webui/signin/BUILD.gn
@@ -18,6 +18,7 @@ "history_sync_optin_app_refresh_test.ts", "history_sync_optin_test.ts", "managed_user_profile_notice_test.ts", + "managed_user_profile_notice_app_refresh_test.ts", "profile_card_menu_test.ts", "profile_customization_test.ts", "profile_picker_app_test.ts",
diff --git a/chrome/test/data/webui/signin/managed_user_profile_notice_app_refresh_test.ts b/chrome/test/data/webui/signin/managed_user_profile_notice_app_refresh_test.ts new file mode 100644 index 0000000..b1d29d3d --- /dev/null +++ b/chrome/test/data/webui/signin/managed_user_profile_notice_app_refresh_test.ts
@@ -0,0 +1,186 @@ +// Copyright 2026 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://managed-user-profile-notice/managed_user_profile_notice_app_refresh.js'; + +import type {ManagedUserProfileNoticeAppRefreshElement} from 'chrome://managed-user-profile-notice/managed_user_profile_notice_app_refresh.js'; +import type {ManagedUserProfileInfo} from 'chrome://managed-user-profile-notice/managed_user_profile_notice_browser_proxy.js'; +import {ManagedUserProfileNoticeBrowserProxyImpl, State} from 'chrome://managed-user-profile-notice/managed_user_profile_notice_browser_proxy.js'; +import type {ManagedUserProfileNoticeDisclosureRefreshElement} from 'chrome://managed-user-profile-notice/managed_user_profile_notice_disclosure_refresh.js'; +import {webUIListenerCallback} from 'chrome://resources/js/cr.js'; +import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; +import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; +import {isChildVisible, isVisible, microtasksFinished} from 'chrome://webui-test/test_util.js'; + +import {TestManagedUserProfileNoticeBrowserProxy} from './test_managed_user_profile_notice_browser_proxy.js'; + +suite('ManagedUserProfileNoticeRefreshTest', function() { + let app: ManagedUserProfileNoticeAppRefreshElement; + let browserProxy: TestManagedUserProfileNoticeBrowserProxy; + + const AVATAR_URL_1: string = 'chrome://theme/IDR_PROFILE_AVATAR_1'; + const AVATAR_URL_2: string = 'chrome://theme/IDR_PROFILE_AVATAR_2'; + + const testManagedUserProfileInfo: ManagedUserProfileInfo = { + pictureUrl: AVATAR_URL_1, + showEnterpriseBadge: false, + title: 'title', + subtitle: 'subtitle', + proceedLabel: 'proceed_label', + accountName: 'account_name', + continueAs: 'continue_as', + email: 'email@email.com', + checkLinkDataCheckboxByDefault: false, + }; + + setup(async function() { + document.body.innerHTML = window.trustedTypes!.emptyHTML; + browserProxy = new TestManagedUserProfileNoticeBrowserProxy( + testManagedUserProfileInfo); + ManagedUserProfileNoticeBrowserProxyImpl.setInstance(browserProxy); + loadTimeData.overrideValues({'showLinkDataCheckbox': false}); + app = document.createElement('managed-user-profile-notice-app-refresh'); + document.body.appendChild(app); + await browserProxy.whenCalled('initialized'); + return microtasksFinished(); + }); + + /** + * Checks that the expected image url is displayed. + */ + function checkImageUrl( + targetElement: ManagedUserProfileNoticeDisclosureRefreshElement, + expectedUrl: string) { + assertTrue(isVisible(targetElement.$.avatar)); + assertEquals(expectedUrl, targetElement.$.avatar.src); + } + + test('proceed', async function() { + assertTrue(isVisible(app.$.proceedButton)); + app.$.proceedButton.click(); + await browserProxy.whenCalled('proceed'); + }); + + test('cancel', async function() { + assertTrue(isVisible(app.$.cancelButton)); + app.$.cancelButton.click(); + await browserProxy.whenCalled('cancel'); + }); + + test('stateChanges', async function() { + async function checkState( + state: State, visibleElements: string[], hiddenElements: string[], + expectedProceedLabel?: string) { + webUIListenerCallback('on-state-changed', state); + await microtasksFinished(); + const stateName = State[state]; + for (const id of visibleElements) { + assertTrue( + isChildVisible(app, id), + `${stateName} State: ${id} should be visible`); + } + for (const id of hiddenElements) { + assertFalse( + isChildVisible(app, id), + `${stateName} State: ${id} should be hidden`); + } + if (expectedProceedLabel) { + assertEquals( + expectedProceedLabel, app.$.proceedButton.textContent.trim(), + `${stateName} State: Proceed label`); + } + } + + const allSections = [ + '#disclosure', + '#processing', + '#error', + '#timeout', + '#success', + ]; + + await checkState( + State.DISCLOSURE, ['#disclosure', '#proceedButton', '#cancelButton'], + allSections.filter(id => id !== '#disclosure'), + testManagedUserProfileInfo.proceedLabel); + + await checkState( + State.PROCESSING, ['#processing', '#cancelButton'], + [...allSections.filter(id => id !== '#processing'), '#proceedButton']); + + await checkState( + State.ERROR, ['#error', '#proceedButton'], + [...allSections.filter(id => id !== '#error'), '#cancelButton'], + app.i18n('closeLabel')); + + await checkState( + State.TIMEOUT, ['#timeout', '#proceedButton', '#cancelButton'], + allSections.filter(id => id !== '#timeout'), app.i18n('retryLabel')); + + await checkState( + State.SUCCESS, ['#success', '#proceedButton'], + [...allSections.filter(id => id !== '#success'), '#cancelButton'], + testManagedUserProfileInfo.proceedLabel); + }); + + test('onProfileInfoChangedDisclosureSection', async function() { + // Navigate to the disclosure section. + webUIListenerCallback('on-state-changed', State.DISCLOSURE); + await microtasksFinished(); + + const targetElement = + app.shadowRoot + .querySelector<ManagedUserProfileNoticeDisclosureRefreshElement>( + '#disclosure'); + assertTrue(!!targetElement); + + // Initial values. + assertTrue(isVisible(targetElement.$.title)); + assertEquals( + app.i18n('profileDisclosureTitle'), + targetElement.$.title.textContent.trim()); + assertTrue(isVisible(targetElement.$.subtitle)); + assertEquals( + app.i18n('profileDisclosureSubtitle'), + targetElement.$.subtitle.textContent.trim()); + assertTrue(isVisible(app.$.proceedButton)); + assertEquals( + testManagedUserProfileInfo.proceedLabel, + app.$.proceedButton.textContent.trim()); + + checkImageUrl(targetElement, AVATAR_URL_1); + assertFalse(isChildVisible(targetElement, '.work-badge')); + + // Update the values. + const newProfileInfo: ManagedUserProfileInfo = { + pictureUrl: AVATAR_URL_2, + showEnterpriseBadge: true, + title: 'new_title', + subtitle: 'new_subtitle', + proceedLabel: 'new_proceed_label', + accountName: 'new_account_name', + continueAs: 'new_continue_as', + email: 'new_email@email.com', + checkLinkDataCheckboxByDefault: false, + }; + webUIListenerCallback('on-profile-info-changed', newProfileInfo); + await microtasksFinished(); + + assertTrue(isVisible(targetElement.$.title)); + assertEquals( + app.i18n('profileDisclosureTitle'), + targetElement.$.title.textContent.trim()); + assertTrue(isVisible(targetElement.$.subtitle)); + assertEquals( + app.i18n('profileDisclosureSubtitle'), + targetElement.$.subtitle.textContent.trim()); + assertTrue(isVisible(app.$.proceedButton)); + assertEquals( + newProfileInfo.proceedLabel, app.$.proceedButton.textContent.trim()); + + checkImageUrl(targetElement, AVATAR_URL_2); + assertTrue(isChildVisible(targetElement, '.work-badge')); + assertTrue(isVisible(app.$.cancelButton)); + }); +});
diff --git a/chrome/test/data/webui/signin/signin_browsertest.cc b/chrome/test/data/webui/signin/signin_browsertest.cc index c9dd9798..868cf8a 100644 --- a/chrome/test/data/webui/signin/signin_browsertest.cc +++ b/chrome/test/data/webui/signin/signin_browsertest.cc
@@ -4,11 +4,12 @@ #include "base/strings/stringprintf.h" #include "base/test/scoped_feature_list.h" +#include "chrome/browser/first_run/first_run_features.h" #include "chrome/browser/ui/webui/signin/signin_url_utils.h" #include "chrome/common/webui_url_constants.h" #include "chrome/test/base/web_ui_mocha_browser_test.h" -#include "components/signin/public/base/signin_switches.h" #include "components/signin/public/base/signin_metrics.h" +#include "components/signin/public/base/signin_switches.h" #include "components/sync/base/features.h" #include "content/public/test/browser_test.h" @@ -58,6 +59,26 @@ RunTest("signin/managed_user_profile_notice_test.js", "mocha.run()"); } +class SigninManagedUserProfileNoticeRefreshTest : public SigninTest { + protected: + SigninManagedUserProfileNoticeRefreshTest() { + feature_list_.InitWithFeatures( + {switches::kFirstRunDesktopRefresh, + switches::kFirstRunDesktopChoiceScreenRefresh}, + {}); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +IN_PROC_BROWSER_TEST_F(SigninManagedUserProfileNoticeRefreshTest, + SigninManagedUserProfileNoticeRefresh) { + set_test_loader_host(chrome::kChromeUIManagedUserProfileNoticeHost); + RunTest("signin/managed_user_profile_notice_app_refresh_test.js", + "mocha.run()"); +} + class SigninTestWithHistorySync : public SigninTest { protected: SigninTestWithHistorySync() { @@ -77,7 +98,10 @@ class SigninTestWithHistorySyncRefresh : public SigninTestWithHistorySync { protected: SigninTestWithHistorySyncRefresh() { - feature_list_.InitAndEnableFeature(switches::kFirstRunDesktopRefresh); + feature_list_.InitWithFeatures( + {switches::kFirstRunDesktopRefresh, + switches::kFirstRunDesktopChoiceScreenRefresh}, + {}); } private:
diff --git a/chrome/test/data/webui/signin/test_history_sync_optin_browser_proxy.ts b/chrome/test/data/webui/signin/test_history_sync_optin_browser_proxy.ts index 5faf62a..f7c4851b 100644 --- a/chrome/test/data/webui/signin/test_history_sync_optin_browser_proxy.ts +++ b/chrome/test/data/webui/signin/test_history_sync_optin_browser_proxy.ts
@@ -3,8 +3,8 @@ // found in the LICENSE file. import type {HistorySyncOptInBrowserProxy} from 'chrome://history-sync-optin/browser_proxy.js'; -import type {PageRemote} from 'chrome://history-sync-optin/history_sync_optin.mojom-webui.js'; -import {PageCallbackRouter, type PageHandlerInterface} from 'chrome://history-sync-optin/history_sync_optin.mojom-webui.js'; +import {PageCallbackRouter} from 'chrome://history-sync-optin/history_sync_optin.mojom-webui.js'; +import type {PageHandlerInterface, PageRemote} from 'chrome://history-sync-optin/history_sync_optin.mojom-webui.js'; import {TestBrowserProxy} from 'chrome://webui-test/test_browser_proxy.js'; export class TestHistorySyncOptInHandler extends TestBrowserProxy implements
diff --git a/chrome/test/data/webui/signin/test_managed_user_profile_notice_browser_proxy.ts b/chrome/test/data/webui/signin/test_managed_user_profile_notice_browser_proxy.ts index c60c56d..0681477 100644 --- a/chrome/test/data/webui/signin/test_managed_user_profile_notice_browser_proxy.ts +++ b/chrome/test/data/webui/signin/test_managed_user_profile_notice_browser_proxy.ts
@@ -12,6 +12,7 @@ constructor(info: ManagedUserProfileInfo) { super([ 'initialized', + 'initializedWithSize', 'proceed', 'cancel', ]);
diff --git a/chrome/test/user_education/mock_browser_user_education_interface.h b/chrome/test/user_education/mock_browser_user_education_interface.h index 7a13cf6..967c07b 100644 --- a/chrome/test/user_education/mock_browser_user_education_interface.h +++ b/chrome/test/user_education/mock_browser_user_education_interface.h
@@ -30,11 +30,11 @@ HasFeaturePromoBeenDismissed, (const base::Feature&), (const override)); - MOCK_METHOD(void, + MOCK_METHOD(bool, MaybeShowFeaturePromo, (user_education::FeaturePromoParams), (override)); - MOCK_METHOD(void, + MOCK_METHOD(bool, MaybeShowStartupFeaturePromo, (user_education::FeaturePromoParams), (override));
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM index f7c86a8..43af9bc3 100644 --- a/chromeos/CHROMEOS_LKGM +++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@ -16619.0.0-1076028 \ No newline at end of file +16619.0.0-1076034 \ No newline at end of file
diff --git a/chromeos/ash/components/audio/cras_audio_handler_unittest.cc b/chromeos/ash/components/audio/cras_audio_handler_unittest.cc index e6a88d0..7ea8961 100644 --- a/chromeos/ash/components/audio/cras_audio_handler_unittest.cc +++ b/chromeos/ash/components/audio/cras_audio_handler_unittest.cc
@@ -436,7 +436,7 @@ } private: - base::ObserverList<media::VideoCaptureObserver> observers_; + base::ObserverList<media::VideoCaptureObserver>::Unchecked observers_; }; } // namespace
diff --git a/chromeos/ash/components/login/auth/public/key.cc b/chromeos/ash/components/login/auth/public/key.cc index 14708c1..b3ceb0e 100644 --- a/chromeos/ash/components/login/auth/public/key.cc +++ b/chromeos/ash/components/login/auth/public/key.cc
@@ -80,7 +80,7 @@ } case KEY_TYPE_SALTED_PBKDF2_AES256_1234: { std::array<uint8_t, 32> derived; - crypto::kdf::DeriveKeyPbkdf2HmacSha1( + crypto::kdf::Pbkdf2HmacSha1( {.iterations = 1234}, base::as_byte_span(secret_), base::as_byte_span(salt), derived, crypto::SubtlePassKey{}); secret_ = base::Base64Encode(derived);
diff --git a/chromeos/chromeos_strings.grd b/chromeos/chromeos_strings.grd index 86308b5..f6ee1ee5 100644 --- a/chromeos/chromeos_strings.grd +++ b/chromeos/chromeos_strings.grd
@@ -600,13 +600,6 @@ <message name="IDS_TABLET_MULTITASK_MENU_NUDGE_TEXT" desc="Text that is shown when the tablet multitask menu nudge is displayed."> Swipe down for more layout options </message> - <!-- ARC SDK Version Labels--> - <message name="IDS_ARC_SDK_VERSION_LABEL" desc="Label for Android SDK Version bundled with ARC"> - SDK Version: - </message> - <message name="IDS_ARC_SDK_VERSION_UNKNOWN" desc="Message displayed when the Android SDK Version can not be found"> - Unknown - </message> <if expr="is_chromeos"> <part file="recorder_strings.grdp" /> @@ -3508,21 +3501,6 @@ <message name="IDS_SEA_PEN_FEEDBACK_PLACEHOLDER" desc="Placeholder text displayed in the feedback text box"> Feedback for wallpaper powered by Google AI </message> - <message name="IDS_SEA_PEN_WALLPAPER_TERMS_DIALOG_TITLE" desc="Title for the wallpaper terms of service dialog."> - Terms of service - </message> - <message name="IDS_SEA_PEN_WALLPAPER_TERMS_ACCEPT_BUTTON" desc="The button which accepts and agrees to the terms for wallpaper service."> - I agree - </message> - <message name="IDS_SEA_PEN_WALLPAPER_TERMS_REFUSE_BUTTON" desc="The button which refuses the terms for wallpaper service."> - No thanks - </message> - <message name="IDS_SEA_PEN_WALLPAPER_TERMS_OF_SERVICE_DESC" desc="Title for the wallpaper terms of service dialog."> - You must be at least 18 years old and agree your use of AI wallpapers is subject to <ph name="GOOGLE_TERMS_OF_SERVICE_LINK"><a target="_blank" href="https://policies.google.com/terms"></ph>Google Terms of Service<ph name="END_LINK_GOOGLE_TERMS_OF_SERVICE"></a></ph> and <ph name="BEGIN_LINK_GEN_AI_TERMS_OF_SERVICE"><a target="_blank" href="https://policies.google.com/terms/generative-ai"></ph>Generative AI Additional Terms of Service<ph name="END_LINK_GEN_AI_TERMS_OF_SERVICE"></a></ph>. - <ph name="LINE_BREAK"><br></ph> - <ph name="LINE_BREAK"><br></ph> - You can only create wallpapers with AI for personal and non-commercial use. When you get wallpaper help, text is sent to Google AI servers to generate wallpaper suggestions, subject to <ph name="BEGIN_LINK_GOOGLE_PRIVACY_POLICY"><a target="_blank" href="https://policies.google.com/privacy"></ph>Google's Privacy Policy<ph name="END_LINK_GOOGLE_PRIVACY_POLICY"></a></ph>. <ph name="BEGIN_LINK_LEARN_MORE"><a target="_blank" href="https://support.google.com/chromebook?p=copyeditor"></ph>Learn more<ph name="END_LINK_LEARN_MORE"></a></ph> - </message> <message name="IDS_SEA_PEN_CREATING_HIGH_RES_IMAGE" desc="The message displayed when the high resolution image is being created."> Creating hi-res image… </message>
diff --git a/chromeos/chromeos_strings_grd/IDS_SEA_PEN_WALLPAPER_TERMS_ACCEPT_BUTTON.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SEA_PEN_WALLPAPER_TERMS_ACCEPT_BUTTON.png.sha1 deleted file mode 100644 index f7cc1376..0000000 --- a/chromeos/chromeos_strings_grd/IDS_SEA_PEN_WALLPAPER_TERMS_ACCEPT_BUTTON.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -e2db48c2b7cd0a55768c648b68468e2ff998b71a \ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_SEA_PEN_WALLPAPER_TERMS_DIALOG_TITLE.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SEA_PEN_WALLPAPER_TERMS_DIALOG_TITLE.png.sha1 deleted file mode 100644 index d1e61db..0000000 --- a/chromeos/chromeos_strings_grd/IDS_SEA_PEN_WALLPAPER_TERMS_DIALOG_TITLE.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -ea47502dd6d8c4a46cc98f476fba3f1a1e636800 \ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_SEA_PEN_WALLPAPER_TERMS_OF_SERVICE_DESC.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SEA_PEN_WALLPAPER_TERMS_OF_SERVICE_DESC.png.sha1 deleted file mode 100644 index 084d626..0000000 --- a/chromeos/chromeos_strings_grd/IDS_SEA_PEN_WALLPAPER_TERMS_OF_SERVICE_DESC.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -564ac26ebe6c9ded301415f4c8e976c8378f552c \ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_SEA_PEN_WALLPAPER_TERMS_REFUSE_BUTTON.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SEA_PEN_WALLPAPER_TERMS_REFUSE_BUTTON.png.sha1 deleted file mode 100644 index f2feff2..0000000 --- a/chromeos/chromeos_strings_grd/IDS_SEA_PEN_WALLPAPER_TERMS_REFUSE_BUTTON.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -ef7d7bc124d54bc93c7e87988497ef0882c8964a \ No newline at end of file
diff --git a/chromeos/components/onc/onc_utils.cc b/chromeos/components/onc/onc_utils.cc index 1dba561..c6096d74 100644 --- a/chromeos/components/onc/onc_utils.cc +++ b/chromeos/components/onc/onc_utils.cc
@@ -724,9 +724,8 @@ } std::array<uint8_t, kKeyBytes> key; - crypto::kdf::DeriveKeyPbkdf2HmacSha1(m->kdf_params, - base::span<const uint8_t>(), m->salt, - key, MakeCryptoPassKey()); + crypto::kdf::Pbkdf2HmacSha1(m->kdf_params, base::span<const uint8_t>(), + m->salt, key, MakeCryptoPassKey()); if (!crypto::hmac::VerifySha1(key, m->ciphertext, m->hmac)) { NET_LOG(ERROR) << kUnableToDecrypt;
diff --git a/chromeos/crosapi/mojom/cros_display_config.mojom b/chromeos/crosapi/mojom/cros_display_config.mojom index c341dd8c..7200c75a 100644 --- a/chromeos/crosapi/mojom/cros_display_config.mojom +++ b/chromeos/crosapi/mojom/cros_display_config.mojom
@@ -13,71 +13,6 @@ // All points, bounds, and insets are in display pixels unless otherwise // sepcified. -// SetDisplayLayoutInfo or SetDisplayProperties result. -[Extensible] -enum DisplayConfigResult { - // CrosDisplayConfigController method call was successful. - [Default] kSuccess = 0, - // Operation is not supported. - kInvalidOperationError, - // Input display ID represents an invalid display. - kInvalidDisplayIdError, - // Unified desktop mode is disabled. - kUnifiedNotEnabledError, - // Input property for operation is out of range. E.g. display zoom factor, - // bounds origin or overscan. - kPropertyValueOutOfRangeError, - // Operation is not supported for internal displays. - kNotSupportedOnInternalDisplayError, - // Negative values are not supportet for the operation. - kNegativeValueError, - // Setting the display mode failed. - kSetDisplayModeError, - // Invalid display layout error. - kInvalidDisplayLayoutError, - // Mode requires multiple displays. - kSingleDisplayError, - // Mirror mode source ID is invalid. - kMirrorModeSourceIdError, - // Mirror mode destination ID is invalid. - kMirrorModeDestIdError, - // Calibration is not available (e.g. no external touch screen device). - kCalibrationNotAvailableError, - // Calibration was not started. - kCalibrationNotStartedError, - // Touch calibration is already active. - kCalibrationInProgressError, - // Invalid input data for calibration. - kCalibrationInvalidDataError, - // Calibration procedure failed. - kCalibrationFailedError, -}; - -// Describes how the displays are laid out. -[Extensible] -enum DisplayLayoutMode { - // In normal mode displays are laid out as described by - // DisplayLayoutInfo.layouts. - [Default] kNormal = 0, - // In unified desktop mode, a single desktop will be stretched across all - // available displays. - kUnified, - // In mirrored mode, the display defined by DisplayLayoutInfo.mirrorSourceId - // will be mirrored in the displays defined by - // DisplayLayoutInfo.mirrorDestinationIds, or in all other displays if - // mirrorDestinationIds is empty. - kMirrored -}; - -// Describes a display edge. -[Extensible] -enum DisplayLayoutPosition { - [Default] kTop = 0, - kRight, - kBottom, - kLeft -}; - // Describes an overscan or touch calibration operation. [Extensible] enum DisplayConfigOperation { @@ -128,56 +63,6 @@ k270Degrees, }; -// Defines a pair of display + touch points used for touch calibration. -struct TouchCalibrationPair { - // The coordinates of the display point. - gfx.mojom.Point display_point@0; - // The coordinates of the touch point corresponding to the display point. - gfx.mojom.Point touch_point@1; -}; - -// Defines the data required for touch calibration. -struct TouchCalibration { - // Must contain exactly four pairs of touch calibration points. - array<TouchCalibrationPair> pairs@0; - // Width and height of the display area when the touch calibration was - // performed. - gfx.mojom.Size bounds@1; -}; - -// Defines the layout of a single display. -struct DisplayLayout { - // The unique identifier of the display. - string id@0; - // The unique identifier of the parent display. Empty for the root display. - string parent_id@1; - // The edge of the display that is shared with the parent display. Ignored for - // the root display. - DisplayLayoutPosition position@2; - // The offset of the display along the connected edge. 0 indicates that - // the topmost or leftmost corner is aligned. - int32 offset@3; -}; - -// Defines the layout mode and details. -struct DisplayLayoutInfo { - // The layout mode to use, see DisplayLayoutMode for details. - DisplayLayoutMode layout_mode@0; - // Ignored if If layout_mode is not kMirrored. Otherwise, if provided, - // specifies the unique identifier of the source display for mirroring. If - // not provided, mirror_destination_ids will be ignored and default ('normal') - // mirrored mode will be enabled. - string? mirror_source_id@1; - // Ignored if layout_mode is not kMirrored. Otherwise, if provided, specifies - // the unique identifiers of the displays to mirror the source display. If not - // provided or empty, all displays will mirror the source display. - array<string>? mirror_destination_ids@2; - // An array of layouts describing a directed graph of displays. Required if - // layout_mode is kNormal or kMirrored and not all displays are mirrored - // ('mixed' mode). Ignored if layout_mode is kUnified. - array<DisplayLayout>? layouts@3; -}; - // EDID extracted parameters. Field description refers to "VESA ENHANCED // EXTENDED DISPLAY IDENTIFICATION DATA STANDARD (Defines EDID Structure // Version 1, Revision 4)" Release A, Revision 2 September 25, 2006. @@ -191,11 +76,6 @@ int32 year_of_manufacture@2; }; -// Struct wrapper so that the property can be optional. -struct DisplayRotation { - DisplayRotationOptions rotation@0; -}; - // Defines the properties for a display mode, i.e. a valid size and scale. struct DisplayMode { // The display mode size in device independent (user visible) pixels. @@ -260,31 +140,3 @@ [MinVersion=1] bool is_detected@19; }; -// Properties for configuring an individual display, used in -// SetDisplayProperties. -struct DisplayConfigProperties { - // If true, makes the display primary. No-op if set to false. - bool set_primary@0; - // If provided, sets the display's overscan insets to the provided value. - // Note: overscan values may not be negative or larger than a half of the - // screen's size. Overscan cannot be changed on the internal monitor. - gfx.mojom.Insets? overscan@1; - // If provided updates the display's rotation, or if the auto-rotation is - // allowed in the device, it can be used to set or clear the user rotation - // lock, enabling or disabling auto-rotation. - DisplayRotation? rotation@2; - // If provided, updates the display's logical bounds origin. Note: when - // updating the display origin, some constraints will be applied. so the final - // bounds origin may be different than the one set. The actual bounds will be - // reflected in DisplayUnitInfo. Cannot be changed on the primary display (or - // if set_primary is true). - gfx.mojom.Point? bounds_origin@3; - // If non zero, updates the zoom associated with the display. This zoom - // performs relayout and repaint thus resulting in a better quality zoom than - // just performing a pixel by pixel stretch enlargement. - double display_zoom_factor@4; - // Optional DisplayMode properties to set. This should match one of the - // modes listed in DisplayUnitInfo.available_display_modes. Other custom - // modes may or may not be valid. - DisplayMode? display_mode@5; -};
diff --git a/chromeos/tast_control_disabled_tests.txt b/chromeos/tast_control_disabled_tests.txt index 0e59f061..04d9b32b 100644 --- a/chromeos/tast_control_disabled_tests.txt +++ b/chromeos/tast_control_disabled_tests.txt
@@ -138,4 +138,7 @@ # b/488388275 tast.health.RunCameraFrameAnalysisRoutine +# b/493342485 +tast.peripherals.LaunchAppFromLauncher.feedback@amd64-generic-vm + # READ COMMENT AT TOP BEFORE ADDING NEW TESTS HERE.
diff --git a/clank b/clank index ae77a65..726cd20 160000 --- a/clank +++ b/clank
@@ -1 +1 @@ -Subproject commit ae77a657d2f3c9282aa750ef27dc7d97225871bc +Subproject commit 726cd20140f7147db6e09fd3e78291b77efd64c3
diff --git a/components/BUILD.gn b/components/BUILD.gn index 7d518a79..2963e41f 100644 --- a/components/BUILD.gn +++ b/components/BUILD.gn
@@ -559,6 +559,7 @@ "//components/url_rewrite:unit_tests", "//components/user_education/common:unit_tests", "//components/value_store:unit_tests", + "//components/visibility_timer:unit_tests", "//components/visited_url_ranking/public:unit_tests", "//components/visitedlink/test:unit_tests", "//components/wallet/content/browser:unit_tests", @@ -850,6 +851,7 @@ "//components/services/print_compositor:unit_tests", ] } + if (enable_print_preview) { deps += [ "//components/pwg_encoder:unit_tests" ] }
diff --git a/components/accessibility_annotator/core/logging/BUILD.gn b/components/accessibility_annotator/core/logging/BUILD.gn new file mode 100644 index 0000000..9749141 --- /dev/null +++ b/components/accessibility_annotator/core/logging/BUILD.gn
@@ -0,0 +1,12 @@ +# Copyright 2026 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//mojo/public/tools/bindings/mojom.gni") + +assert(!is_android) + +mojom("mojo_bindings") { + sources = [ "accessibility_annotator_internals.mojom" ] + webui_module_path = "/" +}
diff --git a/components/accessibility_annotator/core/logging/OWNERS b/components/accessibility_annotator/core/logging/OWNERS new file mode 100644 index 0000000..4d386576 --- /dev/null +++ b/components/accessibility_annotator/core/logging/OWNERS
@@ -0,0 +1,3 @@ +file://components/accessibility_annotator/OWNERS +per-file *.mojom=set noparent +per-file *.mojom=file://ipc/SECURITY_OWNERS \ No newline at end of file
diff --git a/components/accessibility_annotator/core/logging/accessibility_annotator_internals.mojom b/components/accessibility_annotator/core/logging/accessibility_annotator_internals.mojom new file mode 100644 index 0000000..d698a8b --- /dev/null +++ b/components/accessibility_annotator/core/logging/accessibility_annotator_internals.mojom
@@ -0,0 +1,24 @@ +// Copyright 2026 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +module accessibility_annotator_internals.mojom; + +// TODO(crbug.com/488355081): Maybe add a stream here to get updates +// directly from the service. +// For now, get the annotations once when the page is loaded. +interface PageHandlerFactory { + // Create a page handler and link it to the UI. + CreatePageHandler( + pending_remote<Page> page, pending_receiver<PageHandler> handler); +}; + +// Called from TS side of chrome://content-annotator-internals +interface PageHandler { + // Requests annotations and returns the annotated content as a string, if + // available. + GetAnnotatedContent() => (string? content); +}; + +// Called from C++ side of chrome://content-annotator-internals +interface Page {}; \ No newline at end of file
diff --git a/components/autofill/core/browser/foundations/browser_autofill_manager.cc b/components/autofill/core/browser/foundations/browser_autofill_manager.cc index 4b22094..dea33b6 100644 --- a/components/autofill/core/browser/foundations/browser_autofill_manager.cc +++ b/components/autofill/core/browser/foundations/browser_autofill_manager.cc
@@ -1961,10 +1961,30 @@ eligible_features) { switch (eligible_feature) { case AmountExtractionManager::EligibleFeature::kBnpl: - if (!base::FeatureList::IsEnabled( - features::kAutofillEnableAiBasedAmountExtraction)) { + const bool ai_amount_extraction_disabled = + !base::FeatureList::IsEnabled( + features::kAutofillEnableAiBasedAmountExtraction); + const bool pay_later_tabs_enabled = base::FeatureList::IsEnabled( + features::kAutofillEnablePayNowPayLaterTabs); + + // Notifying BNPL manager of suggestion generation is only necessary + // for flows that do an update of the suggestions dropdown. In the + // regex-based amount extraction approach, the dropdown is updated to + // add the BNPL chip so suggestion generation notification is + // necessary. In the AI-based amount extraction case, no suggestion + // dropdown updates happen so it's not necessary. For pay later tabs, + // once again suggestions are updated (switching out progress + // suggestion with regular BNPL suggestions), so suggestion generation + // notification is necessary again. + if (ai_amount_extraction_disabled || pay_later_tabs_enabled) { GetPaymentsBnplManager()->NotifyOfSuggestionGeneration( trigger_source); + } + + // This is the entry point for regex-based amount extraction. If + // AI-based amount extraction is enabled, this should not be + // triggered. + if (ai_amount_extraction_disabled) { GetAmountExtractionManager().TriggerCheckoutAmountExtraction(); } }
diff --git a/components/autofill/core/browser/foundations/browser_autofill_manager_unittest.cc b/components/autofill/core/browser/foundations/browser_autofill_manager_unittest.cc index 654181f..4fab1fe 100644 --- a/components/autofill/core/browser/foundations/browser_autofill_manager_unittest.cc +++ b/components/autofill/core/browser/foundations/browser_autofill_manager_unittest.cc
@@ -3588,6 +3588,48 @@ EXPECT_FALSE(external_delegate()->on_suggestions_returned_seen()); } +// Tests that `AmountExtractionManager` should notify the BNPL manager of +// suggestion generation for pay later tabs, but should not trigger amount +// extraction, when suggestions are generated. +TEST_F(BrowserAutofillManagerTest, NotifyOfSuggestionGeneration_PayLaterTabs) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitWithFeatures( + /*enabled_features=*/{features::kAutofillEnableAmountExtraction, + features::kAutofillEnableBuyNowPayLaterSyncing, + features::kAutofillEnableBuyNowPayLater, + features::kAutofillEnableAiBasedAmountExtraction, + features::kAutofillEnablePayNowPayLaterTabs}, + /*disabled_features=*/{}); + + personal_data().test_payments_data_manager().AddBnplIssuer( + test::GetTestUnlinkedBnplIssuer()); + // Set up our form data. + FormData form = + CreateTestCreditCardFormData(/*is_https=*/true, /*use_month_type=*/false); + FormsSeen({form}); + + // Test case for credit-card-number field. + const FormFieldData& card_number_field = form.fields()[1]; + ASSERT_EQ(card_number_field.name(), u"cardnumber"); + + DenseSet<MockAmountExtractionManager::EligibleFeature> features = { + MockAmountExtractionManager::EligibleFeature::kBnpl}; + ON_CALL(amount_extraction_manager(), GetEligibleFeatures) + .WillByDefault(Return(features)); + + // Verify that BNPL manager is notified of suggestion generation, but amount + // extraction is not triggered. + EXPECT_CALL(amount_extraction_manager(), TriggerCheckoutAmountExtraction) + .Times(0); + EXPECT_CALL(*autofill_manager().GetPaymentsBnplManager(), + NotifyOfSuggestionGeneration); + + OnAskForValuesToFill(form, card_number_field); + + // Verify that suggestions are returned as normal. + EXPECT_TRUE(external_delegate()->on_suggestions_returned_seen()); +} + struct LogAblationTestParams { const char* description; // Whether any autofillable data is stored.
diff --git a/components/autofill/core/browser/payments/android_bnpl_strategy.cc b/components/autofill/core/browser/payments/android_bnpl_strategy.cc index fa41623f..0f553540 100644 --- a/components/autofill/core/browser/payments/android_bnpl_strategy.cc +++ b/components/autofill/core/browser/payments/android_bnpl_strategy.cc
@@ -16,9 +16,9 @@ kSkipNotifyingUpdateCallbackOfSuggestionsShownResponse; } -BnplStrategy::BnplSuggestionAcceptedNextAction -AndroidBnplStrategy::GetNextActionOnBnplSuggestionAcceptance() { - return BnplSuggestionAcceptedNextAction:: +BnplStrategy::UserDecisionToUseBnplNextAction +AndroidBnplStrategy::GetNextActionOnUserDecisionToUseBnpl() { + return UserDecisionToUseBnplNextAction:: kCheckAmountExtractionBeforeContinuingFlowForAndroid; }
diff --git a/components/autofill/core/browser/payments/android_bnpl_strategy.h b/components/autofill/core/browser/payments/android_bnpl_strategy.h index 740c219..847ef12 100644 --- a/components/autofill/core/browser/payments/android_bnpl_strategy.h +++ b/components/autofill/core/browser/payments/android_bnpl_strategy.h
@@ -20,7 +20,7 @@ // BnplStrategy: SuggestionShownNextAction GetNextActionOnSuggestionShown() override; - BnplSuggestionAcceptedNextAction GetNextActionOnBnplSuggestionAcceptance() + UserDecisionToUseBnplNextAction GetNextActionOnUserDecisionToUseBnpl() override; BnplAmountExtractionReturnedNextAction GetNextActionOnAmountExtractionReturned() override;
diff --git a/components/autofill/core/browser/payments/android_bnpl_strategy_unittest.cc b/components/autofill/core/browser/payments/android_bnpl_strategy_unittest.cc index 2f639ff..4853749 100644 --- a/components/autofill/core/browser/payments/android_bnpl_strategy_unittest.cc +++ b/components/autofill/core/browser/payments/android_bnpl_strategy_unittest.cc
@@ -25,11 +25,11 @@ kSkipNotifyingUpdateCallbackOfSuggestionsShownResponse); } -// Verify that GetNextActionOnBnplSuggestionAcceptance() returns the correct +// Verify that GetNextActionOnUserDecisionToUseBnpl() returns the correct // action for the Android platform. -TEST_F(AndroidBnplStrategyTest, GetNextActionOnBnplSuggestionAcceptance) { - EXPECT_EQ(android_bnpl_strategy_.GetNextActionOnBnplSuggestionAcceptance(), - BnplStrategy::BnplSuggestionAcceptedNextAction:: +TEST_F(AndroidBnplStrategyTest, GetNextActionOnUserDecisionToUseBnpl) { + EXPECT_EQ(android_bnpl_strategy_.GetNextActionOnUserDecisionToUseBnpl(), + BnplStrategy::UserDecisionToUseBnplNextAction:: kCheckAmountExtractionBeforeContinuingFlowForAndroid); }
diff --git a/components/autofill/core/browser/payments/bnpl_manager.cc b/components/autofill/core/browser/payments/bnpl_manager.cc index f236cf8..5fd37b0 100644 --- a/components/autofill/core/browser/payments/bnpl_manager.cc +++ b/components/autofill/core/browser/payments/bnpl_manager.cc
@@ -22,6 +22,7 @@ #include "base/rand_util.h" #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" +#include "components/autofill/core/browser/data_model/payments/bnpl_issuer.h" #include "components/autofill/core/browser/data_model/payments/credit_card.h" #include "components/autofill/core/browser/foundations/autofill_manager.h" #include "components/autofill/core/browser/integrators/optimization_guide/autofill_optimization_guide_decider.h" @@ -36,7 +37,9 @@ #include "components/autofill/core/browser/payments/payments_network_interface.h" #include "components/autofill/core/browser/payments/payments_request_details.h" #include "components/autofill/core/browser/payments/payments_util.h" +#include "components/autofill/core/browser/suggestions/payments/credit_card_suggestion_generator.h" #include "components/autofill/core/browser/suggestions/payments/payments_suggestion_generator_util.h" +#include "components/autofill/core/browser/suggestions/suggestion_hiding_reason.h" #include "components/autofill/core/browser/ui/payments/autofill_progress_ui_type.h" #include "components/autofill/core/browser/ui/payments/bnpl_tos_controller.h" #include "components/autofill/core/browser/ui/payments/bnpl_ui_delegate.h" @@ -121,10 +124,10 @@ &BnplManager::OnPrefetchedRiskDataLoaded, weak_factory_.GetWeakPtr())); CHECK(payments_autofill_client().GetBnplStrategy()); - using enum BnplStrategy::BnplSuggestionAcceptedNextAction; + using enum BnplStrategy::UserDecisionToUseBnplNextAction; switch (payments_autofill_client() .GetBnplStrategy() - ->GetNextActionOnBnplSuggestionAcceptance()) { + ->GetNextActionOnUserDecisionToUseBnpl()) { case kShowSelectBnplIssuerUiForDesktop: { CHECK_DEREF(payments_autofill_client().GetBnplUiDelegate()) .ShowSelectBnplIssuerUi( @@ -132,7 +135,7 @@ browser_autofill_manager_->client(), ongoing_flow_state_->final_checkout_amount), ongoing_flow_state_->app_locale, - base::BindRepeating(&BnplManager::OnIssuerSelected, + base::BindRepeating(&BnplManager::OnIssuerAccepted, weak_factory_.GetWeakPtr()), base::BindOnce(&BnplManager::Reset, weak_factory_.GetWeakPtr()), HasSeenAmountExtractionAiTerms()); @@ -153,7 +156,7 @@ browser_autofill_manager_->client(), ongoing_flow_state_->final_checkout_amount), ongoing_flow_state_->app_locale, - base::BindRepeating(&BnplManager::OnIssuerSelected, + base::BindRepeating(&BnplManager::OnIssuerAccepted, weak_factory_.GetWeakPtr()), base::BindOnce(&BnplManager::Reset, weak_factory_.GetWeakPtr()), HasSeenAmountExtractionAiTerms()); @@ -170,7 +173,10 @@ } break; } + case kDoNothing: + break; } + if (base::FeatureList::IsEnabled( features::kAutofillEnableAiBasedAmountExtraction)) { if (HasSeenAmountExtractionAiTerms()) { @@ -192,6 +198,24 @@ .OnUserDecisionToUseBnpl(); } +void BnplManager::OnIssuerAccepted(BnplIssuer issuer) { + ongoing_flow_state_->issuer = std::move(issuer); + + // When an issuer is accepted but no checkout amount is present, call + // server-side AI to extract the amount. + if (base::FeatureList::IsEnabled( + features::kAutofillEnableAiBasedAmountExtraction) && + !ongoing_flow_state_->final_checkout_amount) { + browser_autofill_manager_->GetAmountExtractionManager() + .TriggerCheckoutAmountExtractionWithAi(); + // TODO(crbug.com/477689220): If Pay Now Pay Later tabs UI is enabled, show + // autofill popup progress screen. + return; + } + + OnIssuerAcceptedAndCheckoutAmountAvailable(); +} + void BnplManager::NotifyOfSuggestionGeneration( const AutofillSuggestionTriggerSource trigger_source) { if (!base::FeatureList::IsEnabled(features::kAutofillEnableBuyNowPayLater)) { @@ -202,6 +226,7 @@ std::variant<SuggestionsShownResponse, std::optional<int64_t>>>( 2U, base::BindOnce(&BnplManager::MaybeUpdateDesktopSuggestionsWithBnpl, weak_factory_.GetWeakPtr(), trigger_source)); + autofill_suggestion_trigger_source_ = trigger_source; } void BnplManager::OnSuggestionsShown( @@ -218,6 +243,8 @@ .OnBnplSuggestionShown(); } + update_suggestions_callback_ = update_suggestions_callback; + if (!update_suggestions_barrier_callback_.has_value()) { return; } @@ -277,7 +304,7 @@ : std::vector<BnplIssuerContext>(), extracted_amount, is_amount_supported_by_any_issuer, ongoing_flow_state_->app_locale, - base::BindOnce(&BnplManager::OnIssuerSelected, + base::BindOnce(&BnplManager::OnIssuerAccepted, weak_factory_.GetWeakPtr()), base::BindOnce(&BnplManager::Reset, weak_factory_.GetWeakPtr())); @@ -332,11 +359,13 @@ case kDoNothing: break; case kCloseCurrentUi: - payments_autofill_client() - .GetBnplUiDelegate() - ->RemoveSelectBnplIssuerOrProgressUi(); + HideSuggestionsOrRemoveSelectBnplIssuerOrProgressUi(); + break; } + // TODO(crbug.com/477689220): Ensure error handling is done in a way + // where a new flow is not re-initiated if the user goes back to pay later + // tab. switch (result.error()) { case AiAmountExtractionResult::Error::kFailureToGenerateApc: case AiAmountExtractionResult::Error::kMissingServerResponse: @@ -361,28 +390,34 @@ const std::pair<int64_t, std::string>& amount_and_currency = result.value(); ongoing_flow_state_->final_checkout_amount = amount_and_currency.first; - if (IssuerSelectedAndCheckoutAmountWithinRange()) { - // If the selected issuer is eligible, continue the BNPL flow with this + if (IssuerAcceptedAndCheckoutAmountWithinRange()) { + // If the accepted issuer is eligible, continue the BNPL flow with this // issuer. - OnIssuerSelectedAndCheckoutAmountAvailable(); + OnIssuerAcceptedAndCheckoutAmountAvailable(); } else { - bool is_amount_supported_by_any_issuer = - IsExtractedAmountSupportedByAnyBnplIssuer( - payments_autofill_client() - .GetPaymentsDataManager() - .GetBnplIssuers(), - ongoing_flow_state_->final_checkout_amount); - // If the selected issuer is not eligible, update UI. - CHECK_DEREF(payments_autofill_client().GetBnplUiDelegate()) - .UpdateBnplIssuerUi( - GetSortedBnplIssuerContext( - browser_autofill_manager_->client(), - ongoing_flow_state_->final_checkout_amount), - ongoing_flow_state_->final_checkout_amount, - is_amount_supported_by_any_issuer, ongoing_flow_state_->app_locale, - base::BindOnce(&BnplManager::OnIssuerSelected, - weak_factory_.GetWeakPtr()), - base::BindOnce(&BnplManager::Reset, weak_factory_.GetWeakPtr())); + std::vector<BnplIssuerContext> issuer_contexts = + GetSortedBnplIssuerContext(browser_autofill_manager_->client(), + ongoing_flow_state_->final_checkout_amount); + if (base::FeatureList::IsEnabled( + features::kAutofillEnablePayNowPayLaterTabs)) { + UpdateSuggestionsOnAiAmountExtractionResponse(issuer_contexts); + } else { + bool is_amount_supported_by_any_issuer = + IsExtractedAmountSupportedByAnyBnplIssuer( + payments_autofill_client() + .GetPaymentsDataManager() + .GetBnplIssuers(), + ongoing_flow_state_->final_checkout_amount); + // If the accepted issuer is not eligible, update UI. + CHECK_DEREF(payments_autofill_client().GetBnplUiDelegate()) + .UpdateBnplIssuerUi( + issuer_contexts, ongoing_flow_state_->final_checkout_amount, + is_amount_supported_by_any_issuer, + ongoing_flow_state_->app_locale, + base::BindOnce(&BnplManager::OnIssuerAccepted, + weak_factory_.GetWeakPtr()), + base::BindOnce(&BnplManager::Reset, weak_factory_.GetWeakPtr())); + } } } @@ -436,6 +471,8 @@ payments_autofill_client().GetPaymentsNetworkInterface()->CancelRequest(); browser_autofill_manager_->GetAmountExtractionManager().Reset(); ongoing_flow_state_.reset(); + autofill_suggestion_trigger_source_.reset(); + update_suggestions_callback_.Reset(); weak_factory_.InvalidateWeakPtrs(); } @@ -484,24 +521,8 @@ Reset(); } -void BnplManager::OnIssuerSelected(BnplIssuer selected_issuer) { - ongoing_flow_state_->issuer = std::move(selected_issuer); - - // When an issuer is selected but amount is not received, call server-side AI - // to extract the amount. - if (base::FeatureList::IsEnabled( - features::kAutofillEnableAiBasedAmountExtraction) && - !ongoing_flow_state_->final_checkout_amount) { - browser_autofill_manager_->GetAmountExtractionManager() - .TriggerCheckoutAmountExtractionWithAi(); - return; - } - - OnIssuerSelectedAndCheckoutAmountAvailable(); -} - -bool BnplManager::IssuerSelectedAndCheckoutAmountWithinRange() { - // Check eligibility if an issuer was selected. +bool BnplManager::IssuerAcceptedAndCheckoutAmountWithinRange() { + // Check eligibility if an issuer was accepted. if (!ongoing_flow_state_->issuer) { return false; } @@ -533,7 +554,7 @@ return true; } -void BnplManager::OnIssuerSelectedAndCheckoutAmountAvailable() { +void BnplManager::OnIssuerAcceptedAndCheckoutAmountAvailable() { bool is_linked_issuer = ongoing_flow_state_->issuer->payment_instrument().has_value(); if (is_linked_issuer && !AcceptTosActionRequired()) { @@ -613,9 +634,8 @@ // ToS or error UI within the same view, so removing it is not necessary. break; case kCloseCurrentUi: - payments_autofill_client() - .GetBnplUiDelegate() - ->RemoveSelectBnplIssuerOrProgressUi(); + HideSuggestionsOrRemoveSelectBnplIssuerOrProgressUi(); + break; } if (result == payments::PaymentsAutofillClient::PaymentsRpcResult::kSuccess) { @@ -724,11 +744,10 @@ .GetBnplUiDelegate() ->RemoveBnplTosOrProgressUi(); } else { - // If the ToS UI wasn't shown during this flow, then the issuer - // selection UI or progress UI must be showing, so remove it. - payments_autofill_client() - .GetBnplUiDelegate() - ->RemoveSelectBnplIssuerOrProgressUi(); + // If the ToS UI wasn't shown during this flow, then the autofill + // suggestions UI, issuer selection UI, or progress UI must be showing, so + // remove it. + HideSuggestionsOrRemoveSelectBnplIssuerOrProgressUi(); } } @@ -948,4 +967,42 @@ } } +void BnplManager::UpdateSuggestionsOnAiAmountExtractionResponse( + const std::vector<payments::BnplIssuerContext>& issuer_contexts) { + std::vector<Suggestion> suggestions = base::ToVector( + browser_autofill_manager_->client().GetAutofillSuggestions()); + std::vector<Suggestion> bnpl_suggestions = GetSuggestionsForBnpl( + issuer_contexts, browser_autofill_manager_->client().GetAppLocale(), + /*is_card_number_field_empty=*/true); + + // Replace the loading throbber suggestion with the BNPL suggestions from + // `bnpl_suggestions`. This ensures that suggestions such as footers are kept + // after the newly added suggestions. + auto throbber_it = std::find_if( + suggestions.begin(), suggestions.end(), [](const Suggestion& suggestion) { + return suggestion.type == SuggestionType::kLoadingThrobber; + }); + CHECK(throbber_it != suggestions.end()); + throbber_it = suggestions.erase(throbber_it); + suggestions.insert(throbber_it, + std::make_move_iterator(bnpl_suggestions.begin()), + std::make_move_iterator(bnpl_suggestions.end())); + + CHECK(autofill_suggestion_trigger_source_.has_value()); + update_suggestions_callback_.Run(std::move(suggestions), + autofill_suggestion_trigger_source_.value()); +} + +void BnplManager::HideSuggestionsOrRemoveSelectBnplIssuerOrProgressUi() { + if (base::FeatureList::IsEnabled( + features::kAutofillEnablePayNowPayLaterTabs)) { + browser_autofill_manager_->client().HideAutofillSuggestions( + SuggestionHidingReason::kAcceptSuggestion); + } else { + payments_autofill_client() + .GetBnplUiDelegate() + ->RemoveSelectBnplIssuerOrProgressUi(); + } +} + } // namespace autofill::payments
diff --git a/components/autofill/core/browser/payments/bnpl_manager.h b/components/autofill/core/browser/payments/bnpl_manager.h index a0b74e0..1a0755bb 100644 --- a/components/autofill/core/browser/payments/bnpl_manager.h +++ b/components/autofill/core/browser/payments/bnpl_manager.h
@@ -62,6 +62,12 @@ std::optional<int64_t> final_checkout_amount, OnBnplVcnFetchedCallback on_bnpl_vcn_fetched_callback); + // Runs after the user accepts a BNPL issuer. It will initiate AI amount + // extraction if checkout amount is missing, or redirect to plan selection or + // terms of services depending on the issuer if checkout amount has already + // been extracted. + virtual void OnIssuerAccepted(BnplIssuer issuer); + // Notifies the BNPL manager that suggestion generation has been requested // with the given `trigger_source`. This must be called before // `OnSuggestionsShown()` and `OnAmountExtractionReturned()`, so that the @@ -165,19 +171,14 @@ // factory. void Reset(); - // Runs after the user selects a BNPL issuer, and will redirect to plan - // selection or terms of services depending on the issuer. - void OnIssuerSelected(BnplIssuer selected_issuer); + // Checks if a BNPL issuer was accepted and if the checkout amount is within + // the issuer's range. + bool IssuerAcceptedAndCheckoutAmountWithinRange(); - // Runs after the user selects a BNPL issuer and the checkout amount is - // within the issuer's range, and will redirect to plan selection or terms of - // services depending on the issuer linkage. - bool IssuerSelectedAndCheckoutAmountWithinRange(); - - // Runs after users select a BNPL issuer and the checkout amount is already - // received, and will redirect to plan selection or terms of services + // Runs after the user accepts a BNPL issuer and the checkout amount is + // already received, and will redirect to plan selection or terms of services // depending on the issuer. - void OnIssuerSelectedAndCheckoutAmountAvailable(); + void OnIssuerAcceptedAndCheckoutAmountAvailable(); // This function makes the appropriate server call to retrieve the ToS legal // message for the issuer. @@ -278,6 +279,15 @@ void OnBnplPaymentInstrumentUpdated( PaymentsAutofillClient::PaymentsRpcResult result); + // Updates the existing suggestions list based on the amount extraction + // response. + void UpdateSuggestionsOnAiAmountExtractionResponse( + const std::vector<payments::BnplIssuerContext>& issuer_contexts); + + // Hides the autofill suggestions or removes the select BNPL issuer or + // progress UI. + void HideSuggestionsOrRemoveSelectBnplIssuerOrProgressUi(); + #if BUILDFLAG(IS_ANDROID) // Callback triggered when Issuer selection is cancelled during Touch To Fill // flow. @@ -314,6 +324,16 @@ std::variant<SuggestionsShownResponse, std::optional<int64_t>>)>> update_suggestions_barrier_callback_; + // Trigger source for the current autofill suggestions. Set when the + // suggestions are generated, right before they are shown to the user. Reset + // when the flow is over. + std::optional<AutofillSuggestionTriggerSource> + autofill_suggestion_trigger_source_; + + // Callback for updating the currently shown payments autofill suggestions. + // Set when suggestions are shown, and reset when a BNPL flow is finished. + UpdateSuggestionsCallback update_suggestions_callback_; + base::WeakPtrFactory<BnplManager> weak_factory_{this}; };
diff --git a/components/autofill/core/browser/payments/bnpl_manager_test_api.h b/components/autofill/core/browser/payments/bnpl_manager_test_api.h index cc39002..111a768b 100644 --- a/components/autofill/core/browser/payments/bnpl_manager_test_api.h +++ b/components/autofill/core/browser/payments/bnpl_manager_test_api.h
@@ -56,8 +56,8 @@ void Reset() { bnpl_manager_->Reset(); } - void OnIssuerSelected(BnplIssuer selected_issuer) { - bnpl_manager_->OnIssuerSelected(selected_issuer); + void OnIssuerAccepted(BnplIssuer selected_issuer) { + bnpl_manager_->OnIssuerAccepted(selected_issuer); } BnplManager::OngoingFlowState* GetOngoingFlowState() { @@ -75,6 +75,14 @@ bnpl_manager_->OnRedirectUrlFetched(result, response); } + void OnDidGetLegalMessageFromServer( + PaymentsAutofillClient::PaymentsRpcResult result, + std::string context_token, + LegalMessageLines legal_message) { + bnpl_manager_->OnDidGetLegalMessageFromServer( + result, std::move(context_token), std::move(legal_message)); + } + void GetDetailsForUpdateBnplPaymentInstrument() { bnpl_manager_->GetDetailsForUpdateBnplPaymentInstrument(); }
diff --git a/components/autofill/core/browser/payments/bnpl_manager_unittest.cc b/components/autofill/core/browser/payments/bnpl_manager_unittest.cc index a49c4ab..266c398 100644 --- a/components/autofill/core/browser/payments/bnpl_manager_unittest.cc +++ b/components/autofill/core/browser/payments/bnpl_manager_unittest.cc
@@ -43,11 +43,13 @@ #include "components/autofill/core/browser/payments/test/mock_payments_window_manager.h" #include "components/autofill/core/browser/payments/test_legal_message_line.h" #include "components/autofill/core/browser/payments/test_payments_autofill_client.h" +#include "components/autofill/core/browser/suggestions/suggestion_hiding_reason.h" #include "components/autofill/core/browser/test_utils/autofill_test_utils.h" #include "components/autofill/core/browser/ui/payments/autofill_progress_ui_type.h" #include "components/autofill/core/browser/ui/payments/bnpl_tos_controller.h" #include "components/autofill/core/browser/ui/payments/bnpl_ui_delegate.h" #include "components/autofill/core/browser/ui/payments/select_bnpl_issuer_dialog_controller.h" +#include "components/autofill/core/common/aliases.h" #include "components/autofill/core/common/autofill_payments_features.h" #include "components/ukm/test_ukm_recorder.h" #include "services/metrics/public/cpp/ukm_builders.h" @@ -83,6 +85,17 @@ MOCK_METHOD(void, OnBnplSuggestionShown, (), (override)); }; +class MockAutofillClient : public TestAutofillClient { + public: + MockAutofillClient() = default; + ~MockAutofillClient() override = default; + + MOCK_METHOD(void, + HideAutofillSuggestions, + (SuggestionHidingReason reason), + (override)); +}; + class MockBrowserAutofillManager : public TestBrowserAutofillManager { public: explicit MockBrowserAutofillManager(TestAutofillDriver* driver) @@ -224,7 +237,7 @@ class BnplManagerTest : public Test, public WithTestAutofillClientDriverManager< - TestAutofillClient, + NiceMock<MockAutofillClient>, TestAutofillDriver, NiceMock<MockBrowserAutofillManager>, TestPaymentsAutofillClientMock> { @@ -240,7 +253,7 @@ const std::string kContextToken = "CONTEXT_TOKEN"; const GURL kRedirectUrl = GURL("REDIRECT_URL"); const GURL kPopupUrl = GURL("https://test.url/sometestpath/"); - const std::string kAppLocale = "en-GB"; + const std::string kAppLocale = "en-US"; const std::u16string kLegalMessage = u"LEGAL_MESSAGE"; const std::string kCurrency = "USD"; const GURL kDomain = GURL("https://dummytest.com/somepathforurl"); @@ -367,8 +380,8 @@ return {TestLegalMessageLine(base::UTF16ToUTF8(kLegalMessage))}; } - void OnIssuerSelected(const BnplIssuer& selected_issuer) { - bnpl_manager_->OnIssuerSelected(selected_issuer); + void OnIssuerAccepted(const BnplIssuer& selected_issuer) { + bnpl_manager_->OnIssuerAccepted(selected_issuer); } bool ShouldCloseViewBeforeSwitching() { @@ -717,7 +730,7 @@ EXPECT_EQ(test_api(*bnpl_manager_).GetOngoingFlowState(), nullptr); } -// Tests that `OnIssuerSelected()` calls with a linked BNPL issuer will call +// Tests that `OnIssuerAccepted()` calls with a linked BNPL issuer will call // the payments network interface with the request details filled out correctly. TEST_F( BnplManagerTest, @@ -740,7 +753,7 @@ kCurrency), /*callback=*/_)); - OnIssuerSelected(linked_issuer); + OnIssuerAccepted(linked_issuer); EXPECT_EQ(ongoing_flow_state->issuer, linked_issuer); EXPECT_EQ(ongoing_flow_state->issuer->payment_instrument()->instrument_id(), @@ -748,7 +761,7 @@ EXPECT_FALSE(ongoing_flow_state->risk_data.empty()); } -// Tests that `OnIssuerSelected()` calls with a linked BNPL issuer will not +// Tests that `OnIssuerAccepted()` calls with a linked BNPL issuer will not // load risk data again when there is a risk data string saved. TEST_F( BnplManagerTest, @@ -774,7 +787,7 @@ kAmount, kCurrency), /*callback=*/_)); - OnIssuerSelected(linked_issuer); + OnIssuerAccepted(linked_issuer); EXPECT_EQ(ongoing_flow_state->issuer, linked_issuer); EXPECT_EQ(ongoing_flow_state->issuer->payment_instrument()->instrument_id(), @@ -809,7 +822,7 @@ .WillOnce(base::test::RunOnceCallback<1>( PaymentsAutofillClient::PaymentsRpcResult::kSuccess, response)); - OnIssuerSelected(linked_issuer); + OnIssuerAccepted(linked_issuer); auto* ongoing_flow_state = test_api(*bnpl_manager_).GetOngoingFlowState(); EXPECT_EQ(ongoing_flow_state->issuer, linked_issuer); @@ -841,7 +854,7 @@ AutofillErrorDialogContext::WithBnplPermanentOrTemporaryError( /*is_permanent_error=*/false))); - OnIssuerSelected(linked_issuer); + OnIssuerAccepted(linked_issuer); EXPECT_EQ(test_api(*bnpl_manager_).GetOngoingFlowState(), nullptr); } @@ -870,7 +883,7 @@ AutofillErrorDialogContext::WithBnplPermanentOrTemporaryError( /*is_permanent_error=*/true))); - OnIssuerSelected(linked_issuer); + OnIssuerAccepted(linked_issuer); EXPECT_EQ(test_api(*bnpl_manager_).GetOngoingFlowState(), nullptr); } @@ -901,7 +914,7 @@ GetBnplPaymentInstrumentForFetchingVcn) .WillOnce(SaveArg<0>(&request_details)); - OnIssuerSelected(linked_issuer); + OnIssuerAccepted(linked_issuer); EXPECT_EQ(request_details.billing_customer_number, kBillingCustomerNumber); EXPECT_EQ(request_details.issuer_id, @@ -935,7 +948,7 @@ GetBnplPaymentInstrumentForFetchingVcn) .Times(0); - OnIssuerSelected(linked_issuer); + OnIssuerAccepted(linked_issuer); EXPECT_EQ(test_api(*bnpl_manager_).GetOngoingFlowState(), nullptr); } @@ -965,7 +978,7 @@ AutofillErrorDialogContext::WithBnplPermanentOrTemporaryError( /*is_permanent_error=*/false))); - OnIssuerSelected(linked_issuer); + OnIssuerAccepted(linked_issuer); EXPECT_EQ(test_api(*bnpl_manager_).GetOngoingFlowState(), nullptr); } @@ -1027,7 +1040,7 @@ BnplTosModel bnpl_tos_model; EXPECT_CALL(GetBnplUiDelegate(), ShowBnplTosUi) .WillOnce(SaveArg<0>(&bnpl_tos_model)); - OnIssuerSelected(unlinked_issuer); + OnIssuerAccepted(unlinked_issuer); EXPECT_EQ(test_api(*bnpl_manager_).GetOngoingFlowState()->context_token, kContextToken); @@ -1064,12 +1077,12 @@ EXPECT_NE(test_api(*bnpl_manager_).GetOngoingFlowState(), nullptr); - OnIssuerSelected(unlinked_issuer); + OnIssuerAccepted(unlinked_issuer); EXPECT_EQ(test_api(*bnpl_manager_).GetOngoingFlowState(), nullptr); } -// Tests that `OnIssuerSelected()` correctly sets the instrument_id for an +// Tests that `OnIssuerAccepted()` correctly sets the instrument_id for an // externally linked issuer before proceeding with the flow. TEST_F(BnplManagerTest, OnIssuerSelected_SetsInstrumentIdForExternallyLinkedIssuer) { @@ -1082,7 +1095,7 @@ EXPECT_CALL(*payments_network_interface_, GetDetailsForUpdateBnplPaymentInstrument); - OnIssuerSelected(externally_linked_issuer); + OnIssuerAccepted(externally_linked_issuer); auto* ongoing_flow_state = test_api(*bnpl_manager_).GetOngoingFlowState(); EXPECT_EQ(ongoing_flow_state->issuer, externally_linked_issuer); @@ -1107,7 +1120,7 @@ AutofillErrorDialogContext::WithBnplPermanentOrTemporaryError( /*is_permanent_error=*/false))); - OnIssuerSelected(unlinked_issuer); + OnIssuerAccepted(unlinked_issuer); EXPECT_EQ(test_api(*bnpl_manager_).GetOngoingFlowState(), nullptr); } @@ -2236,6 +2249,118 @@ EXPECT_FALSE(BnplManager::IsBnplIssuerSupported(kBnplKlarnaIssuerId)); } +// Tests that `OnDidGetLegalMessageFromServer` removes the autofill suggestions +// UI instead of the issuer selection UI when PayNowPayLater tabs are enabled. +TEST_F( + BnplManagerTest, + OnDidGetLegalMessageFromServer_PayNowPayLaterTabsEnabled_HidesAutofillSuggestionsUi) { + base::test::ScopedFeatureList scoped_feature_list{ + features::kAutofillEnablePayNowPayLaterTabs}; + + test_api(*bnpl_manager_) + .PopulateManagerWithUserAndBnplIssuerDetails( + kBillingCustomerNumber, kRiskData, kContextToken, kRedirectUrl, + test::GetTestUnlinkedBnplIssuer()); + + EXPECT_CALL( + autofill_client(), + HideAutofillSuggestions(SuggestionHidingReason::kAcceptSuggestion)); + EXPECT_CALL(GetBnplUiDelegate(), RemoveSelectBnplIssuerOrProgressUi).Times(0); + EXPECT_CALL(GetBnplUiDelegate(), ShowBnplTosUi); + + test_api(*bnpl_manager_) + .OnDidGetLegalMessageFromServer( + PaymentsAutofillClient::PaymentsRpcResult::kSuccess, kContextToken, + GetExpectedLegalMessageLines()); +} + +// Tests that `OnDidGetLegalMessageFromServer` removes the issuer selection UI +// or progress throbber UI instead of the autofill suggestions UI when +// PayNowPayLater tabs are disabled. +TEST_F( + BnplManagerTest, + OnDidGetLegalMessageFromServer_PayNowPayLaterTabsDisabled_RemovesIssuerSelectionUi) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndDisableFeature( + {features::kAutofillEnablePayNowPayLaterTabs}); + + test_api(*bnpl_manager_) + .PopulateManagerWithUserAndBnplIssuerDetails( + kBillingCustomerNumber, kRiskData, kContextToken, kRedirectUrl, + test::GetTestUnlinkedBnplIssuer()); + + EXPECT_CALL(GetBnplUiDelegate(), RemoveSelectBnplIssuerOrProgressUi()); + EXPECT_CALL(autofill_client(), HideAutofillSuggestions).Times(0); + EXPECT_CALL(GetBnplUiDelegate(), ShowBnplTosUi); + + test_api(*bnpl_manager_) + .OnDidGetLegalMessageFromServer( + PaymentsAutofillClient::PaymentsRpcResult::kSuccess, kContextToken, + GetExpectedLegalMessageLines()); +} + +// Tests that `OnRedirectUrlFetched` removes the autofill suggestions UI +// instead of the issuer selection UI when PayNowPayLater tabs are enabled. +TEST_F( + BnplManagerTest, + OnRedirectUrlFetched_PayNowPayLaterTabsEnabled_HidesAutofillSuggestionsUi) { + base::test::ScopedFeatureList scoped_feature_list{ + features::kAutofillEnablePayNowPayLaterTabs}; + + test_api(*bnpl_manager_) + .PopulateManagerWithUserAndBnplIssuerDetails( + kBillingCustomerNumber, kRiskData, kContextToken, kRedirectUrl, + test::GetTestLinkedBnplIssuer()); + + EXPECT_CALL( + autofill_client(), + HideAutofillSuggestions(SuggestionHidingReason::kAcceptSuggestion)); + EXPECT_CALL(GetBnplUiDelegate(), RemoveSelectBnplIssuerOrProgressUi).Times(0); + EXPECT_CALL(*static_cast<MockPaymentsWindowManager*>( + payments_autofill_client().GetPaymentsWindowManager()), + InitBnplFlow(_)); + + BnplFetchUrlResponseDetails response; + response.redirect_url = kRedirectUrl; + response.success_url_prefix = GURL("success"); + response.failure_url_prefix = GURL("failure"); + response.context_token = kContextToken; + + test_api(*bnpl_manager_) + .OnRedirectUrlFetched(PaymentsAutofillClient::PaymentsRpcResult::kSuccess, + response); +} + +// Tests that `OnRedirectUrlFetched` removes the issuer selection UI instead of +// the autofill suggestions UI when PayNowPayLater tabs are disabled. +TEST_F( + BnplManagerTest, + OnRedirectUrlFetched_PayNowPayLaterTabsDisabled_RemovesIssuerSelectionUi) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndDisableFeature( + {features::kAutofillEnablePayNowPayLaterTabs}); + + test_api(*bnpl_manager_) + .PopulateManagerWithUserAndBnplIssuerDetails( + kBillingCustomerNumber, kRiskData, kContextToken, kRedirectUrl, + test::GetTestLinkedBnplIssuer()); + + EXPECT_CALL(GetBnplUiDelegate(), RemoveSelectBnplIssuerOrProgressUi()); + EXPECT_CALL(autofill_client(), HideAutofillSuggestions).Times(0); + EXPECT_CALL(*static_cast<MockPaymentsWindowManager*>( + payments_autofill_client().GetPaymentsWindowManager()), + InitBnplFlow); + + BnplFetchUrlResponseDetails response; + response.redirect_url = kRedirectUrl; + response.success_url_prefix = GURL("success"); + response.failure_url_prefix = GURL("failure"); + response.context_token = kContextToken; + + test_api(*bnpl_manager_) + .OnRedirectUrlFetched(PaymentsAutofillClient::PaymentsRpcResult::kSuccess, + response); +} #endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || // BUILDFLAG(IS_CHROMEOS) @@ -2343,7 +2468,7 @@ .IsAutofillAmountExtractionAiTermsSeenPrefEnabled()); } -TEST_F(BnplManagerTest, OnIssuerSelected_TriggersExtractionAfterTermsNotSeen) { +TEST_F(BnplManagerTest, OnIssuerAccepted_TriggersExtractionAfterTermsNotSeen) { base::test::ScopedFeatureList scoped_feature_list; scoped_feature_list.InitAndEnableFeature( features::kAutofillEnableAiBasedAmountExtraction); @@ -2359,13 +2484,13 @@ TriggerCheckoutAmountExtractionWithAi()); EXPECT_CALL(GetBnplUiDelegate(), UpdateBnplIssuerUi); - test_api(*bnpl_manager_).OnIssuerSelected(test::GetTestUnlinkedBnplIssuer()); + test_api(*bnpl_manager_).OnIssuerAccepted(test::GetTestUnlinkedBnplIssuer()); bnpl_manager_->OnAmountExtractionReturnedFromAi( std::make_pair(1'000'000, "USD")); } -// Tests that `OnIssuerSelected()` calls with a linked issuer where ToS +// Tests that `OnIssuerAccepted()` calls with a linked issuer where ToS // acceptance is required will call the payments network interface with the // request details filled out correctly. TEST_F( @@ -2412,12 +2537,12 @@ /*callback=*/_)); #endif // BUILDFLAG(IS_ANDROID) - OnIssuerSelected(issuer); + OnIssuerAccepted(issuer); EXPECT_EQ(test_api(*bnpl_manager_).GetOngoingFlowState()->issuer, issuer); } -// Tests that `OnIssuerSelected()` calls with an unlinked BNPL issuer will call +// Tests that `OnIssuerAccepted()` calls with an unlinked BNPL issuer will call // the payments network interface with the request details filled out correctly. TEST_F( BnplManagerTest, @@ -2456,7 +2581,7 @@ /*callback=*/_)); #endif // BUILDFLAG(IS_ANDROID) - OnIssuerSelected(unlinked_issuer); + OnIssuerAccepted(unlinked_issuer); EXPECT_EQ(test_api(*bnpl_manager_).GetOngoingFlowState()->issuer, unlinked_issuer); @@ -2809,7 +2934,7 @@ bnpl_manager_->OnUserDecisionToUseBnpl( /*final_checkout_amount=*/std::nullopt, /*on_bnpl_vcn_fetched_callback=*/base::DoNothing()); - OnIssuerSelected(test::GetTestLinkedBnplIssuer(IssuerId::kBnplAffirm)); + OnIssuerAccepted(test::GetTestLinkedBnplIssuer(IssuerId::kBnplAffirm)); bnpl_manager_->OnAmountExtractionReturnedFromAi( std::make_pair(100'000'000, "USD")); @@ -2843,7 +2968,7 @@ bnpl_manager_->OnUserDecisionToUseBnpl( /*final_checkout_amount=*/std::nullopt, /*on_bnpl_vcn_fetched_callback=*/base::DoNothing()); - OnIssuerSelected(test::GetTestLinkedBnplIssuer(IssuerId::kBnplZip)); + OnIssuerAccepted(test::GetTestLinkedBnplIssuer(IssuerId::kBnplZip)); bnpl_manager_->OnAmountExtractionReturnedFromAi( std::make_pair(5'000'000, "USD")); @@ -2877,7 +3002,7 @@ bnpl_manager_->OnUserDecisionToUseBnpl( /*final_checkout_amount=*/std::nullopt, /*on_bnpl_vcn_fetched_callback=*/base::DoNothing()); - OnIssuerSelected(test::GetTestLinkedBnplIssuer(IssuerId::kBnplAffirm)); + OnIssuerAccepted(test::GetTestLinkedBnplIssuer(IssuerId::kBnplAffirm)); bnpl_manager_->OnAmountExtractionReturnedFromAi( std::make_pair(100'000'000, "USD")); @@ -2964,7 +3089,77 @@ bnpl_manager_->OnAmountExtractionReturnedFromAi( base::unexpected(AiAmountExtractionResult::Error::kUnsupportedCurrency)); } - #endif // !BUILDFLAG(IS_IOS) +#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \ + BUILDFLAG(IS_CHROMEOS) +TEST_F( + BnplManagerTest, + OnAmountExtractionReturnedFromAi_IssuerNotSelectedYet_PayLaterTabsUpdatesSuggestions) { + base::test::ScopedFeatureList feature_list{ + features::kAutofillEnablePayNowPayLaterTabs}; + + base::MockRepeatingCallback<void(std::vector<Suggestion>, + AutofillSuggestionTriggerSource)> + mock_update_suggestions_callback; + bnpl_manager_->NotifyOfSuggestionGeneration( + AutofillSuggestionTriggerSource::kFormControlElementClicked); + bnpl_manager_->OnSuggestionsShown( + {Suggestion(SuggestionType::kCreditCardEntry), + Suggestion(SuggestionType::kManageCreditCard)}, + mock_update_suggestions_callback.Get()); + + EXPECT_CALL(GetBnplUiDelegate(), ShowSelectBnplIssuerUi).Times(0); + EXPECT_CALL(GetBnplUiDelegate(), ShowProgressUi).Times(0); + bnpl_manager_->OnUserDecisionToUseBnpl( + /*final_checkout_amount=*/std::nullopt, + /*on_bnpl_vcn_fetched_callback=*/base::DoNothing()); + + SetUpLinkedBnplIssuer(/*price_lower_bound_in_micros=*/40'000'000, + /*price_higher_bound_in_micros=*/1'000'000'000, + IssuerId::kBnplAffirm, + /*instrument_id=*/1234); + SetUpUnlinkedBnplIssuer(/*price_lower_bound_in_micros=*/1'000'000'000, + /*price_higher_bound_in_micros=*/2'000'000'000, + IssuerId::kBnplZip); + SetUpLinkedBnplIssuer(/*price_lower_bound_in_micros=*/40'000'000, + /*price_higher_bound_in_micros=*/1'000'000'000, + IssuerId::kBnplKlarna, + /*instrument_id=*/5678); + + autofill_client().SetAutofillSuggestions( + {Suggestion(SuggestionType::kLoadingThrobber), + Suggestion(SuggestionType::kBnplFootnote)}); + + using BnplIssuerAlias = autofill::Suggestion::BnplIssuer; + EXPECT_CALL( + mock_update_suggestions_callback, + Run(UnorderedElementsAre( + AllOf(Field(&Suggestion::type, SuggestionType::kBnplEntry), + Field(&Suggestion::payload, + VariantWith<BnplIssuerAlias>( + Property(&BnplIssuerAlias::value, + Property(&BnplIssuer::issuer_id, + Eq(IssuerId::kBnplAffirm)))))), + AllOf(Field(&Suggestion::type, SuggestionType::kBnplEntry), + Field(&Suggestion::payload, + VariantWith<BnplIssuerAlias>( + Property(&BnplIssuerAlias::value, + Property(&BnplIssuer::issuer_id, + Eq(IssuerId::kBnplKlarna)))))), + AllOf(Field(&Suggestion::type, SuggestionType::kBnplEntry), + Field(&Suggestion::payload, + VariantWith<BnplIssuerAlias>( + Property(&BnplIssuerAlias::value, + Property(&BnplIssuer::issuer_id, + Eq(IssuerId::kBnplZip)))))), + Field(&Suggestion::type, SuggestionType::kBnplFootnote)), + AutofillSuggestionTriggerSource::kFormControlElementClicked)); + + bnpl_manager_->OnAmountExtractionReturnedFromAi( + std::make_pair(1'000'000, "USD")); +} +#endif // #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || + // BUILDFLAG(IS_CHROMEOS) + } // namespace autofill::payments
diff --git a/components/autofill/core/browser/payments/bnpl_strategy.cc b/components/autofill/core/browser/payments/bnpl_strategy.cc index 8cbcb6da..6e934b5 100644 --- a/components/autofill/core/browser/payments/bnpl_strategy.cc +++ b/components/autofill/core/browser/payments/bnpl_strategy.cc
@@ -15,8 +15,8 @@ NOTREACHED(); } -BnplStrategy::BnplSuggestionAcceptedNextAction -BnplStrategy::GetNextActionOnBnplSuggestionAcceptance() { +BnplStrategy::UserDecisionToUseBnplNextAction +BnplStrategy::GetNextActionOnUserDecisionToUseBnpl() { NOTREACHED(); }
diff --git a/components/autofill/core/browser/payments/bnpl_strategy.h b/components/autofill/core/browser/payments/bnpl_strategy.h index b1889c23..cf4f511 100644 --- a/components/autofill/core/browser/payments/bnpl_strategy.h +++ b/components/autofill/core/browser/payments/bnpl_strategy.h
@@ -17,6 +17,7 @@ // Defines the next step that the BnplManager should take after the user has // been shown a payment method autofill suggestion. The strategy // implementation determines which action to return based on the platform. + // TODO(crbug.com/477689220): Rename to SuggestionsShownNextAction. enum class SuggestionShownNextAction { // The flow should check if a BNPL suggestion is currently being shown. // If it isn't, then run the update suggestions barrier callback. @@ -29,9 +30,9 @@ }; // Defines the next step that the BnplManager should take after the user has - // accepted a BNPL autofill suggestion. The strategy implementation determines - // which action to return based on the platform. - enum class BnplSuggestionAcceptedNextAction { + // decided to use BNPL. The strategy implementation determines which action to + // return based on the platform. + enum class UserDecisionToUseBnplNextAction { // The flow should show the Select BNPL Issuer UI. kShowSelectBnplIssuerUiForDesktop = 0, @@ -40,7 +41,11 @@ // screen. Otherwise, show the progress screen. kCheckAmountExtractionBeforeContinuingFlowForAndroid = 1, - kMaxValue = kCheckAmountExtractionBeforeContinuingFlowForAndroid, + // The flow logic will handle the next step, nothing needs to be done and + // the UI does not need to be notified of anything. + kDoNothing = 2, + + kMaxValue = kDoNothing, }; // Defines the next step that the BnplManager should take after amount @@ -76,10 +81,9 @@ // method autofill suggestion. virtual SuggestionShownNextAction GetNextActionOnSuggestionShown(); - // Returns the next action to take after the user has accepted a BNPL - // suggestion. - virtual BnplSuggestionAcceptedNextAction - GetNextActionOnBnplSuggestionAcceptance(); + // Returns the next action to take after the user has decided to use BNPL. + virtual UserDecisionToUseBnplNextAction + GetNextActionOnUserDecisionToUseBnpl(); // Returns the next action to take after the amount extraction is finished. virtual BnplAmountExtractionReturnedNextAction
diff --git a/components/autofill/core/browser/payments/constants.h b/components/autofill/core/browser/payments/constants.h index 9fc90b8..736b79d 100644 --- a/components/autofill/core/browser/payments/constants.h +++ b/components/autofill/core/browser/payments/constants.h
@@ -8,6 +8,7 @@ #include <string_view> #include "components/autofill/core/browser/field_types.h" +#include "components/autofill/core/browser/suggestions/suggestion.h" namespace autofill { @@ -59,6 +60,11 @@ // The diameter of the loading throbber used in dialogs. inline constexpr int kDialogThrobberDiameter = 24; +// The index of the tab that shows all Pay Later suggestions in the suggestion +// bubble. +inline constexpr SuggestionTabIndex kPayLaterSuggestionTabIndex = + SuggestionTabIndex(1); + } // namespace autofill #endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_CONSTANTS_H_
diff --git a/components/autofill/core/browser/payments/desktop_bnpl_strategy.cc b/components/autofill/core/browser/payments/desktop_bnpl_strategy.cc index 09a7a43..9c4748d 100644 --- a/components/autofill/core/browser/payments/desktop_bnpl_strategy.cc +++ b/components/autofill/core/browser/payments/desktop_bnpl_strategy.cc
@@ -4,6 +4,8 @@ #include "components/autofill/core/browser/payments/desktop_bnpl_strategy.h" +#include "components/autofill/core/common/autofill_payments_features.h" + namespace autofill::payments { DesktopBnplStrategy::DesktopBnplStrategy() = default; @@ -16,9 +18,14 @@ kNotifyUpdateCallbackOfSuggestionsShownResponse; } -BnplStrategy::BnplSuggestionAcceptedNextAction -DesktopBnplStrategy::GetNextActionOnBnplSuggestionAcceptance() { - return BnplSuggestionAcceptedNextAction::kShowSelectBnplIssuerUiForDesktop; +BnplStrategy::UserDecisionToUseBnplNextAction +DesktopBnplStrategy::GetNextActionOnUserDecisionToUseBnpl() { + if (base::FeatureList::IsEnabled( + features::kAutofillEnablePayNowPayLaterTabs)) { + return UserDecisionToUseBnplNextAction::kDoNothing; + } + + return UserDecisionToUseBnplNextAction::kShowSelectBnplIssuerUiForDesktop; } BnplStrategy::BnplAmountExtractionReturnedNextAction
diff --git a/components/autofill/core/browser/payments/desktop_bnpl_strategy.h b/components/autofill/core/browser/payments/desktop_bnpl_strategy.h index fd9d0451..5ff33ea 100644 --- a/components/autofill/core/browser/payments/desktop_bnpl_strategy.h +++ b/components/autofill/core/browser/payments/desktop_bnpl_strategy.h
@@ -20,7 +20,7 @@ // BnplStrategy: SuggestionShownNextAction GetNextActionOnSuggestionShown() override; - BnplSuggestionAcceptedNextAction GetNextActionOnBnplSuggestionAcceptance() + UserDecisionToUseBnplNextAction GetNextActionOnUserDecisionToUseBnpl() override; BnplAmountExtractionReturnedNextAction GetNextActionOnAmountExtractionReturned() override;
diff --git a/components/autofill/core/browser/payments/desktop_bnpl_strategy_unittest.cc b/components/autofill/core/browser/payments/desktop_bnpl_strategy_unittest.cc index edd3502..37fa0486 100644 --- a/components/autofill/core/browser/payments/desktop_bnpl_strategy_unittest.cc +++ b/components/autofill/core/browser/payments/desktop_bnpl_strategy_unittest.cc
@@ -4,6 +4,8 @@ #include "components/autofill/core/browser/payments/desktop_bnpl_strategy.h" +#include "base/test/scoped_feature_list.h" +#include "components/autofill/core/common/autofill_payments_features.h" #include "testing/gtest/include/gtest/gtest.h" namespace autofill::payments { @@ -25,14 +27,24 @@ kNotifyUpdateCallbackOfSuggestionsShownResponse); } -// Verify that GetNextActionOnBnplSuggestionAcceptance() returns the correct +// Verify that GetNextActionOnUserDecisionToUseBnpl() returns the correct // action for the desktop platform. -TEST_F(DesktopBnplStrategyTest, GetNextActionOnBnplSuggestionAcceptance) { - EXPECT_EQ(desktop_bnpl_strategy_.GetNextActionOnBnplSuggestionAcceptance(), - BnplStrategy::BnplSuggestionAcceptedNextAction:: +TEST_F(DesktopBnplStrategyTest, GetNextActionOnUserDecisionToUseBnpl) { + EXPECT_EQ(desktop_bnpl_strategy_.GetNextActionOnUserDecisionToUseBnpl(), + BnplStrategy::UserDecisionToUseBnplNextAction:: kShowSelectBnplIssuerUiForDesktop); } +// Verify that GetNextActionOnUserDecisionToUseBnpl() returns the correct +// action for the desktop platform in the Pay later tabs case. +TEST_F(DesktopBnplStrategyTest, + GetNextActionOnUserDecisionToUseBnpl_PayLaterTabs) { + base::test::ScopedFeatureList feature_list{ + features::kAutofillEnablePayNowPayLaterTabs}; + EXPECT_EQ(desktop_bnpl_strategy_.GetNextActionOnUserDecisionToUseBnpl(), + BnplStrategy::UserDecisionToUseBnplNextAction::kDoNothing); +} + // Verify that GetNextActionOnAmountExtractionReturned() returns the correct // action for the desktop platform. TEST_F(DesktopBnplStrategyTest, GetNextActionOnAmountExtractionReturned) {
diff --git a/components/autofill/core/browser/payments/test/mock_bnpl_manager.h b/components/autofill/core/browser/payments/test/mock_bnpl_manager.h index c571c09..689e43887a 100644 --- a/components/autofill/core/browser/payments/test/mock_bnpl_manager.h +++ b/components/autofill/core/browser/payments/test/mock_bnpl_manager.h
@@ -5,6 +5,7 @@ #ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_TEST_MOCK_BNPL_MANAGER_H_ #define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_TEST_MOCK_BNPL_MANAGER_H_ +#include "components/autofill/core/browser/data_model/payments/bnpl_issuer.h" #include "components/autofill/core/browser/payments/bnpl_manager.h" #include "components/autofill/core/browser/suggestions/suggestion.h" #include "testing/gmock/include/gmock/gmock.h" @@ -45,6 +46,8 @@ (std::optional<int64_t> final_checkout_amount, OnBnplVcnFetchedCallback on_bnpl_vcn_fetched_callback), (override)); + + MOCK_METHOD(void, OnIssuerAccepted, (BnplIssuer), (override)); }; } // namespace autofill
diff --git a/components/autofill/core/browser/suggestions/payments/credit_card_suggestion_generator.cc b/components/autofill/core/browser/suggestions/payments/credit_card_suggestion_generator.cc index 8502a81..c3b8a25 100644 --- a/components/autofill/core/browser/suggestions/payments/credit_card_suggestion_generator.cc +++ b/components/autofill/core/browser/suggestions/payments/credit_card_suggestion_generator.cc
@@ -40,34 +40,6 @@ using SuggestionDataSource = SuggestionGenerator::SuggestionDataSource; using SuggestionData = SuggestionGenerator::SuggestionData; -Suggestion CreateBnplSuggestion( - const payments::BnplIssuerContext& issuer_context, - const std::string& app_locale, - const bool is_card_number_field_empty) { - const bool is_linked = issuer_context.issuer.payment_instrument().has_value(); - - Suggestion bnpl_suggestion(SuggestionType::kBnplEntry); - bnpl_suggestion.main_text = - Suggestion::Text(issuer_context.issuer.GetDisplayName(), - Suggestion::Text::IsPrimary(true)); - if (is_card_number_field_empty) { - bnpl_suggestion.labels = { - {Suggestion::Text(payments::GetBnplIssuerSelectionOptionText( - issuer_context.issuer.issuer_id(), app_locale, - base::span_from_ref(issuer_context)))}}; - } else { - bnpl_suggestion.labels = {{Suggestion::Text(l10n_util::GetStringUTF16( - IDS_AUTOFILL_CARD_BNPL_PAY_LATER_CLEAR_FORM_TO_ENABLE))}}; - bnpl_suggestion.acceptability = - Suggestion::Acceptability::kUnacceptableWithDeactivatedStyle; - } - bnpl_suggestion.icon = payments::GetBnplSuggestionIcon( - issuer_context.issuer.issuer_id(), is_linked); - bnpl_suggestion.payload = Suggestion::BnplIssuer(issuer_context.issuer); - - return bnpl_suggestion; -} - bool IsSaveAndFillEnabled() { #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \ BUILDFLAG(IS_CHROMEOS) @@ -225,14 +197,13 @@ Suggestion::Acceptability::kUnacceptable; loading_suggestion.expected_number_of_suggestions = payments_data_manager.GetBnplIssuers().size(); + loading_suggestion.tab_index = kPayLaterSuggestionTabIndex; suggestions.push_back(std::move(loading_suggestion)); } else { - for (const payments::BnplIssuerContext& context : - payments::GetSortedBnplIssuerContext( - client, /*checkout_amount=*/std::nullopt)) { - suggestions.push_back(CreateBnplSuggestion( - context, client.GetAppLocale(), is_card_number_field_empty)); - } + suggestions.append_range(GetSuggestionsForBnpl( + payments::GetSortedBnplIssuerContext( + client, /*checkout_amount=*/std::nullopt), + client.GetAppLocale(), is_card_number_field_empty)); } } @@ -395,6 +366,43 @@ return suggestions; } +std::vector<Suggestion> GetSuggestionsForBnpl( + std::vector<payments::BnplIssuerContext> issuer_contexts, + const std::string& app_locale, + const bool is_card_number_field_empty) { + std::vector<Suggestion> bnpl_suggestions; + bnpl_suggestions.reserve(issuer_contexts.size()); + + for (payments::BnplIssuerContext& issuer_context : issuer_contexts) { + const bool is_linked = + issuer_context.issuer.payment_instrument().has_value(); + + Suggestion bnpl_suggestion(SuggestionType::kBnplEntry); + bnpl_suggestion.main_text = + Suggestion::Text(issuer_context.issuer.GetDisplayName(), + Suggestion::Text::IsPrimary(true)); + if (is_card_number_field_empty) { + bnpl_suggestion.labels = { + {Suggestion::Text(payments::GetBnplIssuerSelectionOptionText( + issuer_context.issuer.issuer_id(), app_locale, + base::span_from_ref(issuer_context)))}}; + } else { + bnpl_suggestion.labels = {{Suggestion::Text(l10n_util::GetStringUTF16( + IDS_AUTOFILL_CARD_BNPL_PAY_LATER_CLEAR_FORM_TO_ENABLE))}}; + bnpl_suggestion.acceptability = + Suggestion::Acceptability::kUnacceptableWithDeactivatedStyle; + } + bnpl_suggestion.icon = payments::GetBnplSuggestionIcon( + issuer_context.issuer.issuer_id(), is_linked); + bnpl_suggestion.payload = + Suggestion::BnplIssuer(std::move(issuer_context.issuer)); + bnpl_suggestion.tab_index = kPayLaterSuggestionTabIndex; + bnpl_suggestions.emplace_back(bnpl_suggestion); + } + + return bnpl_suggestions; +} + CreditCardSuggestionGenerator::CreditCardSuggestionGenerator( const std::vector<std::string>& four_digit_combinations_in_dom, const payments::AmountExtractionStatus& amount_extraction_status,
diff --git a/components/autofill/core/browser/suggestions/payments/credit_card_suggestion_generator.h b/components/autofill/core/browser/suggestions/payments/credit_card_suggestion_generator.h index 1510aad..910d2cc 100644 --- a/components/autofill/core/browser/suggestions/payments/credit_card_suggestion_generator.h +++ b/components/autofill/core/browser/suggestions/payments/credit_card_suggestion_generator.h
@@ -47,6 +47,11 @@ const AutofillMetrics::PaymentsSigninState signin_state_for_metrics, bool exclude_virtual_cards); +std::vector<Suggestion> GetSuggestionsForBnpl( + std::vector<payments::BnplIssuerContext> issuer_contexts, + const std::string& app_locale, + const bool is_card_number_field_empty); + // A `SuggestionGenerator` for `FillingProduct::kCreditCard`. // // This class encapsulates logic used exclusively for generating credit card
diff --git a/components/autofill/core/browser/suggestions/payments/credit_card_suggestion_generator_unittest.cc b/components/autofill/core/browser/suggestions/payments/credit_card_suggestion_generator_unittest.cc index d556798..5ae01ae7 100644 --- a/components/autofill/core/browser/suggestions/payments/credit_card_suggestion_generator_unittest.cc +++ b/components/autofill/core/browser/suggestions/payments/credit_card_suggestion_generator_unittest.cc
@@ -44,6 +44,7 @@ #include "components/autofill/core/browser/metrics/payments/save_and_fill_metrics.h" #include "components/autofill/core/browser/metrics/suggestions_list_metrics.h" #include "components/autofill/core/browser/payments/amount_extraction_manager.h" +#include "components/autofill/core/browser/payments/bnpl_util.h" #include "components/autofill/core/browser/payments/constants.h" #include "components/autofill/core/browser/payments/test/mock_bnpl_manager.h" #include "components/autofill/core/browser/suggestions/payments/payments_suggestion_generator_util.h" @@ -111,6 +112,10 @@ return EqualLabels(suggestion_objects); } +Matcher<Suggestion> EqualSuggestionTabIndex(SuggestionTabIndex tab_index) { + return Field("tab_index", &Suggestion::tab_index, tab_index); +} + // This function is currently only used for BNPL unittests, and BNPL is // currently only available for desktop and android platforms. #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \ @@ -120,7 +125,8 @@ Field(&Suggestion::main_text, suggestion.main_text), Field(&Suggestion::minor_texts, suggestion.minor_texts), Field(&Suggestion::icon, suggestion.icon), - Field(&Suggestion::labels, suggestion.labels)); + Field(&Suggestion::labels, suggestion.labels), + EqualSuggestionTabIndex(suggestion.tab_index)); } #endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || // BUILDFLAG(IS_CHROMEOS) @@ -160,10 +166,6 @@ testing::Matcher<const std::vector<Suggestion>&> ContainsCreditCardFooterSuggestions(bool with_gpay_logo, bool with_bnpl_footnote = false) { - // TODO(crbug.com/477689220): Verify that the BNPL footnote suggestion and the - // Manage Payments suggestion have distinct `tab_index` values to ensure they - // will not be shown at the same time after suggestion filtering - // infrastructure is updated. if (with_bnpl_footnote) { return AllOf( SizeIs(Ge(3)), @@ -172,9 +174,12 @@ return base::span(container).template last<3>(); }, ElementsAre( - EqualsSuggestion(SuggestionType::kBnplFootnote), - EqualsSuggestion(SuggestionType::kSeparator), - EqualsManagePaymentsMethodsSuggestion(with_gpay_logo)))); + AllOf(EqualsSuggestion(SuggestionType::kBnplFootnote), + EqualSuggestionTabIndex(kPayLaterSuggestionTabIndex)), + AllOf(EqualsSuggestion(SuggestionType::kSeparator), + EqualSuggestionTabIndex(kDefaultSuggestionTabIndex)), + AllOf(EqualsManagePaymentsMethodsSuggestion(with_gpay_logo), + EqualSuggestionTabIndex(kDefaultSuggestionTabIndex))))); } return AllOf( SizeIs(Ge(2)), @@ -182,8 +187,11 @@ [](const std::vector<Suggestion>& container) { return base::span(container).template last<2>(); }, - ElementsAre(EqualsSuggestion(SuggestionType::kSeparator), - EqualsManagePaymentsMethodsSuggestion(with_gpay_logo)))); + ElementsAre( + AllOf(EqualsSuggestion(SuggestionType::kSeparator), + EqualSuggestionTabIndex(kDefaultSuggestionTabIndex)), + AllOf(EqualsManagePaymentsMethodsSuggestion(with_gpay_logo), + EqualSuggestionTabIndex(kDefaultSuggestionTabIndex))))); } auto SuggestionWithGuidPayload(const Suggestion::Guid& guid) { @@ -1667,20 +1675,24 @@ std::vector<BnplIssuer> bnpl_issuers = payments_data().GetBnplIssuers(); EXPECT_THAT( updated_suggestions[current_suggestion_index++], - EqualsSuggestion( - SuggestionType::kBnplEntry, - l10n_util::GetStringUTF16(IDS_AUTOFILL_BNPL_PAY_LATER_OPTIONS_TEXT), - Suggestion::Icon::kBnplGeneric, - {{Suggestion::Text(l10n_util::GetStringFUTF16( - IDS_AUTOFILL_BNPL_CREDIT_CARD_SUGGESTION_LABEL_TWO_ISSUERS, - bnpl_issuers[1].GetDisplayName(), - bnpl_issuers[0].GetDisplayName()))}})); + AllOf(EqualsSuggestion( + SuggestionType::kBnplEntry, + l10n_util::GetStringUTF16( + IDS_AUTOFILL_BNPL_PAY_LATER_OPTIONS_TEXT), + Suggestion::Icon::kBnplGeneric, + {{Suggestion::Text(l10n_util::GetStringFUTF16( + IDS_AUTOFILL_BNPL_CREDIT_CARD_SUGGESTION_LABEL_TWO_ISSUERS, + bnpl_issuers[1].GetDisplayName(), + bnpl_issuers[0].GetDisplayName()))}}), + EqualSuggestionTabIndex(kDefaultSuggestionTabIndex))); // Checks the footer suggestions stayed in the same order after the insertion. EXPECT_THAT(updated_suggestions[current_suggestion_index++], - EqualsSuggestion(SuggestionType::kSeparator)); + AllOf(EqualsSuggestion(SuggestionType::kSeparator), + EqualSuggestionTabIndex(kDefaultSuggestionTabIndex))); EXPECT_THAT(updated_suggestions[current_suggestion_index++], - EqualsSuggestion(SuggestionType::kManageCreditCard)); + AllOf(EqualsSuggestion(SuggestionType::kManageCreditCard), + EqualSuggestionTabIndex(kDefaultSuggestionTabIndex))); EXPECT_EQ(current_suggestion_index, updated_suggestions.size()); } @@ -1761,19 +1773,22 @@ .GetPayload<Suggestion::PaymentsPayload>() .extracted_amount_in_micros, extracted_amount_in_micros); - EXPECT_THAT( - updated_suggestions[current_suggestion_index++], - EqualsSuggestion( - SuggestionType::kBnplEntry, - l10n_util::GetStringUTF16(IDS_AUTOFILL_BNPL_PAY_LATER_OPTIONS_TEXT), - Suggestion::Icon::kBnplGeneric, - {{Suggestion::Text(bnpl_issuer.GetDisplayName())}})); + EXPECT_THAT(updated_suggestions[current_suggestion_index++], + AllOf(EqualsSuggestion( + SuggestionType::kBnplEntry, + l10n_util::GetStringUTF16( + IDS_AUTOFILL_BNPL_PAY_LATER_OPTIONS_TEXT), + Suggestion::Icon::kBnplGeneric, + {{Suggestion::Text(bnpl_issuer.GetDisplayName())}}), + EqualSuggestionTabIndex(kDefaultSuggestionTabIndex))); // Checks the footer suggestions stayed in the same order after the insertion. EXPECT_THAT(updated_suggestions[current_suggestion_index++], - EqualsSuggestion(SuggestionType::kSeparator)); + AllOf(EqualsSuggestion(SuggestionType::kSeparator), + EqualSuggestionTabIndex(kDefaultSuggestionTabIndex))); EXPECT_THAT(updated_suggestions[current_suggestion_index++], - EqualsSuggestion(SuggestionType::kManageCreditCard)); + AllOf(EqualsSuggestion(SuggestionType::kManageCreditCard), + EqualSuggestionTabIndex(kDefaultSuggestionTabIndex))); EXPECT_EQ(current_suggestion_index, updated_suggestions.size()); } @@ -2177,161 +2192,6 @@ &feature_engagement::kIPHAutofillBnplAffirmOrZipSuggestionFeature); } -TEST_F(PaymentsSuggestionGeneratorBnplTest, - GenerateCreditCardOrCvcFieldSuggestionsSync_LinkedIssuer_Affirm) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitWithFeatures( - /*enabled_features=*/{features::kAutofillEnablePayNowPayLaterTabs, - features::kAutofillEnableBuyNowPayLater, - features::kAutofillEnableAmountExtraction, - features::kAutofillEnableAiBasedAmountExtraction}, - /*disabled_features=*/{}); - - payments_data().AddCreditCard(test::GetCreditCard()); - BnplIssuer linked_issuer = - test::GetTestLinkedBnplIssuer(BnplIssuer::IssuerId::kBnplAffirm); - payments_data().AddBnplIssuer(linked_issuer); - - ON_CALL(*static_cast<MockAutofillOptimizationGuideDecider*>( - autofill_client().GetAutofillOptimizationGuideDecider()), - IsUrlEligibleForBnplIssuer) - .WillByDefault(testing::Return(true)); - - FormBundle form_bundle = - GetFormWithTypes({.fields = {{.role = CREDIT_CARD_NUMBER}}}); - - const std::vector<Suggestion> suggestions = GetSuggestionsForCreditCards( - form_bundle.form, *form_bundle.form_structure, form_bundle.trigger_field, - *form_bundle.trigger_autofill_field, autofill_client(), - /*four_digit_combinations_in_dom=*/{}, payments::AmountExtractionStatus(), - credit_card_form_event_logger(), - AutofillMetrics::PaymentsSigninState::kUnknown, - /*exclude_virtual_cards=*/false); - - auto bnpl_it = std::find_if( - suggestions.begin(), suggestions.end(), - [](const Suggestion& s) { return s.type == SuggestionType::kBnplEntry; }); - - ASSERT_NE(bnpl_it, suggestions.end()) - << "Expected a BNPL suggestion to be generated."; - - EXPECT_EQ(bnpl_it->main_text.value, linked_issuer.GetDisplayName()); - EXPECT_EQ(bnpl_it->icon, Suggestion::Icon::kBnplAffirmLinked); - EXPECT_THAT( - bnpl_it->labels, - ElementsAre(std::vector< - Suggestion::Text>{Suggestion::Text(l10n_util::GetStringUTF16( - IDS_AUTOFILL_CARD_BNPL_PAY_LATER_PAYMENT_OPTION_AFFIRM_AND_AFTERPAY))})); - - EXPECT_TRUE(std::holds_alternative<Suggestion::BnplIssuer>(bnpl_it->payload)); - EXPECT_EQ(std::get<Suggestion::BnplIssuer>(bnpl_it->payload).value(), - linked_issuer); -} - -TEST_F(PaymentsSuggestionGeneratorBnplTest, - GenerateCreditCardOrCvcFieldSuggestionsSync_UnlinkedIssuer_Zip) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitWithFeatures( - /*enabled_features=*/{features::kAutofillEnablePayNowPayLaterTabs, - features::kAutofillEnableBuyNowPayLater, - features::kAutofillEnableAmountExtraction, - features::kAutofillEnableAiBasedAmountExtraction}, - /*disabled_features=*/{}); - - payments_data().AddCreditCard(test::GetCreditCard()); - - // `GetTestUnlinkedBnplIssuer()` defaults to Zip. - BnplIssuer unlinked_issuer = test::GetTestUnlinkedBnplIssuer(); - ASSERT_EQ(unlinked_issuer.issuer_id(), BnplIssuer::IssuerId::kBnplZip); - payments_data().AddBnplIssuer(unlinked_issuer); - - ON_CALL(*static_cast<MockAutofillOptimizationGuideDecider*>( - autofill_client().GetAutofillOptimizationGuideDecider()), - IsUrlEligibleForBnplIssuer) - .WillByDefault(testing::Return(true)); - - FormBundle form_bundle = - GetFormWithTypes({.fields = {{.role = CREDIT_CARD_NUMBER}}}); - - const std::vector<Suggestion> suggestions = GetSuggestionsForCreditCards( - form_bundle.form, *form_bundle.form_structure, form_bundle.trigger_field, - *form_bundle.trigger_autofill_field, autofill_client(), - /*four_digit_combinations_in_dom=*/{}, payments::AmountExtractionStatus(), - credit_card_form_event_logger(), - AutofillMetrics::PaymentsSigninState::kUnknown, - /*exclude_virtual_cards=*/false); - - auto bnpl_it = std::find_if( - suggestions.begin(), suggestions.end(), - [](const Suggestion& s) { return s.type == SuggestionType::kBnplEntry; }); - - ASSERT_NE(bnpl_it, suggestions.end()) - << "Expected a BNPL suggestion to be generated."; - - EXPECT_EQ(bnpl_it->main_text.value, unlinked_issuer.GetDisplayName()); - EXPECT_EQ(bnpl_it->icon, Suggestion::Icon::kBnplZipUnlinked); - EXPECT_THAT(bnpl_it->labels, - ElementsAre(std::vector<Suggestion::Text>{ - Suggestion::Text(l10n_util::GetStringUTF16( - IDS_AUTOFILL_CARD_BNPL_PAY_LATER_PAYMENT_OPTION_ZIP))})); - - EXPECT_TRUE(std::holds_alternative<Suggestion::BnplIssuer>(bnpl_it->payload)); - EXPECT_EQ(std::get<Suggestion::BnplIssuer>(bnpl_it->payload).value(), - unlinked_issuer); -} - -TEST_F(PaymentsSuggestionGeneratorBnplTest, - GenerateCreditCardOrCvcFieldSuggestionsSync_LinkedIssuer_Klarna) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitWithFeatures( - /*enabled_features=*/{features::kAutofillEnablePayNowPayLaterTabs, - features::kAutofillEnableBuyNowPayLater, - features::kAutofillEnableBuyNowPayLaterForKlarna, - features::kAutofillEnableAmountExtraction, - features::kAutofillEnableAiBasedAmountExtraction}, - /*disabled_features=*/{}); - - payments_data().AddCreditCard(test::GetCreditCard()); - BnplIssuer linked_issuer = - test::GetTestLinkedBnplIssuer(BnplIssuer::IssuerId::kBnplKlarna); - payments_data().AddBnplIssuer(linked_issuer); - - ON_CALL(*static_cast<MockAutofillOptimizationGuideDecider*>( - autofill_client().GetAutofillOptimizationGuideDecider()), - IsUrlEligibleForBnplIssuer) - .WillByDefault(testing::Return(true)); - - FormBundle form_bundle = - GetFormWithTypes({.fields = {{.role = CREDIT_CARD_NUMBER}}}); - - const std::vector<Suggestion> suggestions = GetSuggestionsForCreditCards( - form_bundle.form, *form_bundle.form_structure, form_bundle.trigger_field, - *form_bundle.trigger_autofill_field, autofill_client(), - /*four_digit_combinations_in_dom=*/{}, payments::AmountExtractionStatus(), - credit_card_form_event_logger(), - AutofillMetrics::PaymentsSigninState::kUnknown, - /*exclude_virtual_cards=*/false); - - auto bnpl_it = std::find_if( - suggestions.begin(), suggestions.end(), - [](const Suggestion& s) { return s.type == SuggestionType::kBnplEntry; }); - - ASSERT_NE(bnpl_it, suggestions.end()) - << "Expected a BNPL suggestion to be generated."; - - EXPECT_EQ(bnpl_it->main_text.value, linked_issuer.GetDisplayName()); - EXPECT_EQ(bnpl_it->icon, Suggestion::Icon::kBnplKlarnaLinked); - EXPECT_THAT( - bnpl_it->labels, - ElementsAre(std::vector<Suggestion::Text>{ - Suggestion::Text(l10n_util::GetStringUTF16( - IDS_AUTOFILL_CARD_BNPL_PAY_LATER_PAYMENT_OPTION_KLARNA))})); - - EXPECT_TRUE(std::holds_alternative<Suggestion::BnplIssuer>(bnpl_it->payload)); - EXPECT_EQ(std::get<Suggestion::BnplIssuer>(bnpl_it->payload).value(), - linked_issuer); -} - TEST_F( PaymentsSuggestionGeneratorBnplTest, GenerateCreditCardOrCvcFieldSuggestionsSync_CardNumberFieldNotEmpty_PayLaterIssuerDisabled) { @@ -2386,6 +2246,7 @@ EXPECT_EQ(std::get<Suggestion::BnplIssuer>(disabled_bnpl_suggestion->payload) .value(), linked_issuer); + EXPECT_EQ(disabled_bnpl_suggestion->tab_index, kPayLaterSuggestionTabIndex); } TEST_F( @@ -2424,10 +2285,18 @@ ASSERT_EQ(suggestions.size(), 7U); - EXPECT_EQ(suggestions[0].type, SuggestionType::kCreditCardEntry); - EXPECT_EQ(suggestions[1].type, SuggestionType::kBnplEntry); - EXPECT_EQ(suggestions[2].type, SuggestionType::kBnplEntry); - EXPECT_EQ(suggestions[3].type, SuggestionType::kBnplEntry); + EXPECT_THAT(suggestions[0], + AllOf(EqualsSuggestion(SuggestionType::kCreditCardEntry), + EqualSuggestionTabIndex(kDefaultSuggestionTabIndex))); + EXPECT_THAT(suggestions[1], + AllOf(EqualsSuggestion(SuggestionType::kBnplEntry), + EqualSuggestionTabIndex(kPayLaterSuggestionTabIndex))); + EXPECT_THAT(suggestions[2], + AllOf(EqualsSuggestion(SuggestionType::kBnplEntry), + EqualSuggestionTabIndex(kPayLaterSuggestionTabIndex))); + EXPECT_THAT(suggestions[3], + AllOf(EqualsSuggestion(SuggestionType::kBnplEntry), + EqualSuggestionTabIndex(kPayLaterSuggestionTabIndex))); EXPECT_THAT(suggestions, ContainsCreditCardFooterSuggestions(/*with_gpay_logo=*/false, /*with_bnpl_footnote=*/true)); @@ -2481,6 +2350,7 @@ EXPECT_EQ(loading_throbber_finder->acceptability, Suggestion::Acceptability::kUnacceptable); + EXPECT_EQ(loading_throbber_finder->tab_index, kPayLaterSuggestionTabIndex); // 3 BNPL issuers were added. EXPECT_EQ(loading_throbber_finder->expected_number_of_suggestions, 3u); @@ -2525,11 +2395,12 @@ /*exclude_virtual_cards=*/false); ASSERT_EQ(suggestions.size(), 5U); - EXPECT_EQ(suggestions[0].type, SuggestionType::kCreditCardEntry); - EXPECT_EQ(suggestions[1].type, SuggestionType::kSeparator); - EXPECT_EQ(suggestions[2].type, SuggestionType::kBnplEntry); - EXPECT_EQ(suggestions[3].type, SuggestionType::kSeparator); - EXPECT_EQ(suggestions[4].type, SuggestionType::kManageCreditCard); + EXPECT_THAT(suggestions, + ElementsAre(EqualsSuggestion(SuggestionType::kCreditCardEntry), + EqualsSuggestion(SuggestionType::kSeparator), + EqualsSuggestion(SuggestionType::kBnplEntry), + EqualsSuggestion(SuggestionType::kSeparator), + EqualsSuggestion(SuggestionType::kManageCreditCard))); } TEST_F( @@ -2572,6 +2443,7 @@ EXPECT_EQ(bnpl_footnote->acceptability, Suggestion::Acceptability::kUnacceptable); + EXPECT_EQ(bnpl_footnote->tab_index, kPayLaterSuggestionTabIndex); } TEST_F( @@ -2608,6 +2480,90 @@ return s.type == SuggestionType::kBnplFootnote; })); } + +// Params of PaymentsSuggestionGeneratorPnplTabTestForIssuer: +// -- BnplIssuer::IssuerId IssuerId: The Buy Now Pay Later issuer which the +// suggestion is generated for. +// -- int ExpectedLabelTextId: The id of the expected text that should be +// displayed in the suggestion label. +class PaymentsSuggestionGeneratorPnplTabTestForIssuer + : public PaymentsSuggestionGeneratorTest, + public testing::WithParamInterface< + std::tuple<BnplIssuer::IssuerId, int>> { + public: + BnplIssuer::IssuerId IssuerId() { return std::get<0>(GetParam()); } + Suggestion::Text ExpectedLabelText() { + return Suggestion::Text(l10n_util::GetStringUTF16(std::get<1>(GetParam()))); + } + + void SetUp() override { + PaymentsSuggestionGeneratorTest::SetUp(); + scoped_feature_list_.InitWithFeatures( + /*enabled_features=*/{features::kAutofillEnablePayNowPayLaterTabs, + features::kAutofillEnableBuyNowPayLater, + features::kAutofillEnableBuyNowPayLaterForKlarna, + features::kAutofillEnableAmountExtraction, + features::kAutofillEnableAiBasedAmountExtraction}, + /*disabled_features=*/{}); + autofill_client().GetPrefs()->SetBoolean( + prefs::kAutofillAmountExtractionAiTermsSeen, false); + } + + private: + base::test::ScopedFeatureList scoped_feature_list_; +}; + +INSTANTIATE_TEST_SUITE_P( + All, + PaymentsSuggestionGeneratorPnplTabTestForIssuer, + testing::Values( + std::make_tuple( + BnplIssuer::IssuerId::kBnplAffirm, + IDS_AUTOFILL_CARD_BNPL_PAY_LATER_PAYMENT_OPTION_AFFIRM_AND_AFTERPAY), + std::make_tuple(BnplIssuer::IssuerId::kBnplZip, + IDS_AUTOFILL_CARD_BNPL_PAY_LATER_PAYMENT_OPTION_ZIP), + std::make_tuple( + BnplIssuer::IssuerId::kBnplKlarna, + IDS_AUTOFILL_CARD_BNPL_PAY_LATER_PAYMENT_OPTION_KLARNA))); + +TEST_P(PaymentsSuggestionGeneratorPnplTabTestForIssuer, + GenerateCreditCardOrCvcFieldSuggestionsSync_LinkedIssuer) { + payments_data().AddCreditCard(test::GetCreditCard()); + BnplIssuer issuer = test::GetTestLinkedBnplIssuer(IssuerId()); + payments_data().AddBnplIssuer(issuer); + + ON_CALL(*static_cast<MockAutofillOptimizationGuideDecider*>( + autofill_client().GetAutofillOptimizationGuideDecider()), + IsUrlEligibleForBnplIssuer) + .WillByDefault(testing::Return(true)); + + FormBundle form_bundle = + GetFormWithTypes({.fields = {{.role = CREDIT_CARD_NUMBER}}}); + + const std::vector<Suggestion> suggestions = GetSuggestionsForCreditCards( + form_bundle.form, *form_bundle.form_structure, form_bundle.trigger_field, + *form_bundle.trigger_autofill_field, autofill_client(), + /*four_digit_combinations_in_dom=*/{}, payments::AmountExtractionStatus(), + credit_card_form_event_logger(), + AutofillMetrics::PaymentsSigninState::kUnknown, + /*exclude_virtual_cards=*/false); + + auto bnpl_it = std::find_if( + suggestions.begin(), suggestions.end(), + [](const Suggestion& s) { return s.type == SuggestionType::kBnplEntry; }); + + ASSERT_NE(bnpl_it, suggestions.end()) + << "Expected a BNPL suggestion to be generated."; + + EXPECT_EQ(bnpl_it->main_text.value, issuer.GetDisplayName()); + EXPECT_EQ(bnpl_it->icon, + payments::GetBnplSuggestionIcon(IssuerId(), /*is_linked=*/true)); + EXPECT_THAT(bnpl_it->labels, + ElementsAre(std::vector<Suggestion::Text>{ExpectedLabelText()})); + EXPECT_TRUE(std::holds_alternative<Suggestion::BnplIssuer>(bnpl_it->payload)); + EXPECT_EQ(std::get<Suggestion::BnplIssuer>(bnpl_it->payload).value(), issuer); + EXPECT_EQ(bnpl_it->tab_index, kPayLaterSuggestionTabIndex); +} #endif // !BUILDFLAG(IS_ANDROID) // Ensures that `GetBnplPriceLowerBound()` returns the minimum lower price
diff --git a/components/autofill/core/browser/suggestions/payments/payments_suggestion_generator_util.cc b/components/autofill/core/browser/suggestions/payments/payments_suggestion_generator_util.cc index d1cdc19..907cbde 100644 --- a/components/autofill/core/browser/suggestions/payments/payments_suggestion_generator_util.cc +++ b/components/autofill/core/browser/suggestions/payments/payments_suggestion_generator_util.cc
@@ -1023,6 +1023,8 @@ Suggestion CreateBnplFootnoteSuggestion() { Suggestion bnpl_footnote = Suggestion(SuggestionType::kBnplFootnote); bnpl_footnote.acceptability = Suggestion::Acceptability::kUnacceptable; + bnpl_footnote.tab_index = kPayLaterSuggestionTabIndex; + return bnpl_footnote; }
diff --git a/components/autofill/core/browser/suggestions/suggestion.h b/components/autofill/core/browser/suggestions/suggestion.h index 28ed862f..bcbaf6d5 100644 --- a/components/autofill/core/browser/suggestions/suggestion.h +++ b/components/autofill/core/browser/suggestions/suggestion.h
@@ -22,6 +22,7 @@ #include "components/autofill/core/browser/field_types.h" #include "components/autofill/core/browser/suggestions/suggestion_type.h" #include "components/autofill/core/browser/webdata/autocomplete/autocomplete_entry.h" +#include "components/autofill/core/common/autofill_payments_features.h" #include "components/autofill/core/common/unique_ids.h" #include "ui/gfx/image/image.h" #include "url/gurl.h" @@ -218,6 +219,7 @@ using IsLoading = base::StrongAlias<class IsLoadingTag, bool>; using InstrumentId = base::StrongAlias<class InstrumentIdTag, uint64_t>; + // TODO(crbug.com/477689220): Directly use BnplIssuer and remove the alias. using BnplIssuer = base::StrongAlias<class BnplIssuerTag, BnplIssuer>; using Payload = std::variant<Guid, InstrumentId, @@ -478,8 +480,11 @@ return std::holds_alternative<Guid>(payload) || std::holds_alternative<PaymentsPayload>(payload); case SuggestionType::kBnplEntry: - return std::holds_alternative<PaymentsPayload>(payload) || - std::holds_alternative<BnplIssuer>(payload); + if (base::FeatureList::IsEnabled( + features::kAutofillEnablePayNowPayLaterTabs)) { + return std::holds_alternative<BnplIssuer>(payload); + } + return std::holds_alternative<PaymentsPayload>(payload); case SuggestionType::kAtMemorySearchResult: return std::holds_alternative<AtMemoryPayload>(payload); case SuggestionType::kDevtoolsTestAddressEntry:
diff --git a/components/autofill/core/browser/ui/autofill_external_delegate.cc b/components/autofill/core/browser/ui/autofill_external_delegate.cc index 62cedca..5450b460 100644 --- a/components/autofill/core/browser/ui/autofill_external_delegate.cc +++ b/components/autofill/core/browser/ui/autofill_external_delegate.cc
@@ -874,7 +874,15 @@ case SuggestionType::kBnplFootnote: NOTREACHED(); // Should be handled elsewhere. } - // Note that some suggestion types return early. + + if (suggestion.type == SuggestionType::kBnplEntry && + base::FeatureList::IsEnabled( + features::kAutofillEnablePayNowPayLaterTabs)) { + // Return early to prevent the popup from hiding. Popup will instead be + // closed by `BnplManager`. + return; + } + manager_->client().HideAutofillSuggestions( SuggestionHidingReason::kAcceptSuggestion); } @@ -992,6 +1000,22 @@ SuggestionHidingReason::kEndEditing); } +void AutofillExternalDelegate::OnPayLaterTabOpened() { + manager_->GetPaymentsBnplManager()->OnUserDecisionToUseBnpl( + std::nullopt, base::BindOnce( + [](base::WeakPtr<AutofillExternalDelegate> delegate, + const CreditCard& card) { + if (delegate) { + delegate->manager_->FillOrPreviewForm( + mojom::ActionPersistence::kFill, + delegate->query_form_, + delegate->query_field_.global_id(), &card, + AutofillTriggerSource::kPopup); + } + }, + GetWeakPtr())); +} + void AutofillExternalDelegate::ClearPreviewedForm() { manager_->driver().RendererShouldClearPreviewedForm(); } @@ -1320,12 +1344,18 @@ payments::BnplManager* bnpl_manager = manager_->GetPaymentsBnplManager(); CHECK(bnpl_manager); - bnpl_manager->OnUserDecisionToUseBnpl( - /*final_checkout_amount=*/suggestion - .GetPayload<Suggestion::PaymentsPayload>() - .extracted_amount_in_micros, - base::BindOnce(&AutofillExternalDelegate::FillFetchedCreditCard, - GetWeakPtr(), AutofillTriggerSource::kPopup)); + if (base::FeatureList::IsEnabled( + features::kAutofillEnablePayNowPayLaterTabs)) { + bnpl_manager->OnIssuerAccepted( + /*issuer=*/suggestion.GetPayload<Suggestion::BnplIssuer>().value()); + } else { + bnpl_manager->OnUserDecisionToUseBnpl( + /*final_checkout_amount=*/suggestion + .GetPayload<Suggestion::PaymentsPayload>() + .extracted_amount_in_micros, + base::BindOnce(&AutofillExternalDelegate::FillFetchedCreditCard, + GetWeakPtr(), AutofillTriggerSource::kPopup)); + } break; } default:
diff --git a/components/autofill/core/browser/ui/autofill_external_delegate.h b/components/autofill/core/browser/ui/autofill_external_delegate.h index 0ad7bf1..c94b7c7 100644 --- a/components/autofill/core/browser/ui/autofill_external_delegate.h +++ b/components/autofill/core/browser/ui/autofill_external_delegate.h
@@ -122,6 +122,9 @@ // used to help record the metrics of when a new popup is shown. void DidEndTextFieldEditing(); + // Triggered when the pay later tab is opened in the autofill dropdown. + void OnPayLaterTabOpened(); + const FormData& query_form() const { return query_form_; } void AttemptToDisplayAutofillSuggestionsForTest(
diff --git a/components/autofill/core/browser/ui/autofill_external_delegate_unittest.cc b/components/autofill/core/browser/ui/autofill_external_delegate_unittest.cc index 90f59de..7aec99e 100644 --- a/components/autofill/core/browser/ui/autofill_external_delegate_unittest.cc +++ b/components/autofill/core/browser/ui/autofill_external_delegate_unittest.cc
@@ -863,6 +863,57 @@ {}); } +// Tests that accepting a BNPL entry when PayNowPayLater tabs are enabled +// delegates to `BnplManager::OnIssuerAccepted` and does not hide the +// suggestions popup immediately. +TEST_F(AutofillExternalDelegateTest, + AcceptedBnplEntry_PayNowPayLaterEnabled_CallsOnIssuerAccepted) { + base::test::ScopedFeatureList scoped_feature_list{ + features::kAutofillEnablePayNowPayLaterTabs}; + + IssueOnQuery(); + + Suggestion suggestion(SuggestionType::kBnplEntry); + BnplIssuer test_issuer = test::GetTestLinkedBnplIssuer(); + suggestion.payload = Suggestion::BnplIssuer(test_issuer); + + EXPECT_CALL(*autofill_manager().GetPaymentsBnplManager(), + OnIssuerAccepted(test_issuer)); + + EXPECT_CALL(autofill_client(), HideAutofillSuggestions).Times(0); + + external_delegate().DidAcceptSuggestion(suggestion, + SuggestionPosition{.row = 0}); +} + +// Tests that accepting a BNPL entry when PayNowPayLater tabs are disabled +// delegates to `BnplManager::OnUserDecisionToUseBnpl` and hides the suggestions +// popup. +TEST_F(AutofillExternalDelegateTest, + AcceptedBnplEntry_PayNowPayLaterEnabled_CallsOnUserDecisionToUseBnpl) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndDisableFeature( + features::kAutofillEnablePayNowPayLaterTabs); + + IssueOnQuery(); + + const std::optional<int64_t> expected_amount = 50'000'000; + EXPECT_CALL(*autofill_manager().GetPaymentsBnplManager(), + OnUserDecisionToUseBnpl(expected_amount, _)); + EXPECT_CALL( + autofill_client(), + HideAutofillSuggestions(SuggestionHidingReason::kAcceptSuggestion)); + + Suggestion::PaymentsPayload payments_payload; + payments_payload.extracted_amount_in_micros = expected_amount; + Suggestion suggestion = CreateAutofillSuggestion( + SuggestionType::kBnplEntry, /*main_text_value=*/u"BNPL suggestion", + payments_payload); + + external_delegate().DidAcceptSuggestion(suggestion, + SuggestionPosition{.row = 0}); +} + // Tests that `show_tabbed_popup` is false when the main filling // product is not a credit card (e.g., an Address field). TEST_F(AutofillExternalDelegateTest, ShowTabbedPopup_NotCreditCard) { @@ -1021,6 +1072,49 @@ OnSuggestionsReturned(queried_field().global_id(), {Suggestion(SuggestionType::kCreditCardEntry)}); } + +// Ensures the BNPL Manager is notified of the user deciding to use BNPL when a +// pay later tab is opened. +TEST_F(AutofillExternalDelegateTest, OnPayLaterTabOpened) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitWithFeatures( + /*enabled_features=*/{features::kAutofillEnableAmountExtraction, + features::kAutofillEnableBuyNowPayLaterSyncing, + features::kAutofillEnableBuyNowPayLater, + features::kAutofillEnableAiBasedAmountExtraction, + features::kAutofillEnablePayNowPayLaterTabs}, + /*disabled_features=*/{}); + + base::OnceCallback<void(const CreditCard&)> captured_fill_callback; + EXPECT_CALL(*autofill_manager().GetPaymentsBnplManager(), + OnUserDecisionToUseBnpl( + /*final_checkout_amount=*/testing::Eq(std::nullopt), + /*on_bnpl_vcn_fetched_callback=*/testing::_)) + .Times(1) + .WillOnce([&](std::optional<long>, + base::OnceCallback<void(const CreditCard&)> callback) { + captured_fill_callback = std::move(callback); + }); + + external_delegate().OnPayLaterTabOpened(); + + ASSERT_FALSE(captured_fill_callback.is_null()); + + CreditCard test_card = test::GetCreditCard(); + + EXPECT_CALL( + autofill_manager(), + FillOrPreviewForm( + /*action_persistence=*/mojom::ActionPersistence::kFill, + /*form=*/testing::_, + /*field_id=*/testing::_, + /*filling_payload=*/ + testing::VariantWith<const CreditCard*>(testing::Eq(&test_card)), + /*trigger_source=*/testing::_)) + .Times(1); + + std::move(captured_fill_callback).Run(test_card); +} #endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || // BUILDFLAG(IS_CHROMEOS)
diff --git a/components/autofill/ios/form_util/resources/fill_util.ts b/components/autofill/ios/form_util/resources/fill_util.ts index 8f5805cb..14d334b65 100644 --- a/components/autofill/ios/form_util/resources/fill_util.ts +++ b/components/autofill/ios/form_util/resources/fill_util.ts
@@ -23,6 +23,9 @@ // TODO(crbug.com/469457516): Update the variables in the classes to follow the // naming convention. /* eslint-disable @typescript-eslint/naming-convention */ + +// TODO(crbug.com/493624186): Fix members asserted as non-null . +/* eslint-disable no-restricted-syntax */ export class AutofillFormFieldData extends JsonSafeObject { name!: string; value!: string; @@ -61,6 +64,7 @@ name_attribute?: string; id_attribute?: string; } +/* eslint-enable no-restricted-syntax */ /* eslint-enable @typescript-eslint/naming-convention */ export declare interface FrameTokenWithPredecessor {
diff --git a/components/collaboration/internal/android/java/src/org/chromium/components/collaboration/comments/CommentsServiceBridge.java b/components/collaboration/internal/android/java/src/org/chromium/components/collaboration/comments/CommentsServiceBridge.java index 06bc4a6..e94eea5 100644 --- a/components/collaboration/internal/android/java/src/org/chromium/components/collaboration/comments/CommentsServiceBridge.java +++ b/components/collaboration/internal/android/java/src/org/chromium/components/collaboration/comments/CommentsServiceBridge.java
@@ -54,32 +54,26 @@ String content, @Nullable UUID parentCommentId, Callback<Boolean> successCallback) { - String uuidString = - CommentsServiceBridgeJni.get() - .addComment( - mNativeCommentsServiceBridge, - collaborationId, - url, - content, - parentCommentId == null ? null : parentCommentId.toString(), - successCallback); - return UUID.fromString(uuidString); + return CommentsServiceBridgeJni.get() + .addComment( + mNativeCommentsServiceBridge, + collaborationId, + url, + content, + parentCommentId, + successCallback); } @Override public void editComment(UUID commentId, String newContent, Callback<Boolean> successCallback) { CommentsServiceBridgeJni.get() - .editComment( - mNativeCommentsServiceBridge, - commentId.toString(), - newContent, - successCallback); + .editComment(mNativeCommentsServiceBridge, commentId, newContent, successCallback); } @Override public void deleteComment(UUID commentId, Callback<Boolean> successCallback) { CommentsServiceBridgeJni.get() - .deleteComment(mNativeCommentsServiceBridge, commentId.toString(), successCallback); + .deleteComment(mNativeCommentsServiceBridge, commentId, successCallback); } @Override @@ -112,23 +106,23 @@ boolean isEmptyService(long nativeCommentsServiceBridge); @JniType("base::Uuid") - String addComment( + UUID addComment( long nativeCommentsServiceBridge, @JniType("std::string") String collaborationId, @JniType("GURL") GURL url, @JniType("std::string") String content, - @JniType("std::optional<base::Uuid>") @Nullable String parentCommentId, + @JniType("std::optional<base::Uuid>") @Nullable UUID parentCommentId, Callback<Boolean> successCallback); void editComment( long nativeCommentsServiceBridge, - @JniType("base::Uuid") String commentId, + @JniType("base::Uuid") UUID commentId, @JniType("std::string") String newContent, Callback<Boolean> successCallback); void deleteComment( long nativeCommentsServiceBridge, - @JniType("base::Uuid") String commentId, + @JniType("base::Uuid") UUID commentId, Callback<Boolean> successCallback); void queryComments(
diff --git a/components/collaboration/internal/android/java/src/org/chromium/components/collaboration/messaging/MessagingBackendServiceBridge.java b/components/collaboration/internal/android/java/src/org/chromium/components/collaboration/messaging/MessagingBackendServiceBridge.java index 07f92567..1a4ab7f 100644 --- a/components/collaboration/internal/android/java/src/org/chromium/components/collaboration/messaging/MessagingBackendServiceBridge.java +++ b/components/collaboration/internal/android/java/src/org/chromium/components/collaboration/messaging/MessagingBackendServiceBridge.java
@@ -207,13 +207,13 @@ List<PersistentMessage> getMessagesForTab( long nativeMessagingBackendServiceBridge, int localTabId, - @JniType("std::optional<base::Uuid>") @Nullable String syncTabId, + @JniType("std::optional<std::string>") @Nullable String syncTabId, @PersistentNotificationType int type); List<PersistentMessage> getMessagesForGroup( long nativeMessagingBackendServiceBridge, @Nullable LocalTabGroupId localGroupId, - @JniType("std::optional<base::Uuid>") @Nullable String syncGroupId, + @JniType("std::optional<std::string>") @Nullable String syncGroupId, @PersistentNotificationType int type); List<PersistentMessage> getMessages( @@ -232,7 +232,7 @@ void clearPersistentMessage( long nativeMessagingBackendServiceBridge, - @JniType("base::Uuid") String messageId, + @JniType("std::string") String messageId, @PersistentNotificationType int type); } }
diff --git a/components/collaboration/internal/android/messaging/messaging_backend_service_bridge.cc b/components/collaboration/internal/android/messaging/messaging_backend_service_bridge.cc index a77b89b..19d46232 100644 --- a/components/collaboration/internal/android/messaging/messaging_backend_service_bridge.cc +++ b/components/collaboration/internal/android/messaging/messaging_backend_service_bridge.cc
@@ -87,19 +87,20 @@ MessagingBackendServiceBridge::GetMessagesForTab( JNIEnv* env, int32_t j_local_tab_id, - const std::optional<base::Uuid>& sync_tab_id, + const std::optional<std::string>& sync_tab_id_str, int32_t j_type) { auto type = static_cast<PersistentNotificationType>(j_type); if (j_local_tab_id != kInvalidTabId) { - CHECK(!sync_tab_id); + CHECK(!sync_tab_id_str); tab_groups::LocalTabID tab_id = tab_groups::FromJavaTabId(j_local_tab_id); auto messages = service_->GetMessagesForTab(tab_id, type); return PersistentMessagesToJava(env, messages); } - if (sync_tab_id) { + if (sync_tab_id_str) { CHECK(j_local_tab_id == kInvalidTabId); - auto messages = service_->GetMessagesForTab(*sync_tab_id, type); + base::Uuid sync_tab_id = base::Uuid::ParseLowercase(*sync_tab_id_str); + auto messages = service_->GetMessagesForTab(sync_tab_id, type); return PersistentMessagesToJava(env, messages); } @@ -110,21 +111,22 @@ MessagingBackendServiceBridge::GetMessagesForGroup( JNIEnv* env, const base::android::JavaRef<jobject>& j_local_group_id, - const std::optional<base::Uuid>& sync_group_id, + const std::optional<std::string>& sync_group_id_str, int32_t j_type) { auto type = static_cast<PersistentNotificationType>(j_type); if (j_local_group_id) { - CHECK(!sync_group_id); + CHECK(!sync_group_id_str); auto group_id = tab_groups::TabGroupSyncConversionsBridge::FromJavaTabGroupId( env, j_local_group_id); auto messages = service_->GetMessagesForGroup(group_id, type); return PersistentMessagesToJava(env, messages); } - if (sync_group_id) { + if (sync_group_id_str) { CHECK(!j_local_group_id); - auto messages = service_->GetMessagesForGroup(*sync_group_id, type); + base::Uuid sync_group_id = base::Uuid::ParseLowercase(*sync_group_id_str); + auto messages = service_->GetMessagesForGroup(sync_group_id, type); return PersistentMessagesToJava(env, messages); } @@ -157,10 +159,11 @@ void MessagingBackendServiceBridge::ClearPersistentMessage( JNIEnv* env, - const base::Uuid& message_id, + const std::string& message_id_str, int32_t j_type) { auto type = static_cast<PersistentNotificationType>(j_type); - service_->ClearPersistentMessage(message_id, type); + service_->ClearPersistentMessage(base::Uuid::ParseLowercase(message_id_str), + type); } void MessagingBackendServiceBridge::RunInstantaneousMessageSuccessCallback(
diff --git a/components/collaboration/internal/android/messaging/messaging_backend_service_bridge.h b/components/collaboration/internal/android/messaging/messaging_backend_service_bridge.h index e70b5498..e1a80c4e 100644 --- a/components/collaboration/internal/android/messaging/messaging_backend_service_bridge.h +++ b/components/collaboration/internal/android/messaging/messaging_backend_service_bridge.h
@@ -48,12 +48,12 @@ base::android::ScopedJavaLocalRef<jobject> GetMessagesForTab( JNIEnv* env, int32_t j_local_tab_id, - const std::optional<base::Uuid>& sync_tab_id, + const std::optional<std::string>& sync_tab_id, int32_t j_type); base::android::ScopedJavaLocalRef<jobject> GetMessagesForGroup( JNIEnv* env, const base::android::JavaRef<jobject>& j_local_group_id, - const std::optional<base::Uuid>& sync_group_id, + const std::optional<std::string>& sync_group_id, int32_t j_type); base::android::ScopedJavaLocalRef<jobject> GetMessages(JNIEnv* env, int32_t j_type); @@ -63,7 +63,7 @@ void ClearDirtyTabMessagesForGroup(JNIEnv* env, const std::string& collaboration_id); void ClearPersistentMessage(JNIEnv* env, - const base::Uuid& message_id, + const std::string& message_id, int32_t j_type); void RunInstantaneousMessageSuccessCallback(JNIEnv* env,
diff --git a/components/contextual_search/android/java/src/org/chromium/components/contextual_search/InputState.java b/components/contextual_search/android/java/src/org/chromium/components/contextual_search/InputState.java index 5d8b679..b7055015 100644 --- a/components/contextual_search/android/java/src/org/chromium/components/contextual_search/InputState.java +++ b/components/contextual_search/android/java/src/org/chromium/components/contextual_search/InputState.java
@@ -17,6 +17,7 @@ import org.chromium.components.omnibox.ModelConfigProto.ModelConfig; import org.chromium.components.omnibox.SectionConfigProto.SectionConfig; import org.chromium.components.omnibox.ToolConfigProto.ToolConfig; +import org.chromium.components.omnibox.ToolModeProto.ToolMode; import java.util.ArrayList; import java.util.Collections; @@ -169,7 +170,20 @@ * @return Whether the tool should be enabled in the UI. */ public boolean isToolEnabled(int toolMode) { - return activeTool == toolMode || !disabledTools.contains(toolMode); + return activeTool == toolMode + || (allowedTools.contains(toolMode) && !disabledTools.contains(toolMode)); + } + + /** Returns whether the image gen tool should be visible, by checking both tool modes. */ + public boolean isImageGenToolVisible() { + return isToolVisible(ToolMode.TOOL_MODE_IMAGE_GEN_VALUE) + || isToolVisible(ToolMode.TOOL_MODE_IMAGE_GEN_UPLOAD_VALUE); + } + + /** Returns whether the image gen tool should be enabled, by checking both tool modes. */ + public boolean isImageGenToolEnabled() { + return isToolEnabled(ToolMode.TOOL_MODE_IMAGE_GEN_VALUE) + || isToolEnabled(ToolMode.TOOL_MODE_IMAGE_GEN_UPLOAD_VALUE); } /** @@ -185,7 +199,8 @@ * @return Whether the model should be enabled in the UI. */ public boolean isModelEnabled(int modelMode) { - return activeModel == modelMode || !disabledModels.contains(modelMode); + return activeModel == modelMode + || (allowedModels.contains(modelMode) && !disabledModels.contains(modelMode)); } private static List<Integer> toList(int @Nullable [] array) {
diff --git a/components/contextual_search/android/java/src/org/chromium/components/contextual_search/InputStateTest.java b/components/contextual_search/android/java/src/org/chromium/components/contextual_search/InputStateTest.java index 5f95741..af0927e4 100644 --- a/components/contextual_search/android/java/src/org/chromium/components/contextual_search/InputStateTest.java +++ b/components/contextual_search/android/java/src/org/chromium/components/contextual_search/InputStateTest.java
@@ -93,7 +93,7 @@ assertFalse(state.isToolEnabled(ToolMode.TOOL_MODE_DEEP_SEARCH_VALUE)); assertFalse(state.isToolVisible(ToolMode.TOOL_MODE_CANVAS_VALUE)); - assertTrue(state.isToolEnabled(ToolMode.TOOL_MODE_CANVAS_VALUE)); + assertFalse(state.isToolEnabled(ToolMode.TOOL_MODE_CANVAS_VALUE)); assertTrue(state.isModelVisible(ModelMode.MODEL_MODE_GEMINI_PRO_VALUE)); assertTrue(state.isModelEnabled(ModelMode.MODEL_MODE_GEMINI_PRO_VALUE)); @@ -102,6 +102,76 @@ assertFalse(state.isModelEnabled(ModelMode.MODEL_MODE_GEMINI_REGULAR_VALUE)); assertFalse(state.isModelVisible(ModelMode.MODEL_MODE_GEMINI_PRO_AUTOROUTE_VALUE)); - assertTrue(state.isModelEnabled(ModelMode.MODEL_MODE_GEMINI_PRO_AUTOROUTE_VALUE)); + assertFalse(state.isModelEnabled(ModelMode.MODEL_MODE_GEMINI_PRO_AUTOROUTE_VALUE)); + } + + @Test + public void testIsToolEnabled() { + InputState activeAllowedDisabled = + new InputState.Builder() + .withActiveTool(ToolMode.TOOL_MODE_IMAGE_GEN_VALUE) + .withAllowedTools(ToolMode.TOOL_MODE_IMAGE_GEN_VALUE) + .withDisabledTools(ToolMode.TOOL_MODE_IMAGE_GEN_VALUE) + .build(); + assertTrue(activeAllowedDisabled.isToolEnabled(ToolMode.TOOL_MODE_IMAGE_GEN_VALUE)); + + InputState activeNotAllowedDisabled = + new InputState.Builder() + .withActiveTool(ToolMode.TOOL_MODE_IMAGE_GEN_VALUE) + .withDisabledTools(ToolMode.TOOL_MODE_IMAGE_GEN_VALUE) + .build(); + assertTrue(activeNotAllowedDisabled.isToolEnabled(ToolMode.TOOL_MODE_IMAGE_GEN_VALUE)); + + InputState allowedNotDisabled = + new InputState.Builder() + .withAllowedTools(ToolMode.TOOL_MODE_IMAGE_GEN_VALUE) + .build(); + assertTrue(allowedNotDisabled.isToolEnabled(ToolMode.TOOL_MODE_IMAGE_GEN_VALUE)); + + InputState allowedDisabled = + new InputState.Builder() + .withAllowedTools(ToolMode.TOOL_MODE_IMAGE_GEN_VALUE) + .withDisabledTools(ToolMode.TOOL_MODE_IMAGE_GEN_VALUE) + .build(); + assertFalse(allowedDisabled.isToolEnabled(ToolMode.TOOL_MODE_IMAGE_GEN_VALUE)); + + InputState notAllowedNotDisabled = new InputState.Builder().build(); + assertFalse(notAllowedNotDisabled.isToolEnabled(ToolMode.TOOL_MODE_IMAGE_GEN_VALUE)); + } + + @Test + public void testEitherImageGenToolVisibilityAndEnablement() { + InputState state = + new InputState.Builder() + .withActiveTool(ToolMode.TOOL_MODE_IMAGE_GEN_VALUE) + .withAllowedTools(ToolMode.TOOL_MODE_IMAGE_GEN_UPLOAD_VALUE) + .withDisabledTools(ToolMode.TOOL_MODE_IMAGE_GEN_UPLOAD_VALUE) + .build(); + + assertTrue(state.isImageGenToolVisible()); + assertTrue(state.isImageGenToolEnabled()); + + InputState stateOnlyUploadAllowed = + new InputState.Builder() + .withAllowedTools(ToolMode.TOOL_MODE_IMAGE_GEN_UPLOAD_VALUE) + .build(); + assertTrue(stateOnlyUploadAllowed.isImageGenToolVisible()); + assertTrue(stateOnlyUploadAllowed.isImageGenToolEnabled()); + + InputState stateNeitherVisible = new InputState.Builder().build(); + assertFalse(stateNeitherVisible.isImageGenToolVisible()); + assertFalse(stateNeitherVisible.isImageGenToolEnabled()); + + InputState stateBothDisabled = + new InputState.Builder() + .withAllowedTools( + ToolMode.TOOL_MODE_IMAGE_GEN_VALUE, + ToolMode.TOOL_MODE_IMAGE_GEN_UPLOAD_VALUE) + .withDisabledTools( + ToolMode.TOOL_MODE_IMAGE_GEN_VALUE, + ToolMode.TOOL_MODE_IMAGE_GEN_UPLOAD_VALUE) + .build(); + assertTrue(stateBothDisabled.isImageGenToolVisible()); + assertFalse(stateBothDisabled.isImageGenToolEnabled()); } }
diff --git a/components/contextual_search/contextual_search_metrics_recorder.cc b/components/contextual_search/contextual_search_metrics_recorder.cc index 5755272..344c5a0 100644 --- a/components/contextual_search/contextual_search_metrics_recorder.cc +++ b/components/contextual_search/contextual_search_metrics_recorder.cc
@@ -600,4 +600,17 @@ is_contextual); } +void ContextualSearchMetricsRecorder::RecordTypedSuggestNavigation( + bool is_verbatim) { + std::string suffix = is_verbatim ? "Verbatim" : "SearchSuggest"; + base::RecordAction(base::UserMetricsAction( + base::StrCat({"ContextualSearch.TypedSuggestNavigation.", suffix, ".", + metrics_suffix_}) + .c_str())); + base::UmaHistogramBoolean( + base::StrCat({"ContextualSearch.TypedSuggestNavigation.IsVerbatim.", + metrics_suffix_}), + is_verbatim); +} + } // namespace contextual_search
diff --git a/components/contextual_search/contextual_search_metrics_recorder.h b/components/contextual_search/contextual_search_metrics_recorder.h index bc95927..47eb1fa9 100644 --- a/components/contextual_search/contextual_search_metrics_recorder.h +++ b/components/contextual_search/contextual_search_metrics_recorder.h
@@ -163,6 +163,9 @@ // Records when a zero-suggest suggestion is clicked. virtual void RecordZeroSuggestClick(bool is_contextual); + // Records when a typed suggestion is clicked. + virtual void RecordTypedSuggestNavigation(bool is_verbatim); + private: // Called when the session starts to correctly track session // durations.
diff --git a/components/contextual_search/contextual_search_service_unittest.cc b/components/contextual_search/contextual_search_service_unittest.cc index c119952..ef63976 100644 --- a/components/contextual_search/contextual_search_service_unittest.cc +++ b/components/contextual_search/contextual_search_service_unittest.cc
@@ -621,4 +621,16 @@ file_token, file_name, file_mime_type, std::move(buffer), std::nullopt); } +TEST(ContextualSearchTypesTest, ContextUploadStatus_EnumSize) { + // The expected value should be the integer value of `kMaxValue`. + // The current kMaxValue is `kUploadReplaced`, which has a value of 8. + EXPECT_EQ(static_cast<int>(ContextUploadStatus::kMaxValue), 8); +} + +TEST(ContextualSearchTypesTest, ContextUploadErrorType_EnumSize) { + // The expected value should be the integer value of `kMaxValue`. + // The current kMaxValue is `kImageProcessingError`, which has a value of 6. + EXPECT_EQ(static_cast<int>(ContextUploadErrorType::kMaxValue), 6); +} + } // namespace contextual_search
diff --git a/components/contextual_search/contextual_search_types.h b/components/contextual_search/contextual_search_types.h index 2d717a9..0aed39d 100644 --- a/components/contextual_search/contextual_search_types.h +++ b/components/contextual_search/contextual_search_types.h
@@ -42,6 +42,10 @@ kProcessingSuggestSignalsReady = 7, // File is being replaced. kUploadReplaced = 8, + + // Add new enumerators above this line. + // This must always be the last valid enum. + kMaxValue = kUploadReplaced, }; // For upload error notifications and metrics. @@ -60,6 +64,10 @@ kAborted = 5, // Image processing error. kImageProcessingError = 6, + + // Add new enumerators above this line. + // This must always be the last valid enum. + kMaxValue = kImageProcessingError, }; // Struct containing file information for a file upload.
diff --git a/components/devtools/simple_devtools_protocol_client/simple_devtools_protocol_client.cc b/components/devtools/simple_devtools_protocol_client/simple_devtools_protocol_client.cc index ea13b34..c2b19c2 100644 --- a/components/devtools/simple_devtools_protocol_client/simple_devtools_protocol_client.cc +++ b/components/devtools/simple_devtools_protocol_client/simple_devtools_protocol_client.cc
@@ -123,6 +123,10 @@ } } +bool SimpleDevToolsProtocolClient::MayAccessAllCookies() { + return true; +} + void SimpleDevToolsProtocolClient::DispatchProtocolMessageTask( base::DictValue message) { VLOG(kVLogLevel) << "\n[CDP RECV] " << message.DebugString();
diff --git a/components/devtools/simple_devtools_protocol_client/simple_devtools_protocol_client.h b/components/devtools/simple_devtools_protocol_client/simple_devtools_protocol_client.h index bf2040ab..e788767 100644 --- a/components/devtools/simple_devtools_protocol_client/simple_devtools_protocol_client.h +++ b/components/devtools/simple_devtools_protocol_client/simple_devtools_protocol_client.h
@@ -66,6 +66,7 @@ void DispatchProtocolMessage(content::DevToolsAgentHost* agent_host, base::span<const uint8_t> json_message) override; void AgentHostClosed(content::DevToolsAgentHost* agent_host) override; + bool MayAccessAllCookies() override; // Virtual for tests. virtual void DispatchProtocolMessageTask(base::DictValue message);
diff --git a/components/embedder_support/android/delegate/color_picker_bridge.cc b/components/embedder_support/android/delegate/color_picker_bridge.cc index 0c407dd..18d7274 100644 --- a/components/embedder_support/android/delegate/color_picker_bridge.cc +++ b/components/embedder_support/android/delegate/color_picker_bridge.cc
@@ -14,7 +14,6 @@ // Must come after all headers that specialize FromJniType() / ToJniType(). #include "components/embedder_support/android/web_contents_delegate_jni/ColorPickerBridge_jni.h" -using base::android::ConvertUTF8ToJavaString; using base::android::JavaRef; namespace web_contents_delegate_android { @@ -35,7 +34,7 @@ // Create a bridge to communicate with Java-side code. j_color_chooser_.Reset(Java_ColorPickerBridge_create( - env, reinterpret_cast<intptr_t>(this), window_android->GetJavaObject())); + env, reinterpret_cast<intptr_t>(this), window_android)); // End with the initial color if the bridge creation failed. if (j_color_chooser_.is_null()) { @@ -46,8 +45,7 @@ // For an element that includes suggestions, send them to Java. for (const auto& suggestion : suggestions) { Java_ColorPickerBridge_addColorSuggestion( - env, j_color_chooser_, suggestion->color, - ConvertUTF8ToJavaString(env, suggestion->label)); + env, j_color_chooser_, suggestion->color, suggestion->label); } // Show the color picker dialog.
diff --git a/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/ColorPickerBridge.java b/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/ColorPickerBridge.java index 61f817c..7df093e0 100644 --- a/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/ColorPickerBridge.java +++ b/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/ColorPickerBridge.java
@@ -10,6 +10,7 @@ import org.jni_zero.CalledByNative; import org.jni_zero.JNINamespace; +import org.jni_zero.JniType; import org.jni_zero.NativeMethods; import org.chromium.base.ContextUtils; @@ -30,7 +31,8 @@ private final ColorPickerCoordinator mColorPickerCoordinator; @CalledByNative - static @Nullable ColorPickerBridge create(long nativeDialog, WindowAndroid windowAndroid) { + static @Nullable ColorPickerBridge create( + long nativeDialog, @JniType("ui::WindowAndroid*") WindowAndroid windowAndroid) { if (windowAndroid == null) return null; Context context = windowAndroid.getContext().get(); if (ContextUtils.activityFromContext(context) == null) return null; @@ -54,7 +56,7 @@ } @CalledByNative - void addColorSuggestion(int color, String label) { + void addColorSuggestion(int color, @JniType("std::string") String label) { if (mColorPickerCoordinator != null) { mColorPickerCoordinator.addColorSuggestion(color, label); }
diff --git a/components/enterprise/connectors/core/BUILD.gn b/components/enterprise/connectors/core/BUILD.gn index 49af0b7..d9eb13c0 100644 --- a/components/enterprise/connectors/core/BUILD.gn +++ b/components/enterprise/connectors/core/BUILD.gn
@@ -125,6 +125,8 @@ "cloud_content_scanning/deep_scanning_utils.h", "cloud_content_scanning/file_analysis_request_base.cc", "cloud_content_scanning/file_analysis_request_base.h", + "cloud_content_scanning/file_opening_job.cc", + "cloud_content_scanning/file_opening_job.h", "cloud_content_scanning/multipart_uploader.cc", "cloud_content_scanning/multipart_uploader.h", "cloud_content_scanning/multipart_uploader_base.cc", @@ -241,6 +243,7 @@ sources = [ "cloud_content_scanning/connector_data_pipe_getter_unittest.cc", "cloud_content_scanning/file_analysis_request_base_unittest.cc", + "cloud_content_scanning/file_opening_job_unittest.cc", "cloud_content_scanning/multipart_uploader_base_unittest.cc", "cloud_content_scanning/multipart_uploader_unittest.cc", "cloud_content_scanning/resumable_uploader_base_unittest.cc",
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/file_opening_job.cc b/components/enterprise/connectors/core/cloud_content_scanning/file_opening_job.cc similarity index 92% rename from chrome/browser/safe_browsing/cloud_content_scanning/file_opening_job.cc rename to components/enterprise/connectors/core/cloud_content_scanning/file_opening_job.cc index 711aa23..44010e6 100644 --- a/chrome/browser/safe_browsing/cloud_content_scanning/file_opening_job.cc +++ b/components/enterprise/connectors/core/cloud_content_scanning/file_opening_job.cc
@@ -2,13 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/safe_browsing/cloud_content_scanning/file_opening_job.h" +#include "components/enterprise/connectors/core/cloud_content_scanning/file_opening_job.h" #include "base/command_line.h" #include "base/functional/bind.h" #include "base/logging.h" #include "base/strings/string_number_conversions.h" #include "base/task/task_traits.h" +#include "components/enterprise/connectors/core/cloud_content_scanning/file_analysis_request_base.h" #include "components/safe_browsing/core/common/safebrowsing_switches.h" namespace safe_browsing { @@ -57,8 +58,9 @@ } FileOpeningJob::~FileOpeningJob() { - if (file_opening_job_handle_) + if (file_opening_job_handle_) { file_opening_job_handle_.Cancel(); + } } void FileOpeningJob::ProcessNextTask(base::JobDelegate* job_delegate) { @@ -70,8 +72,9 @@ // be true indicates we were the not the thread that took it. // std::memory_order_relaxed is safe here since `taken` is not synchronized // with other state. - if (tasks_[i].taken.exchange(true, std::memory_order_relaxed)) + if (tasks_[i].taken.exchange(true, std::memory_order_relaxed)) { continue; + } // Since we know we now have taken `tasks_[i]`, we can do the file opening // work safely.
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/file_opening_job.h b/components/enterprise/connectors/core/cloud_content_scanning/file_opening_job.h similarity index 80% rename from chrome/browser/safe_browsing/cloud_content_scanning/file_opening_job.h rename to components/enterprise/connectors/core/cloud_content_scanning/file_opening_job.h index ee1fbe1c..9ec8615 100644 --- a/chrome/browser/safe_browsing/cloud_content_scanning/file_opening_job.h +++ b/components/enterprise/connectors/core/cloud_content_scanning/file_opening_job.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_SAFE_BROWSING_CLOUD_CONTENT_SCANNING_FILE_OPENING_JOB_H_ -#define CHROME_BROWSER_SAFE_BROWSING_CLOUD_CONTENT_SCANNING_FILE_OPENING_JOB_H_ +#ifndef COMPONENTS_ENTERPRISE_CONNECTORS_CORE_CLOUD_CONTENT_SCANNING_FILE_OPENING_JOB_H_ +#define COMPONENTS_ENTERPRISE_CONNECTORS_CORE_CLOUD_CONTENT_SCANNING_FILE_OPENING_JOB_H_ #include <atomic> #include <vector> @@ -11,12 +11,16 @@ #include "base/gtest_prod_util.h" #include "base/memory/raw_ptr.h" #include "base/task/post_job.h" -#include "chrome/browser/safe_browsing/cloud_content_scanning/file_analysis_request.h" + +namespace enterprise_connectors { +class FileAnalysisRequestBase; +} // namespace enterprise_connectors namespace safe_browsing { // This class encapsulates a base::PostJob call made to open multiple files to -// set up multiple FileAnalysiRequests to avoid using too many system resources. +// set up multiple FileAnalysisRequestBases to avoid using too many system +// resources. class FileOpeningJob { public: // Struct to store data necessary for a synchronized file opening task. @@ -25,7 +29,8 @@ ~FileOpeningTask(); // Non-owning pointer to the request corresponding to the file to open. - raw_ptr<safe_browsing::FileAnalysisRequest, AcrossTasksDanglingUntriaged> + raw_ptr<enterprise_connectors::FileAnalysisRequestBase, + AcrossTasksDanglingUntriaged> request = nullptr; // Indicates if this task has been taken and is owned by a thread. @@ -72,4 +77,4 @@ } // namespace safe_browsing -#endif // CHROME_BROWSER_SAFE_BROWSING_CLOUD_CONTENT_SCANNING_FILE_OPENING_JOB_H_ +#endif // COMPONENTS_ENTERPRISE_CONNECTORS_CORE_CLOUD_CONTENT_SCANNING_FILE_OPENING_JOB_H_
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/file_opening_job_unittest.cc b/components/enterprise/connectors/core/cloud_content_scanning/file_opening_job_unittest.cc similarity index 71% rename from chrome/browser/safe_browsing/cloud_content_scanning/file_opening_job_unittest.cc rename to components/enterprise/connectors/core/cloud_content_scanning/file_opening_job_unittest.cc index 71948cb..6e28171 100644 --- a/chrome/browser/safe_browsing/cloud_content_scanning/file_opening_job_unittest.cc +++ b/components/enterprise/connectors/core/cloud_content_scanning/file_opening_job_unittest.cc
@@ -2,33 +2,47 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/safe_browsing/cloud_content_scanning/file_opening_job.h" +#include "components/enterprise/connectors/core/cloud_content_scanning/file_opening_job.h" #include <memory> #include "base/command_line.h" #include "base/containers/span.h" +#include "base/files/file.h" #include "base/files/scoped_temp_dir.h" #include "base/memory/weak_ptr.h" #include "base/run_loop.h" #include "base/strings/stringprintf.h" #include "base/test/scoped_command_line.h" +#include "base/test/task_environment.h" #include "build/build_config.h" -#include "chrome/browser/enterprise/connectors/common.h" -#include "chrome/browser/safe_browsing/cloud_content_scanning/file_analysis_request.h" #include "components/enterprise/connectors/core/cloud_content_scanning/common.h" -#include "content/public/test/browser_task_environment.h" +#include "components/enterprise/connectors/core/cloud_content_scanning/file_analysis_request_base.h" +#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" -namespace safe_browsing { +namespace enterprise_connectors { +class MockFileAnalysisRequestBase : public FileAnalysisRequestBase { + public: + using FileAnalysisRequestBase::FileAnalysisRequestBase; +#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) + MOCK_METHOD1(ProcessZipFile, void(Data)); + MOCK_METHOD1(ProcessRarFile, void(Data)); +#endif +}; +} // namespace enterprise_connectors + +namespace safe_browsing { class FileOpeningJobTest : public testing::Test { public: void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); } - void OnGotFileData(std::unique_ptr<FileAnalysisRequest> request, - enterprise_connectors::ScanRequestUploadResult result, - enterprise_connectors::BinaryUploadRequest::Data data) { + void OnGotFileData( + std::unique_ptr<enterprise_connectors::MockFileAnalysisRequestBase> + request, + enterprise_connectors::ScanRequestUploadResult result, + enterprise_connectors::BinaryUploadRequest::Data data) { EXPECT_EQ(enterprise_connectors::ScanRequestUploadResult::kSuccess, result); EXPECT_TRUE(data.contents.empty()); EXPECT_FALSE(data.mime_type.empty()); @@ -39,8 +53,9 @@ data.hash); ++on_got_file_data_count_; - if (on_got_file_data_count_ == quit_file_count_) + if (on_got_file_data_count_ == quit_file_count_) { quit_closure_.Run(); + } } std::vector<FileOpeningJob::FileOpeningTask> CreateFilesAndTasks(int num) { @@ -53,11 +68,15 @@ base::File file(path, base::File::FLAG_CREATE | base::File::FLAG_WRITE); file.WriteAtCurrentPos(base::byte_span_from_cstring("foo")); - auto request = std::make_unique<FileAnalysisRequest>( - enterprise_connectors::AnalysisSettings(), path, path.BaseName(), - /*mime_type*/ "", - /*delay_opening_file*/ true, base::DoNothing()); - auto* request_raw = request.get(); + auto request = + std::make_unique<enterprise_connectors::MockFileAnalysisRequestBase>( + enterprise_connectors::AnalysisSettings(), path, path.BaseName(), + /*mime_type*/ "", + /*delay_opening_file*/ true, base::DoNothing(), + base::NullCallback(), + base::SingleThreadTaskRunner::GetCurrentDefault()); + enterprise_connectors::FileAnalysisRequestBase* request_raw = + request.get(); request_raw->GetRequestData( base::BindOnce(&FileOpeningJobTest::OnGotFileData, weak_factory_.GetWeakPtr(), std::move(request))); @@ -69,7 +88,7 @@ protected: base::ScopedTempDir temp_dir_; - content::BrowserTaskEnvironment browser_task_environment_; + base::test::TaskEnvironment task_environment_; int next_file_id_ = 0; int on_got_file_data_count_ = 0;
diff --git a/components/enterprise/connectors/core/features.cc b/components/enterprise/connectors/core/features.cc index 0ceb4b6..126e353 100644 --- a/components/enterprise/connectors/core/features.cc +++ b/components/enterprise/connectors/core/features.cc
@@ -38,4 +38,7 @@ // Enables scanning of pasted images for DLP. BASE_FEATURE(kDlpScanPastedImages, base::FEATURE_ENABLED_BY_DEFAULT); +// Controls enabling bulk data entry support in Glic actuation logic. +BASE_FEATURE(kGlicBulkDataEntrySupport, base::FEATURE_DISABLED_BY_DEFAULT); + } // namespace enterprise_connectors
diff --git a/components/enterprise/connectors/core/features.h b/components/enterprise/connectors/core/features.h index 2618d424..0f32c4f 100644 --- a/components/enterprise/connectors/core/features.h +++ b/components/enterprise/connectors/core/features.h
@@ -42,6 +42,9 @@ BASE_DECLARE_FEATURE(kDlpScanPastedImages); +// Controls enabling bulk data entry support in Glic actuation logic. +BASE_DECLARE_FEATURE(kGlicBulkDataEntrySupport); + } // namespace enterprise_connectors #endif // COMPONENTS_ENTERPRISE_CONNECTORS_CORE_FEATURES_H_
diff --git a/components/metrics/metrics_pref_names.h b/components/metrics/metrics_pref_names.h index f85fd13..57a5f27 100644 --- a/components/metrics/metrics_pref_names.h +++ b/components/metrics/metrics_pref_names.h
@@ -7,8 +7,7 @@ #include "build/build_config.h" -namespace metrics { -namespace prefs { +namespace metrics::prefs { // Alphabetical list of preference names specific to the metrics // component. @@ -255,10 +254,6 @@ // For measuring data use for throttling UMA log uploads on cellular. -// Dictionary for measuring cellular data used by UKM service during last 7 -// days. -inline constexpr char kUkmCellDataUse[] = - "user_experience_metrics.ukm_cell_datause"; // Dictionary for measuring cellular data used by UMA service during last 7 // days. inline constexpr char kUmaCellDataUse[] = @@ -275,7 +270,6 @@ // of a crash. inline constexpr char kMetricsCurrentUserId[] = "metrics.current_user_id"; -} // namespace prefs -} // namespace metrics +} // namespace metrics::prefs #endif // COMPONENTS_METRICS_METRICS_PREF_NAMES_H_
diff --git a/components/offline_items_collection/core/android/offline_item_bridge_unittest.cc b/components/offline_items_collection/core/android/offline_item_bridge_unittest.cc index 3d52786..07b66ba 100644 --- a/components/offline_items_collection/core/android/offline_item_bridge_unittest.cc +++ b/components/offline_items_collection/core/android/offline_item_bridge_unittest.cc
@@ -22,8 +22,7 @@ class OfflineItemBridgeTest : public ::testing::Test { public: OfflineItemBridgeTest() - : j_test_(JOfflineItemBridgeUnitTestClass::Constructor( - AttachCurrentThread())) {} + : j_test_(JOfflineItemBridgeUnitTestClass::New(AttachCurrentThread())) {} const jni_zero::ScopedJavaGlobalRef<JOfflineItemBridgeUnitTest>& j_test() { return j_test_;
diff --git a/components/omnibox/browser/android/java/src/org/chromium/components/omnibox/AutocompleteMatch.java b/components/omnibox/browser/android/java/src/org/chromium/components/omnibox/AutocompleteMatch.java index a956d88..f83740dd 100644 --- a/components/omnibox/browser/android/java/src/org/chromium/components/omnibox/AutocompleteMatch.java +++ b/components/omnibox/browser/android/java/src/org/chromium/components/omnibox/AutocompleteMatch.java
@@ -223,7 +223,7 @@ boolean allowedToBeDefaultMatch, @JniType("std::u16string") String inlineAutocompletion, @JniType("std::u16string") String additionalText, - @JniType("base::Uuid") String localTabGroupId, + @JniType("std::optional<std::string>") @Nullable String localTabGroupId, @JniType("std::u16string") String associatedKeyword, byte[] serializedSuggestTemplate) { assert contentClassificationOffsets.length == contentClassificationStyles.length; @@ -266,7 +266,7 @@ allowedToBeDefaultMatch, inlineAutocompletion, additionalText, - TextUtils.isEmpty(localTabGroupId) ? null : localTabGroupId, + localTabGroupId, TextUtils.isEmpty(associatedKeyword) ? null : associatedKeyword, serializedSuggestTemplate); match.updateNativeObjectRef(nativeObject);
diff --git a/components/omnibox/browser/autocomplete_match_android.cc b/components/omnibox/browser/autocomplete_match_android.cc index 926b28c..be6f4e6 100644 --- a/components/omnibox/browser/autocomplete_match_android.cc +++ b/components/omnibox/browser/autocomplete_match_android.cc
@@ -117,7 +117,9 @@ suggestion_group_id.value_or(omnibox::GROUP_INVALID), j_clipboard_image_data, has_tab_match.value_or(false), actions_list, allowed_to_be_default_match, inline_autocompletion, additional_text, - matching_tab_group_uuid.value_or(base::Uuid()), + matching_tab_group_uuid + ? std::make_optional(matching_tab_group_uuid->AsLowercaseString()) + : std::nullopt, associated_keyword, j_suggest_template)); return ScopedJavaLocalRef<jobject>(*java_match_);
diff --git a/components/omnibox/browser/searchbox.mojom b/components/omnibox/browser/searchbox.mojom index 321fb4d9..efed792 100644 --- a/components/omnibox/browser/searchbox.mojom +++ b/components/omnibox/browser/searchbox.mojom
@@ -391,11 +391,18 @@ // Called when a user enables a tool. SetActiveToolMode(composebox_query.mojom.ToolMode tool); + // Called when a user enables a model. SetActiveModelMode(composebox_query.mojom.ModelMode model); // Activates a metrics funnel for the session. ActivateMetricsFunnel(string funnel_name); + + // Called when a user interacts with a tool selection button explicitly. + RecordToolSelectionAction(composebox_query.mojom.ToolMode tool); + + // Called when a user interacts with a model selection button explicitly. + RecordModelSelectionAction(composebox_query.mojom.ModelMode model); }; // WebUI-side handler for requests from the browser.
diff --git a/components/one_time_tokens/android/backend/sms/sms_otp_to_one_time_token_retrieval_error_converter.cc b/components/one_time_tokens/android/backend/sms/sms_otp_to_one_time_token_retrieval_error_converter.cc index aa2f93f..b266ce1 100644 --- a/components/one_time_tokens/android/backend/sms/sms_otp_to_one_time_token_retrieval_error_converter.cc +++ b/components/one_time_tokens/android/backend/sms/sms_otp_to_one_time_token_retrieval_error_converter.cc
@@ -4,6 +4,7 @@ #include "components/one_time_tokens/android/backend/sms/sms_otp_to_one_time_token_retrieval_error_converter.h" +#include "base/notreached.h" #include "components/one_time_tokens/android/backend/sms/sms_otp_retrieval_api_error_codes.h" #include "components/one_time_tokens/core/browser/one_time_token_retrieval_error.h" @@ -25,6 +26,9 @@ return OneTimeTokenRetrievalError::kSmsOtpBackendApiNotAvailable; case SmsOtpRetrievalApiErrorCode::kUserPermissionRequired: return OneTimeTokenRetrievalError::kSmsOtpBackendUserPermissionRequired; + default: + // TODO(crbug.com/493648142) REMOVE THIS ONCE FIXED. + return OneTimeTokenRetrievalError::kUnknown; } // LINT.ThenChange(//components/one_time_tokens/core/browser/one_time_token_retrieval_error.h) }
diff --git a/components/optimization_guide/internal b/components/optimization_guide/internal index 89bf056..53d3b7d 160000 --- a/components/optimization_guide/internal +++ b/components/optimization_guide/internal
@@ -1 +1 @@ -Subproject commit 89bf056f23fe4545522f6c2fde4ed5e15957544e +Subproject commit 53d3b7da14796b293ff6d501fb2b7ccbcff1086b
diff --git a/components/optimization_guide/proto/features/common_quality_data.proto b/components/optimization_guide/proto/features/common_quality_data.proto index 5589218..ad07e62 100644 --- a/components/optimization_guide/proto/features/common_quality_data.proto +++ b/components/optimization_guide/proto/features/common_quality_data.proto
@@ -729,6 +729,11 @@ message TableData { // The name of the table, coming from the caption. + // Note: this field has some quirks for backwards-compatibility reasons: + // 1. It is only populated if the table name is an immediate child of the + // table element. Table names further down in the tree are skipped, leaving + // this field empty. + // 2. The table name also will appear in a separate child text node. string table_name = 1 [features = { field_presence: EXPLICIT }]; reserved 2, 3, 4;
diff --git a/components/optimization_guide/proto/features/finds.proto b/components/optimization_guide/proto/features/finds.proto index b6031e9..1518433 100644 --- a/components/optimization_guide/proto/features/finds.proto +++ b/components/optimization_guide/proto/features/finds.proto
@@ -55,14 +55,17 @@ // The "hook" title for the notification (e.g., "Best Mexican in NYC"). string theme_title = 1 [features = { field_presence: EXPLICIT }]; + // The description of the theme. + string description = 2 [features = { field_presence: EXPLICIT }]; + // Identifies the theme by a specific type, used for user opt-out. - ThemeType theme_type = 2 [features = { field_presence: EXPLICIT }]; + ThemeType theme_type = 3 [features = { field_presence: EXPLICIT }]; // The list of net-new URLs matching this theme. - repeated SuggestedContent suggestions = 3; + repeated SuggestedContent suggestions = 4; // Score used to prioritize client behavior. - int64 score = 4 [features = { field_presence: EXPLICIT }]; + int64 score = 5 [features = { field_presence: EXPLICIT }]; // A single entry for suggested content, there can be multiple of // these per-theme. @@ -70,9 +73,12 @@ // The title to display in the notification. string title = 1 [features = { field_presence: EXPLICIT }]; + // The description to display in the notification. + string description = 2 [features = { field_presence: EXPLICIT }]; + // The destination URL. // Must be validated as "live" (200 OK) before showing. - string target_url = 2 [features = { field_presence: EXPLICIT }]; + string target_url = 3 [features = { field_presence: EXPLICIT }]; } // Bucket themes to support "opting-out" of topics on the client.
diff --git a/components/os_crypt/async/browser/freedesktop_secret_key_provider.cc b/components/os_crypt/async/browser/freedesktop_secret_key_provider.cc index c45f79ee..657bc07 100644 --- a/components/os_crypt/async/browser/freedesktop_secret_key_provider.cc +++ b/components/os_crypt/async/browser/freedesktop_secret_key_provider.cc
@@ -832,7 +832,7 @@ base::span<const uint8_t> secret) { static_assert(kDerivedKeySizeInBits % 8 == 0); std::array<uint8_t, kDerivedKeySizeInBits / 8> key_bytes; - crypto::kdf::DeriveKeyPbkdf2HmacSha1( + crypto::kdf::Pbkdf2HmacSha1( {kEncryptionIterations}, secret, base::as_byte_span(base::span_from_cstring(kSalt)), key_bytes, crypto::SubtlePassKey{});
diff --git a/components/os_crypt/async/browser/keychain_key_provider.mm b/components/os_crypt/async/browser/keychain_key_provider.mm index 64a3bb5..85d7e379 100644 --- a/components/os_crypt/async/browser/keychain_key_provider.mm +++ b/components/os_crypt/async/browser/keychain_key_provider.mm
@@ -58,9 +58,9 @@ } std::array<uint8_t, kDerivedKeySize> key_bytes; - crypto::kdf::DeriveKeyPbkdf2HmacSha1({.iterations = kIterations}, - base::as_byte_span(password), kSalt, - key_bytes, subtle_passkey); + crypto::kdf::Pbkdf2HmacSha1({.iterations = kIterations}, + base::as_byte_span(password), kSalt, key_bytes, + subtle_passkey); return Encryptor::Key(key_bytes, mojom::Algorithm::kAES128CBC); }
diff --git a/components/os_crypt/sync/os_crypt_linux.cc b/components/os_crypt/sync/os_crypt_linux.cc index 4f963041..f6c7f1af 100644 --- a/components/os_crypt/sync/os_crypt_linux.cc +++ b/components/os_crypt/sync/os_crypt_linux.cc
@@ -288,8 +288,8 @@ std::array<uint8_t, OSCryptImpl::kDerivedKeyBytes> OSCryptImpl::Pbkdf2( const std::string& key) { std::array<uint8_t, OSCryptImpl::kDerivedKeyBytes> result; - crypto::kdf::DeriveKeyPbkdf2HmacSha1(kParams, base::as_byte_span(key), kSalt, - result, MakeCryptoPassKey()); + crypto::kdf::Pbkdf2HmacSha1(kParams, base::as_byte_span(key), kSalt, result, + MakeCryptoPassKey()); return result; }
diff --git a/components/os_crypt/sync/os_crypt_mac.mm b/components/os_crypt/sync/os_crypt_mac.mm index 4bcafe27..1d4d73c 100644 --- a/components/os_crypt/sync/os_crypt_mac.mm +++ b/components/os_crypt/sync/os_crypt_mac.mm
@@ -147,9 +147,9 @@ static constexpr size_t kIterations = 1003; std::array<uint8_t, kDerivedKeySize> key; - crypto::kdf::DeriveKeyPbkdf2HmacSha1({.iterations = kIterations}, - base::as_byte_span(password), kSalt, key, - crypto::SubtlePassKey{}); + crypto::kdf::Pbkdf2HmacSha1({.iterations = kIterations}, + base::as_byte_span(password), kSalt, key, + crypto::SubtlePassKey{}); key_ = key; return true; }
diff --git a/components/password_manager/core/browser/leak_detection/encryption_utils.cc b/components/password_manager/core/browser/leak_detection/encryption_utils.cc index 4311746..da4c161c 100644 --- a/components/password_manager/core/browser/leak_detection/encryption_utils.cc +++ b/components/password_manager/core/browser/leak_detection/encryption_utils.cc
@@ -116,10 +116,9 @@ {canonicalized_username, base::as_string_view(kPasswordHashSalt)}); std::string result(kHashKeyLength, 0); - crypto::kdf::DeriveKeyScrypt( - kScryptParams, base::as_byte_span(username_password), - base::as_byte_span(salt), base::as_writable_byte_span(result), - MakeCryptoPassKey()); + crypto::kdf::Scrypt(kScryptParams, base::as_byte_span(username_password), + base::as_byte_span(salt), + base::as_writable_byte_span(result), MakeCryptoPassKey()); return result; }
diff --git a/components/password_manager/core/browser/password_hash_data.cc b/components/password_manager/core/browser/password_hash_data.cc index d7cb1a0..0e714944 100644 --- a/components/password_manager/core/browser/password_hash_data.cc +++ b/components/password_manager/core/browser/password_hash_data.cc
@@ -61,9 +61,9 @@ }; std::array<uint8_t, 8> result; - crypto::kdf::DeriveKeyScrypt(kScryptParams, base::as_byte_span(text), - base::as_byte_span(salt), result, - MakeCryptoPassKeyForPasswordHash()); + crypto::kdf::Scrypt(kScryptParams, base::as_byte_span(text), + base::as_byte_span(salt), result, + MakeCryptoPassKeyForPasswordHash()); uint64_t val = base::U64FromLittleEndian(result); // Take 37 bits of |hash|.
diff --git a/components/policy/core/common/cloud/cloud_policy_client.h b/components/policy/core/common/cloud/cloud_policy_client.h index dd563f0..11e347cb 100644 --- a/components/policy/core/common/cloud/cloud_policy_client.h +++ b/components/policy/core/common/cloud/cloud_policy_client.h
@@ -191,7 +191,7 @@ // PSM protocol execution result. Its value will exist if the device // undergoes enrollment and a PSM server-backed state determination was // performed before (on Chrome OS, as encoded in the - // `prefs::kEnrollmentPsmResult` pref). + // `ash::prefs::kEnrollmentPsmResult` pref). std::optional< enterprise_management::DeviceRegisterRequest::PsmExecutionResult> psm_execution_result; @@ -199,7 +199,7 @@ // The following field is relevant only to Chrome OS. // PSM protocol determination timestamp. Its value will exist if the device // undergoes enrollment and PSM got executed successfully (on ChromeOS, as - // encoded in `prefs::kEnrollmentPsmDeterminationTime` pref). + // encoded in `ash::prefs::kEnrollmentPsmDeterminationTime` pref). std::optional<int64_t> psm_determination_timestamp; // The following field is relevant only to Chrome OS Demo Mode.
diff --git a/components/saved_tab_groups/internal/android/tab_group_sync_service_android_unittest.cc b/components/saved_tab_groups/internal/android/tab_group_sync_service_android_unittest.cc index 5c8f885..89a24c4 100644 --- a/components/saved_tab_groups/internal/android/tab_group_sync_service_android_unittest.cc +++ b/components/saved_tab_groups/internal/android/tab_group_sync_service_android_unittest.cc
@@ -65,8 +65,8 @@ ~TabGroupSyncServiceAndroidTest() override = default; void SetUp() override { - j_test_ = JTabGroupSyncServiceAndroidUnitTestClass::Constructor( - AttachCurrentThread()); + j_test_ = + JTabGroupSyncServiceAndroidUnitTestClass::New(AttachCurrentThread()); CreateBridge(); SetUpJavaTestObserver(); }
diff --git a/components/search/ntp_features.cc b/components/search/ntp_features.cc index 3d9675e..06010a7 100644 --- a/components/search/ntp_features.cc +++ b/components/search/ntp_features.cc
@@ -250,6 +250,12 @@ BASE_FEATURE(kNtpFeatureOptimizationDismissModulesRemoval, base::FEATURE_ENABLED_BY_DEFAULT); +// If enabled, will support animated Doodles on the NTP. +BASE_FEATURE(kNtpAnimatedDoodles, base::FEATURE_DISABLED_BY_DEFAULT); + +// If enabled, will support Doodle Murals on the NTP. +BASE_FEATURE(kNtpDoodleMurals, base::FEATURE_DISABLED_BY_DEFAULT); + // If enabled, animates the AIM caret on the NTP. BASE_FEATURE(kNtpAnimatedCaret, base::FEATURE_ENABLED_BY_DEFAULT);
diff --git a/components/search/ntp_features.h b/components/search/ntp_features.h index 888b188..88544914 100644 --- a/components/search/ntp_features.h +++ b/components/search/ntp_features.h
@@ -85,6 +85,8 @@ BASE_DECLARE_FEATURE(kNtpFeatureOptimizationModuleRemoval); BASE_DECLARE_FEATURE(kNtpFeatureOptimizationShortcutsRemoval); BASE_DECLARE_FEATURE(kNtpFeatureOptimizationDismissModulesRemoval); +BASE_DECLARE_FEATURE(kNtpAnimatedDoodles); +BASE_DECLARE_FEATURE(kNtpDoodleMurals); // Parameter for controlling the luminosity difference for NTP elements on light // backgrounds.
diff --git a/components/services/quarantine/quarantine_unittest.cc b/components/services/quarantine/quarantine_unittest.cc index 8f9e8c4e..b06eab1 100644 --- a/components/services/quarantine/quarantine_unittest.cc +++ b/components/services/quarantine/quarantine_unittest.cc
@@ -30,9 +30,9 @@ const char kInternetReferrerURL[] = "http://example.com/some-other-url"; const char kTestGUID[] = "69f8621d-c46a-4e88-b915-1ce5415cb008"; -void CheckQuarantineResult(QuarantineFileResult result, - QuarantineFileResult expected_result) { - EXPECT_EQ(expected_result, result); +void CheckQuarantineResult(QuarantineFileResult expected, + QuarantineFileResult actual) { + EXPECT_EQ(expected, actual); } class QuarantineTest : public testing::Test {
diff --git a/components/site_engagement/content/android/java/src/org/chromium/components/site_engagement/SiteEngagementService.java b/components/site_engagement/content/android/java/src/org/chromium/components/site_engagement/SiteEngagementService.java index 63c2b0f..8e1b51d6 100644 --- a/components/site_engagement/content/android/java/src/org/chromium/components/site_engagement/SiteEngagementService.java +++ b/components/site_engagement/content/android/java/src/org/chromium/components/site_engagement/SiteEngagementService.java
@@ -6,6 +6,7 @@ import org.jni_zero.CalledByNative; import org.jni_zero.JNINamespace; +import org.jni_zero.JniType; import org.jni_zero.NativeMethods; import org.chromium.base.ThreadUtils; @@ -81,9 +82,12 @@ void setParamValuesForTesting(); - double getScore(long nativeSiteEngagementServiceAndroid, String url); + double getScore( + long nativeSiteEngagementServiceAndroid, @JniType("std::string") String url); void resetBaseScoreForURL( - long nativeSiteEngagementServiceAndroid, String url, double score); + long nativeSiteEngagementServiceAndroid, + @JniType("std::string") String url, + double score); } }
diff --git a/components/site_engagement/content/android/site_engagement_service_android.cc b/components/site_engagement/content/android/site_engagement_service_android.cc index ef26da7..25bd367 100644 --- a/components/site_engagement/content/android/site_engagement_service_android.cc +++ b/components/site_engagement/content/android/site_engagement_service_android.cc
@@ -46,24 +46,13 @@ java_service_.Reset(); } -double SiteEngagementServiceAndroid::GetScore( - JNIEnv* env, - const JavaRef<jstring>& jurl) const { - if (!jurl) - return 0; - - return service_->GetScore( - GURL(base::android::ConvertJavaStringToUTF16(env, jurl))); +double SiteEngagementServiceAndroid::GetScore(const std::string& url) const { + return service_->GetScore(GURL(url)); } -void SiteEngagementServiceAndroid::ResetBaseScoreForURL( - JNIEnv* env, - const JavaRef<jstring>& jurl, - double score) { - if (jurl) { - service_->ResetBaseScoreForURL( - GURL(base::android::ConvertJavaStringToUTF16(env, jurl)), score); - } +void SiteEngagementServiceAndroid::ResetBaseScoreForURL(const std::string& url, + double score) { + service_->ResetBaseScoreForURL(GURL(url), score); } static void JNI_SiteEngagementService_SetParamValuesForTesting(JNIEnv* env) {
diff --git a/components/site_engagement/content/android/site_engagement_service_android.h b/components/site_engagement/content/android/site_engagement_service_android.h index 297aafb9..681fa75 100644 --- a/components/site_engagement/content/android/site_engagement_service_android.h +++ b/components/site_engagement/content/android/site_engagement_service_android.h
@@ -34,12 +34,9 @@ ~SiteEngagementServiceAndroid(); - double GetScore(JNIEnv* env, - const base::android::JavaRef<jstring>& jurl) const; + double GetScore(const std::string& url) const; - void ResetBaseScoreForURL(JNIEnv* env, - const base::android::JavaRef<jstring>& jurl, - double score); + void ResetBaseScoreForURL(const std::string& url, double score); private: base::android::ScopedJavaGlobalRef<jobject> java_service_;
diff --git a/components/sync/engine/nigori/nigori.cc b/components/sync/engine/nigori/nigori.cc index 5f4fe5f4..b555062 100644 --- a/components/sync/engine/nigori/nigori.cc +++ b/components/sync/engine/nigori/nigori.cc
@@ -123,19 +123,19 @@ // Kuser = PBKDF2(P, Suser, Nuser, 16) user_key = std::make_optional<std::array<uint8_t, kKeySizeBytes>>(); - crypto::kdf::DeriveKeyPbkdf2HmacSha1( + crypto::kdf::Pbkdf2HmacSha1( crypto::kdf::Pbkdf2HmacSha1Params{.iterations = 1002}, base::as_byte_span(password), kSalt, user_key.value(), Nigori::MakeCryptoPassKey()); // Kenc = PBKDF2(P, Suser, Nenc, 16) - crypto::kdf::DeriveKeyPbkdf2HmacSha1( + crypto::kdf::Pbkdf2HmacSha1( crypto::kdf::Pbkdf2HmacSha1Params{.iterations = 1003}, base::as_byte_span(password), kSalt, encryption_key, Nigori::MakeCryptoPassKey()); // Kmac = PBKDF2(P, Suser, Nmac, 16) - crypto::kdf::DeriveKeyPbkdf2HmacSha1( + crypto::kdf::Pbkdf2HmacSha1( crypto::kdf::Pbkdf2HmacSha1Params{.iterations = 1004}, base::as_byte_span(password), kSalt, mac_key, Nigori::MakeCryptoPassKey()); @@ -158,9 +158,8 @@ }; std::array<uint8_t, kKeySizeBytes * 2> keys; - crypto::kdf::DeriveKeyScrypt(params, base::as_byte_span(password), - base::as_byte_span(salt), keys, - MakeCryptoPassKey()); + crypto::kdf::Scrypt(params, base::as_byte_span(password), + base::as_byte_span(salt), keys, MakeCryptoPassKey()); base::span(encryption_key).copy_from(base::span(keys).first(kKeySizeBytes)); base::span(mac_key).copy_from(base::span(keys).subspan(kKeySizeBytes));
diff --git a/components/visibility_timer/BUILD.gn b/components/visibility_timer/BUILD.gn new file mode 100644 index 0000000..b5e695ba --- /dev/null +++ b/components/visibility_timer/BUILD.gn
@@ -0,0 +1,24 @@ +# Copyright 2026 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +source_set("visibility_timer") { + public = [ "visibility_timer_tab_helper.h" ] + sources = [ "visibility_timer_tab_helper.cc" ] + deps = [ + "//base", + "//content/public/browser", + ] +} + +source_set("unit_tests") { + testonly = true + sources = [ "visibility_timer_tab_helper_unittest.cc" ] + deps = [ + ":visibility_timer", + "//base/test:test_support", + "//content/test:test_support", + "//testing/gmock", + "//testing/gtest", + ] +}
diff --git a/components/visibility_timer/DEPS b/components/visibility_timer/DEPS new file mode 100644 index 0000000..d79a7d0 --- /dev/null +++ b/components/visibility_timer/DEPS
@@ -0,0 +1,4 @@ +include_rules = [ + "+content/public/browser", + "+content/public/test", +]
diff --git a/components/visibility_timer/OWNERS b/components/visibility_timer/OWNERS new file mode 100644 index 0000000..d69bfed --- /dev/null +++ b/components/visibility_timer/OWNERS
@@ -0,0 +1,3 @@ +avi@chromium.org +dtapuska@chromium.org +dcheng@chromium.org
diff --git a/components/visibility_timer/README.md b/components/visibility_timer/README.md new file mode 100644 index 0000000..c6f8352 --- /dev/null +++ b/components/visibility_timer/README.md
@@ -0,0 +1,7 @@ +# Visibility Timer + +`VisibilityTimerTabHelper` is a `WebContentsObserver` that executes a task after +the `WebContents` has been continuously visible for a set amount of time. If the +tab becomes hidden before the timer fires, the timer is reset. This is useful +for deferring non-critical actions until a user explicitly keeps a tab visible +for a given duration.
diff --git a/chrome/browser/visibility_timer_tab_helper.cc b/components/visibility_timer/visibility_timer_tab_helper.cc similarity index 88% rename from chrome/browser/visibility_timer_tab_helper.cc rename to components/visibility_timer/visibility_timer_tab_helper.cc index 8d8d41ff..bd506d8 100644 --- a/chrome/browser/visibility_timer_tab_helper.cc +++ b/components/visibility_timer/visibility_timer_tab_helper.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/visibility_timer_tab_helper.h" +#include "components/visibility_timer/visibility_timer_tab_helper.h" #include <utility> @@ -13,6 +13,8 @@ #include "content/public/browser/visibility.h" #include "content/public/browser/web_contents.h" +namespace visibility_timer { + WEB_CONTENTS_USER_DATA_KEY_IMPL(VisibilityTimerTabHelper); struct VisibilityTimerTabHelper::Task { @@ -27,8 +29,9 @@ const base::Location& from_here, base::OnceClosure task, base::TimeDelta visible_delay) { - if (web_contents()->IsBeingDestroyed()) + if (web_contents()->IsBeingDestroyed()) { return; + } task_queue_.push_back({visible_delay, from_here, std::move(task)}); @@ -41,10 +44,11 @@ void VisibilityTimerTabHelper::OnVisibilityChanged( content::Visibility visibility) { if (!task_queue_.empty()) { - if (visibility == content::Visibility::VISIBLE) + if (visibility == content::Visibility::VISIBLE) { StartNextTaskTimer(); - else + } else { timer_.Stop(); + } } } @@ -57,8 +61,9 @@ DCHECK_EQ(web_contents()->GetVisibility(), content::Visibility::VISIBLE); task_queue_.pop_front(); - if (!task_queue_.empty()) + if (!task_queue_.empty()) { StartNextTaskTimer(); + } std::move(task).Run(); } @@ -79,3 +84,5 @@ base::BindOnce(&VisibilityTimerTabHelper::RunTask, base::Unretained(this), std::move(callback_pair.second))); } + +} // namespace visibility_timer
diff --git a/chrome/browser/visibility_timer_tab_helper.h b/components/visibility_timer/visibility_timer_tab_helper.h similarity index 87% rename from chrome/browser/visibility_timer_tab_helper.h rename to components/visibility_timer/visibility_timer_tab_helper.h index 23702d1..3d43f9709 100644 --- a/chrome/browser/visibility_timer_tab_helper.h +++ b/components/visibility_timer/visibility_timer_tab_helper.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_VISIBILITY_TIMER_TAB_HELPER_H_ -#define CHROME_BROWSER_VISIBILITY_TIMER_TAB_HELPER_H_ +#ifndef COMPONENTS_VISIBILITY_TIMER_VISIBILITY_TIMER_TAB_HELPER_H_ +#define COMPONENTS_VISIBILITY_TIMER_VISIBILITY_TIMER_TAB_HELPER_H_ #include "base/containers/circular_deque.h" #include "base/functional/callback_forward.h" @@ -11,6 +11,8 @@ #include "content/public/browser/web_contents_observer.h" #include "content/public/browser/web_contents_user_data.h" +namespace visibility_timer { + // At most one of these is attached to each WebContents. It allows posting // delayed tasks whose timer only counts down whilst the WebContents is visible // (and whose timer is reset whenever the WebContents stops being visible). @@ -49,4 +51,6 @@ WEB_CONTENTS_USER_DATA_KEY_DECL(); }; -#endif // CHROME_BROWSER_VISIBILITY_TIMER_TAB_HELPER_H_ +} // namespace visibility_timer + +#endif // COMPONENTS_VISIBILITY_TIMER_VISIBILITY_TIMER_TAB_HELPER_H_
diff --git a/chrome/browser/visibility_timer_tab_helper_unittest.cc b/components/visibility_timer/visibility_timer_tab_helper_unittest.cc similarity index 90% rename from chrome/browser/visibility_timer_tab_helper_unittest.cc rename to components/visibility_timer/visibility_timer_tab_helper_unittest.cc index 1bcc582..895663a 100644 --- a/chrome/browser/visibility_timer_tab_helper_unittest.cc +++ b/components/visibility_timer/visibility_timer_tab_helper_unittest.cc
@@ -2,17 +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/visibility_timer_tab_helper.h" +#include "components/visibility_timer/visibility_timer_tab_helper.h" #include "base/test/bind.h" #include "base/test/task_environment.h" -#include "chrome/test/base/chrome_render_view_host_test_harness.h" #include "content/public/browser/web_contents.h" +#include "content/public/test/test_renderer_host.h" -class VisibilityTimerTabHelperTest : public ChromeRenderViewHostTestHarness { +namespace visibility_timer { + +class VisibilityTimerTabHelperTest : public content::RenderViewHostTestHarness { public: VisibilityTimerTabHelperTest() - : ChromeRenderViewHostTestHarness( + : content::RenderViewHostTestHarness( base::test::TaskEnvironment::TimeSource::MOCK_TIME) {} }; @@ -57,8 +59,9 @@ EXPECT_FALSE(task_executed); // But 5*500ms > 1 second, so it should now be blocked. - for (int n = 0; n < 4; n++) + for (int n = 0; n < 4; n++) { task_environment()->FastForwardBy(base::Milliseconds(500)); + } EXPECT_TRUE(task_executed); } @@ -95,3 +98,5 @@ EXPECT_EQ("12", tasks_executed); } + +} // namespace visibility_timer
diff --git a/components/webapps/README.md b/components/webapps/README.md new file mode 100644 index 0000000..706ef00 --- /dev/null +++ b/components/webapps/README.md
@@ -0,0 +1,7 @@ +# components/webapps + +This directory contains web applications (Progressive Web Apps) features and logic that are shared between Android and Desktop platforms. + +If you are looking for documentation specific to the overall Web Apps architecture, see the following: +* [Web Apps Core Concepts](/docs/webapps/README.md) - Universal and cross-platform Progressive Web App documentation. +* [Desktop `WebAppProvider`](/chrome/browser/web_applications/README.md) - Desktop-specific implementation details.
diff --git a/components/webapps/browser/android/app_banner_manager_android.cc b/components/webapps/browser/android/app_banner_manager_android.cc index 87e2330..e725d0ab 100644 --- a/components/webapps/browser/android/app_banner_manager_android.cc +++ b/components/webapps/browser/android/app_banner_manager_android.cc
@@ -51,10 +51,7 @@ // Must come after all headers that specialize FromJniType() / ToJniType(). #include "components/webapps/browser/android/webapps_jni_headers/AppBannerManager_jni.h" -using base::android::ConvertJavaStringToUTF16; -using base::android::ConvertJavaStringToUTF8; -using base::android::ConvertUTF16ToJavaString; -using base::android::ConvertUTF8ToJavaString; +using base::android::AttachCurrentThread; using base::android::JavaRef; namespace webapps { @@ -105,9 +102,9 @@ } AppBannerManagerAndroid::QueryNativeAppConfig::QueryNativeAppConfig( - const base::android::ScopedJavaLocalRef<jstring>& url, - const base::android::ScopedJavaLocalRef<jstring>& package, - const base::android::ScopedJavaLocalRef<jstring>& referrer) + const std::string& url, + const std::string& package, + const std::string& referrer) : url(url), package(package), referrer(referrer) {} AppBannerManagerAndroid::QueryNativeAppConfig::QueryNativeAppConfig( @@ -139,9 +136,9 @@ JNIEnv* env, int request_id, const JavaRef<jobject>& japp_data, - const JavaRef<jstring>& japp_title, - const JavaRef<jstring>& japp_package, - const JavaRef<jstring>& jicon_url) { + std::u16string&& app_title, + std::string&& app_package, + std::string&& icon_url) { // If the state isn't fetching native data, that means the page must have // navigated or reset in some way. if (app_banner_manager_->state() != @@ -156,9 +153,7 @@ } current_native_request_id_ = std::nullopt; native_java_app_data_.Reset(japp_data); - std::string app_package = ConvertJavaStringToUTF8(env, japp_package); - std::u16string app_title = ConvertJavaStringToUTF16(env, japp_title); - GURL primary_icon_url = GURL(ConvertJavaStringToUTF8(env, jicon_url)); + GURL primary_icon_url = GURL(icon_url); if (app_package.empty()) { std::move(native_check_callback_storage_) @@ -272,15 +267,15 @@ InstallableStatusCode code = InstallableStatusCode::NO_ERROR_DETECTED; for (const auto& application : manifest.related_applications) { - JNIEnv* env = base::android::AttachCurrentThread(); base::expected<QueryNativeAppConfig, InstallableStatusCode> result = - GetNativeAppFetchRequestConfig(validated_url, env, application); + GetNativeAppFetchRequestConfig(validated_url, application); if (!result.has_value()) { code = result.error(); continue; } + JNIEnv* env = AttachCurrentThread(); TrackDisplayEvent(DISPLAY_EVENT_NATIVE_APP_BANNER_REQUESTED); // Send the info to the Java side to get info about the app. // This async call will run OnAppDetailsRetrieved() when completed. @@ -323,10 +318,8 @@ return false; } - JNIEnv* env = base::android::AttachCurrentThread(); - base::android::ScopedJavaLocalRef<jstring> java_id( - ConvertUTF16ToJavaString(env, related_app.id.value())); - return Java_AppBannerManager_isRelatedNonWebAppInstalled(env, java_id); + return Java_AppBannerManager_isRelatedNonWebAppInstalled( + AttachCurrentThread(), related_app.id.value()); } void AppBannerManagerAndroid::MaybeShowAmbientBadge( @@ -574,7 +567,6 @@ InstallableStatusCode> AppBannerManagerAndroid::GetNativeAppFetchRequestConfig( const GURL& validated_url, - JNIEnv* env, const blink::Manifest::RelatedApplication& related_application) const { if (!related_application.platform.has_value() || !base::EqualsASCII(related_application.platform.value(), kPlatformPlay)) { @@ -621,14 +613,7 @@ } referrer += "playinline=chrome_inline"; - base::android::ScopedJavaLocalRef<jstring> jurl( - ConvertUTF8ToJavaString(env, validated_url.spec())); - base::android::ScopedJavaLocalRef<jstring> jpackage( - ConvertUTF8ToJavaString(env, id)); - base::android::ScopedJavaLocalRef<jstring> jreferrer( - ConvertUTF8ToJavaString(env, referrer)); - - return QueryNativeAppConfig(jurl, jpackage, jreferrer); + return QueryNativeAppConfig(validated_url.spec(), id, referrer); } void AppBannerManagerAndroid::OnNativeAppIconFetched(std::string app_package, @@ -705,29 +690,24 @@ static base::android::ScopedJavaLocalRef<jobject> JNI_AppBannerManager_GetJavaBannerManagerForWebContents( JNIEnv* env, - const JavaRef<jobject>& java_web_contents) { - auto* manager = AppBannerManagerAndroid::FromWebContents( - content::WebContents::FromJavaWebContents(java_web_contents)); + content::WebContents* web_contents) { + auto* manager = AppBannerManagerAndroid::FromWebContents(web_contents); return manager ? manager->GetJavaBannerManager() : base::android::ScopedJavaLocalRef<jobject>(); } // static -static base::android::ScopedJavaLocalRef<jstring> -JNI_AppBannerManager_GetInstallableWebAppManifestId( +static std::string JNI_AppBannerManager_GetInstallableWebAppManifestId( JNIEnv* env, - const base::android::JavaRef<jobject>& java_web_contents) { - return base::android::ConvertUTF8ToJavaString( - env, AppBannerManager::GetInstallableWebAppManifestId( - content::WebContents::FromJavaWebContents(java_web_contents))); + content::WebContents* web_contents) { + return AppBannerManager::GetInstallableWebAppManifestId(web_contents); } // static static bool JNI_AppBannerManager_IsProbablyPromotable( JNIEnv* env, - const base::android::JavaRef<jobject>& java_web_contents) { - auto* manager = AppBannerManager::FromWebContents( - content::WebContents::FromJavaWebContents(java_web_contents)); + content::WebContents* web_contents) { + auto* manager = AppBannerManager::FromWebContents(web_contents); if (!manager) { return false; }
diff --git a/components/webapps/browser/android/app_banner_manager_android.h b/components/webapps/browser/android/app_banner_manager_android.h index e3983db..dcec35b 100644 --- a/components/webapps/browser/android/app_banner_manager_android.h +++ b/components/webapps/browser/android/app_banner_manager_android.h
@@ -119,13 +119,12 @@ // Called when the Java-side has retrieved information for the app. // Returns |false| if an icon fetch couldn't be kicked off. - void OnAppDetailsRetrieved( - JNIEnv* env, - int request_id, - const base::android::JavaRef<jobject>& japp_data, - const base::android::JavaRef<jstring>& japp_title, - const base::android::JavaRef<jstring>& japp_package, - const base::android::JavaRef<jstring>& jicon_url); + void OnAppDetailsRetrieved(JNIEnv* env, + int request_id, + const base::android::JavaRef<jobject>& japp_data, + std::u16string&& app_title, + std::string&& app_package, + std::string&& icon_url); void ShowBannerFromBadge(const InstallBannerConfig& config); @@ -202,16 +201,15 @@ friend class content::WebContentsUserData<AppBannerManagerAndroid>; struct QueryNativeAppConfig { - QueryNativeAppConfig( - const base::android::ScopedJavaLocalRef<jstring>& url, - const base::android::ScopedJavaLocalRef<jstring>& package, - const base::android::ScopedJavaLocalRef<jstring>& referrer); + QueryNativeAppConfig(const std::string& url, + const std::string& package, + const std::string& referrer); QueryNativeAppConfig(const QueryNativeAppConfig& config); ~QueryNativeAppConfig(); - base::android::ScopedJavaLocalRef<jstring> url; - base::android::ScopedJavaLocalRef<jstring> package; - base::android::ScopedJavaLocalRef<jstring> referrer; + std::string url; + std::string package; + std::string referrer; }; // Creates the Java-side AppBannerManager. @@ -226,7 +224,6 @@ base::expected<QueryNativeAppConfig, InstallableStatusCode> GetNativeAppFetchRequestConfig( const GURL& validated_url, - JNIEnv* env, const blink::Manifest::RelatedApplication& related_application) const; // Called when the download of a native app's icon is complete, as native
diff --git a/components/webapps/browser/android/java/src/org/chromium/components/webapps/AppBannerManager.java b/components/webapps/browser/android/java/src/org/chromium/components/webapps/AppBannerManager.java index 5380522..98dc1eb 100644 --- a/components/webapps/browser/android/java/src/org/chromium/components/webapps/AppBannerManager.java +++ b/components/webapps/browser/android/java/src/org/chromium/components/webapps/AppBannerManager.java
@@ -12,6 +12,7 @@ import org.jni_zero.CalledByNative; import org.jni_zero.JNINamespace; +import org.jni_zero.JniType; import org.jni_zero.NativeMethods; import org.chromium.base.ContextUtils; @@ -131,7 +132,11 @@ */ @CalledByNative private void fetchAppDetails( - int requestId, String url, String packageName, String referrer, int iconSizeInDp) { + int requestId, + @JniType("std::string") String url, + @JniType("std::string") String packageName, + @JniType("std::string") String referrer, + int iconSizeInDp) { if (sAppDetailsDelegate == null) return; Context context = ContextUtils.getApplicationContext(); @@ -142,7 +147,8 @@ } @CalledByNative - private static boolean isRelatedNonWebAppInstalled(String packageName) { + private static boolean isRelatedNonWebAppInstalled( + @JniType("std::u16string") String packageName) { return PackageUtils.isPackageInstalled(packageName); } @@ -177,7 +183,8 @@ * Returns the manifest id if the current page is installable, otherwise returns the empty * string. */ - public static @Nullable String maybeGetManifestId(WebContents webContents) { + public static @Nullable String maybeGetManifestId( + @JniType("content::WebContents*") WebContents webContents) { AppBannerManager manager = webContents != null ? AppBannerManager.forWebContents(webContents) : null; if (manager != null) { @@ -187,7 +194,8 @@ } /** Returns true if the web app can be promoted into an installable application. */ - public static boolean isProbablyPromotable(WebContents webContents) { + public static boolean isProbablyPromotable( + @JniType("content::WebContents*") WebContents webContents) { return AppBannerManagerJni.get().isProbablyPromotable(webContents); } @@ -227,12 +235,13 @@ } /** Returns the AppBannerManager object. This is owned by the C++ banner manager. */ - public static AppBannerManager forWebContents(WebContents contents) { + public static AppBannerManager forWebContents( + @JniType("content::WebContents*") WebContents contents) { ThreadUtils.assertOnUiThread(); return AppBannerManagerJni.get().getJavaBannerManagerForWebContents(contents); } - public String getManifestId(WebContents contents) { + public String getManifestId(@JniType("content::WebContents*") WebContents contents) { return AppBannerManagerJni.get().getInstallableWebAppManifestId(contents); } @@ -247,17 +256,20 @@ @NativeMethods @VisibleForTesting public interface Natives { - AppBannerManager getJavaBannerManagerForWebContents(WebContents webContents); + AppBannerManager getJavaBannerManagerForWebContents( + @JniType("content::WebContents*") WebContents webContents); - String getInstallableWebAppManifestId(WebContents webContents); + @JniType("std::string") + String getInstallableWebAppManifestId( + @JniType("content::WebContents*") WebContents webContents); void onAppDetailsRetrieved( long nativeAppBannerManagerAndroid, int requestId, AppData data, - @Nullable String title, - String packageName, - @Nullable String imageUrl); + @JniType("std::u16string") @Nullable String title, + @JniType("std::string") String packageName, + @JniType("std::string") @Nullable String imageUrl); // Testing methods. void ignoreChromeChannelForTesting(); @@ -274,6 +286,6 @@ void setOverrideSegmentationResultForTesting(boolean show); - boolean isProbablyPromotable(WebContents contents); + boolean isProbablyPromotable(@JniType("content::WebContents*") WebContents contents); } }
diff --git a/components/webauthn/core/browser/passkey_model_utils.cc b/components/webauthn/core/browser/passkey_model_utils.cc index 711a2e6..aba35f3 100644 --- a/components/webauthn/core/browser/passkey_model_utils.cc +++ b/components/webauthn/core/browser/passkey_model_utils.cc
@@ -22,7 +22,7 @@ #include "components/sync/protocol/webauthn_credential_specifics.pb.h" #include "crypto/aead.h" #include "crypto/hash.h" -#include "crypto/hkdf.h" +#include "crypto/kdf.h" #include "crypto/keypair.h" #include "crypto/random.h" #include "crypto/sign.h" @@ -91,8 +91,8 @@ base::span<const uint8_t> trusted_vault_key) { constexpr std::string_view kHkdfInfo = "KeychainApplicationKey:gmscore_module:com.google.android.gms.fido"; - return crypto::HkdfSha256<kEncryptionSecretSize>( - trusted_vault_key, + return crypto::kdf::Hkdf<kEncryptionSecretSize>( + crypto::hash::kSha256, trusted_vault_key, /*salt=*/base::span<const uint8_t>(), base::as_bytes(base::span(kHkdfInfo))); } @@ -101,8 +101,8 @@ base::span<const uint8_t> private_key) { CHECK(!private_key.empty()); constexpr std::string_view kHkdfInfo = "derived PRF HMAC secret"; - return crypto::HkdfSha256<kEncryptionSecretSize>( - private_key, + return crypto::kdf::Hkdf<kHmacSecretSize>( + crypto::hash::kSha256, private_key, /*salt=*/base::span<const uint8_t>(), base::as_bytes(base::span(kHkdfInfo))); }
diff --git a/components/webauthn/ios/resources/passkey_controller.ts b/components/webauthn/ios/resources/passkey_controller.ts index ce7b4fd..42ca6fb 100644 --- a/components/webauthn/ios/resources/passkey_controller.ts +++ b/components/webauthn/ios/resources/passkey_controller.ts
@@ -632,8 +632,12 @@ // eslint-disable-next-line @typescript-eslint/explicit-member-accessibility public promise: Promise<PublicKeyCredential>; // Resolve function of the deferred promise. + // TODO(crbug.com/493624186): Fix members asserted as non-null . + /* eslint-disable-next-line no-restricted-syntax */ private resolve!: ResolveFunction<PublicKeyCredential>; // Reject function of the deferred promise. + // TODO(crbug.com/493624186): Fix members asserted as non-null . + /* eslint-disable-next-line no-restricted-syntax */ private reject!: RejectFunction; // Unique ID for this deferred promise. // eslint-disable-next-line @typescript-eslint/explicit-member-accessibility
diff --git a/components/webxr/android/openxr_platform_helper_android.cc b/components/webxr/android/openxr_platform_helper_android.cc index 93ef365..ef08a7d 100644 --- a/components/webxr/android/openxr_platform_helper_android.cc +++ b/components/webxr/android/openxr_platform_helper_android.cc
@@ -97,10 +97,6 @@ bool OpenXrPlatformHelperAndroid::CheckHardwareSupport( content::WebContents* web_contents) { - if (!device::features::IsOpenXrArEnabled()) { - return true; - } - XrInstance instance = XR_NULL_HANDLE; if (!XR_SUCCEEDED(CreateTemporaryInstance(&instance, web_contents))) { return false;
diff --git a/content/browser/child_process_security_policy_impl.h b/content/browser/child_process_security_policy_impl.h index e8f4b94c..5d08a5ae 100644 --- a/content/browser/child_process_security_policy_impl.h +++ b/content/browser/child_process_security_policy_impl.h
@@ -438,22 +438,12 @@ // this method exactly once. This call must be made on the UI thread. void Add(ChildProcessId child_id, BrowserContext* browser_context); - // TODO(crbug.com/379869738) Remove this method when usages are ported. - inline void Add(int child_id, BrowserContext* browser_context) { - Add(ChildProcessId::FromUnsafeValue(child_id), browser_context); - } - // Helper method for unit tests that calls Add() and // LockProcess() with an "allow_any_site" lock. This ensures that the process // policy is always in a state where it is valid to call // CanAccessDataForOrigin(). void AddForTesting(ChildProcessId child_id, BrowserContext* browser_context); - // TODO(crbug.com/379869738) Remove this method when usages are ported. - inline void AddForTesting(int child_id, BrowserContext* browser_context) { - AddForTesting(ChildProcessId::FromUnsafeValue(child_id), browser_context); - } - // Upon destruction, child processes should unregister themselves by calling // this method exactly once. This call must be made on the UI thread. // @@ -465,11 +455,6 @@ // revoked. void Remove(ChildProcessId child_id); - // TODO(crbug.com/379869738) Remove this method when usages are ported. - inline void Remove(int child_id) { - Remove(ChildProcessId::FromUnsafeValue(child_id)); - } - // Whenever the browser processes commands the child process to commit a URL, // it should call this method to grant the child process the capability to // commit anything from the URL's origin, along with permission to request all
diff --git a/content/browser/child_process_security_policy_unittest.cc b/content/browser/child_process_security_policy_unittest.cc index 7ea843d..74af087 100644 --- a/content/browser/child_process_security_policy_unittest.cc +++ b/content/browser/child_process_security_policy_unittest.cc
@@ -3148,16 +3148,18 @@ /*is_fenced=*/false, /*is_fixed_storage_partition=*/false); - p->Add(kRendererID, &context); + p->Add(kRendererProcess, &context); p->LockProcess(foo_instance->GetIsolationContext(), kRendererProcess, /*is_process_used=*/false, ProcessLock::FromSiteInfo(foo_instance->GetSiteInfo())); p->AddCommittedOrigin(kRendererID, foo); - EXPECT_TRUE(p->GetProcessLock(kRendererID).IsLockedToSite()); - EXPECT_TRUE( - p->GetProcessLock(kRendererID).agent_cluster_key().IsOriginKeyed()); - EXPECT_EQ(foo.GetURL(), p->GetProcessLock(kRendererID).GetProcessLockURL()); + EXPECT_TRUE(p->GetProcessLock(kRendererProcess).IsLockedToSite()); + EXPECT_TRUE(p->GetProcessLock(kRendererProcess) + .agent_cluster_key() + .IsOriginKeyed()); + EXPECT_EQ(foo.GetURL(), + p->GetProcessLock(kRendererProcess).GetProcessLockURL()); EXPECT_TRUE(ProcessLock::FromSiteInfo(foo_instance->GetSiteInfo()) .agent_cluster_key() @@ -3199,7 +3201,7 @@ // Create a SiteInstance for sub.foo.com in a new BrowsingInstance. TestBrowserContext context; { - p->Add(kRendererID, &context); + p->Add(kRendererProcess, &context); // Isolate foo.com so we can't get a default SiteInstance. This will mean // that https://sub.foo.com will end up in a site-keyed SiteInstance, which // is what we need. @@ -3218,13 +3220,15 @@ ProcessLock::FromSiteInfo(foo_instance->GetSiteInfo())); p->AddCommittedOrigin(kRendererID, sub_foo_origin); - EXPECT_TRUE(p->GetProcessLock(kRendererID).IsLockedToSite()); + EXPECT_TRUE(p->GetProcessLock(kRendererProcess).IsLockedToSite()); // Note: This might become true in the future if we convert legacy isolated // origins to create origin-keyed AgentClusterKeys instead of site-keyed. - EXPECT_FALSE( - p->GetProcessLock(kRendererID).agent_cluster_key().IsOriginKeyed()); - EXPECT_EQ(SiteInfo::GetSiteForOrigin(sub_foo_origin), - p->GetProcessLock(kRendererID).agent_cluster_key().GetSite()); + EXPECT_FALSE(p->GetProcessLock(kRendererProcess) + .agent_cluster_key() + .IsOriginKeyed()); + EXPECT_EQ( + SiteInfo::GetSiteForOrigin(sub_foo_origin), + p->GetProcessLock(kRendererProcess).agent_cluster_key().GetSite()); EXPECT_FALSE(ProcessLock::FromSiteInfo(foo_instance->GetSiteInfo()) .agent_cluster_key()
diff --git a/content/browser/devtools/devtools_http_handler.cc b/content/browser/devtools/devtools_http_handler.cc index 79bf965..f6fa7d52 100644 --- a/content/browser/devtools/devtools_http_handler.cc +++ b/content/browser/devtools/devtools_http_handler.cc
@@ -348,6 +348,8 @@ std::string GetTypeForMetrics() override { return "RemoteDebugger"; } + bool MayAccessAllCookies() override { return true; } + void AgentHostClosed(DevToolsAgentHost* agent_host) override { DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK(agent_host == agent_host_.get());
diff --git a/content/browser/devtools/devtools_pipe_handler.cc b/content/browser/devtools/devtools_pipe_handler.cc index 2a75e6f..b15a18e5 100644 --- a/content/browser/devtools/devtools_pipe_handler.cc +++ b/content/browser/devtools/devtools_pipe_handler.cc
@@ -463,6 +463,10 @@ void DevToolsPipeHandler::AgentHostClosed(DevToolsAgentHost* agent_host) {} +bool DevToolsPipeHandler::MayAccessAllCookies() { + return true; +} + bool DevToolsPipeHandler::UsesBinaryProtocol() { return mode_ == ProtocolMode::kCBOR; }
diff --git a/content/browser/devtools/devtools_pipe_handler.h b/content/browser/devtools/devtools_pipe_handler.h index 4615515..6263c0a8 100644 --- a/content/browser/devtools/devtools_pipe_handler.h +++ b/content/browser/devtools/devtools_pipe_handler.h
@@ -33,6 +33,7 @@ void DispatchProtocolMessage(DevToolsAgentHost* agent_host, base::span<const uint8_t> message) override; void AgentHostClosed(DevToolsAgentHost* agent_host) override; + bool MayAccessAllCookies() override; bool UsesBinaryProtocol() override; bool AllowUnsafeOperations() override; std::string GetTypeForMetrics() override;
diff --git a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc index 7065a09..a1b18ab 100644 --- a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc +++ b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
@@ -2765,6 +2765,43 @@ EXPECT_EQ(2u, found); } +IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, + ClearBrowserCookiesWithAllCookieAccess) { + ASSERT_TRUE(embedded_test_server()->Start()); + GURL main_page_url = embedded_test_server()->GetURL("a.test", "/title1.html"); + NavigateToURLBlockUntilNavigationsComplete(shell(), main_page_url, 1); + Attach(); + + // Set cookies on two different hosts via the protocol. + base::DictValue set_cookies_params; + base::ListValue cookies_list; + base::DictValue cookie_a; + cookie_a.Set("name", "cookie_a"); + cookie_a.Set("value", "value_a"); + cookie_a.Set("url", embedded_test_server()->GetURL("a.test", "/").spec()); + cookies_list.Append(std::move(cookie_a)); + base::DictValue cookie_b; + cookie_b.Set("name", "cookie_b"); + cookie_b.Set("value", "value_b"); + cookie_b.Set("url", embedded_test_server()->GetURL("b.test", "/").spec()); + cookies_list.Append(std::move(cookie_b)); + set_cookies_params.Set("cookies", std::move(cookies_list)); + SendCommandSync("Network.setCookies", std::move(set_cookies_params)); + EXPECT_FALSE(error()); + + const base::ListValue* cookies = + SendCommandSync("Network.getAllCookies")->FindList("cookies"); + ASSERT_TRUE(cookies); + EXPECT_EQ(2u, cookies->size()); + + SendCommandSync("Network.clearBrowserCookies"); + EXPECT_FALSE(error()); + + cookies = SendCommandSync("Network.getAllCookies")->FindList("cookies"); + ASSERT_TRUE(cookies); + EXPECT_TRUE(cookies->empty()); +} + IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, CookiePermissions) { SetNotAttachableHosts({"b.test"}); content::SetupCrossSiteRedirector(embedded_test_server());
diff --git a/content/browser/devtools/protocol/network_handler.cc b/content/browser/devtools/protocol/network_handler.cc index 673fdb06..e41fe47 100644 --- a/content/browser/devtools/protocol/network_handler.cc +++ b/content/browser/devtools/protocol/network_handler.cc
@@ -2415,12 +2415,22 @@ bool is_webui, base::OnceClosure callback) { auto* cookie_manager = storage_partition->GetCookieManagerForBrowserProcess(); - cookie_manager->GetAllCookies( - base::BindOnce(&DeleteFilteredCookies, base::Unretained(cookie_manager), - /*name=*/std::nullopt, /*normalized_domain=*/std::nullopt, - /*path=*/std::nullopt, /*partition_key=*/nullptr, - /*filter_by_partition_key=*/false, std::ref(client), - is_webui, std::move(callback))); + + if (client.MayAccessAllCookies()) { + // Unrestricted clients can clear all cookies atomically. + cookie_manager->DeleteCookies( + network::mojom::CookieDeletionFilter::New(), + base::BindOnce(base::IgnoreArgs<uint32_t>(std::move(callback)))); + } else { + // Restricted clients must filter by URL permissions before deletion. + cookie_manager->GetAllCookies( + base::BindOnce(&DeleteFilteredCookies, base::Unretained(cookie_manager), + /*name=*/std::nullopt, + /*normalized_domain=*/std::nullopt, + /*path=*/std::nullopt, /*partition_key=*/nullptr, + /*filter_by_partition_key=*/false, std::ref(client), + is_webui, std::move(callback))); + } } // static
diff --git a/content/browser/devtools/protocol/target_handler.cc b/content/browser/devtools/protocol/target_handler.cc index 18f066a..38b73db 100644 --- a/content/browser/devtools/protocol/target_handler.cc +++ b/content/browser/devtools/protocol/target_handler.cc
@@ -201,6 +201,8 @@ connector_->AgentHostClosed(agent_host); } + bool MayAccessAllCookies() override { return true; } + bool AllowUnsafeOperations() override { return permissions_.allow_unsafe_operations; } @@ -606,6 +608,8 @@ Detach(true); } + bool MayAccessAllCookies() override { return true; } + bool MayAttachToURL(const GURL& url, bool is_webui) override { return GetRootClient()->MayAttachToURL(url, is_webui); }
diff --git a/content/browser/file_system/browser_file_system_helper_unittest.cc b/content/browser/file_system/browser_file_system_helper_unittest.cc index a7172f4..7c36bba 100644 --- a/content/browser/file_system/browser_file_system_helper_unittest.cc +++ b/content/browser/file_system/browser_file_system_helper_unittest.cc
@@ -53,7 +53,7 @@ TestBrowserContext browser_context; ChildProcessSecurityPolicyImpl* p = ChildProcessSecurityPolicyImpl::GetInstance(); - p->AddForTesting(kRendererID, &browser_context); + p->AddForTesting(kRendererProcess, &browser_context); // Prepare |original_file| FileSystemURL that comes from a |sensitive_origin|. // This attempts to simulate for unit testing the drive URL from @@ -144,7 +144,7 @@ EXPECT_FALSE(p->CanCopyIntoFileSystemFile(kRendererProcess, dropped_file)); EXPECT_FALSE(p->CanDeleteFileSystemFile(kRendererProcess, dropped_file)); - p->Remove(kRendererID); + p->Remove(kRendererProcess); } TEST(BrowserFileSystemHelperTest, PrepareDropDataForChildProcess_LocalFiles) { @@ -173,7 +173,7 @@ TestBrowserContext browser_context; ChildProcessSecurityPolicyImpl* p = ChildProcessSecurityPolicyImpl::GetInstance(); - p->AddForTesting(kRendererID, &browser_context); + p->AddForTesting(kRendererProcess, &browser_context); // Prepare content::DropData containing some local files. const base::FilePath kDraggedFile = @@ -224,7 +224,7 @@ EXPECT_FALSE( p->CanCommitURL(kRendererID, net::FilePathToFileURL(kOtherFile))); - p->Remove(kRendererID); + p->Remove(kRendererProcess); SetBrowserClientForTesting(old_browser_client); }
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc index b6ccb19..33d730f5 100644 --- a/content/browser/loader/navigation_url_loader_impl.cc +++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -1369,8 +1369,7 @@ std::move(factory), global_request_id_.request_id, options, resource_request_.get(), GetUIThreadTaskRunner({BrowserTaskType::kNavigationNetworkResponse}), - /*cors_exempt_header_list=*/std::nullopt, - &request_info_->common_params->initiator_origin_trial_features); + /*cors_exempt_header_list=*/std::nullopt); } const network::ResourceRequest&
diff --git a/content/browser/preloading/prefetch/prefetch_service_unittest.cc b/content/browser/preloading/prefetch/prefetch_service_unittest.cc index 57772cf..29cbc00 100644 --- a/content/browser/preloading/prefetch/prefetch_service_unittest.cc +++ b/content/browser/preloading/prefetch/prefetch_service_unittest.cc
@@ -616,7 +616,7 @@ void VerifyIsolationInfo(const net::IsolationInfo& isolation_info) { EXPECT_FALSE(isolation_info.IsEmpty()); - EXPECT_TRUE(isolation_info.network_isolation_key().IsFullyPopulated()); + EXPECT_FALSE(isolation_info.network_isolation_key().IsEmpty()); EXPECT_FALSE(isolation_info.network_isolation_key().IsTransient()); EXPECT_FALSE(isolation_info.site_for_cookies().IsNull()); } @@ -3986,11 +3986,6 @@ {"Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.NotServed.", histogram_suffix}), 0); - histogram_tester.ExpectTotalCount( - base::StrCat( - {"Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.NotServed.", - histogram_suffix}), - 0); histogram_tester.ExpectUniqueSample( base::StrCat( {"Prefetch.PrefetchMatchingBlockedNavigation.PerMatchingCandidate.",
diff --git a/content/browser/preloading/prerender/prerender_handle_impl.cc b/content/browser/preloading/prerender/prerender_handle_impl.cc index 38ae62e..52605f1 100644 --- a/content/browser/preloading/prerender/prerender_handle_impl.cc +++ b/content/browser/preloading/prerender/prerender_handle_impl.cc
@@ -18,12 +18,6 @@ namespace { -int32_t GetNextHandleId() { - static int32_t next_handle_id = 1; - CHECK_LT(next_handle_id, std::numeric_limits<int32_t>::max()); - return next_handle_id++; -} - // Returns true when the error callback should be fired. The callback does not // need to be fired when prerendering succeed but is never activated, or it is // intentinally cancelled by an embedder (e.g., calling the cancellation API). @@ -156,8 +150,7 @@ PrerenderHostId prerender_host_id, const GURL& prerendering_url, std::optional<net::HttpNoVarySearchData> no_vary_search_hint) - : handle_id_(GetNextHandleId()), - prerender_host_id_(prerender_host_id), + : prerender_host_id_(prerender_host_id), prerender_host_registry_(std::move(prerender_host_registry)), prerendering_url_(prerendering_url), no_vary_search_hint_(std::move(no_vary_search_hint)) { @@ -178,10 +171,6 @@ } } -int32_t PrerenderHandleImpl::GetHandleId() const { - return handle_id_; -} - PrerenderHostId PrerenderHandleImpl::GetPrerenderHostId() const { return prerender_host_id_; }
diff --git a/content/browser/preloading/prerender/prerender_handle_impl.h b/content/browser/preloading/prerender/prerender_handle_impl.h index 7e0a1ca..f3f321d 100644 --- a/content/browser/preloading/prerender/prerender_handle_impl.h +++ b/content/browser/preloading/prerender/prerender_handle_impl.h
@@ -30,7 +30,6 @@ ~PrerenderHandleImpl() override; // PrerenderHandle: - int32_t GetHandleId() const override; PrerenderHostId GetPrerenderHostId() const override; const GURL& GetInitialPrerenderingUrl() const override; const std::optional<net::HttpNoVarySearchData>& GetNoVarySearchHint() @@ -56,7 +55,6 @@ } private: - const int handle_id_; const PrerenderHostId prerender_host_id_; base::WeakPtr<PrerenderHostRegistry> prerender_host_registry_;
diff --git a/content/browser/renderer_host/code_cache_host_impl.cc b/content/browser/renderer_host/code_cache_host_impl.cc index a255629..f8116be 100644 --- a/content/browser/renderer_host/code_cache_host_impl.cc +++ b/content/browser/renderer_host/code_cache_host_impl.cc
@@ -57,7 +57,7 @@ }; bool CheckSecurityForAccessingCodeCacheData(const GURL& resource_url, - int render_process_id, + ChildProcessId render_process_id, Operation operation) { if (!resource_url.is_valid()) { return false; @@ -132,7 +132,7 @@ // Case 4. origin_lock if the scheme of origin_lock is // Http/Https/chrome/chrome-untrusted. // Case 5. std::nullopt otherwise. -std::optional<GURL> GetOriginLock(int render_process_id) { +std::optional<GURL> GetOriginLock(ChildProcessId render_process_id) { ProcessLock process_lock = ChildProcessSecurityPolicyImpl::GetInstance()->GetProcessLock( render_process_id); @@ -193,7 +193,7 @@ base::Time expected_response_time, mojo_base::BigBuffer data, const std::string& cache_storage_cache_name, - int render_process_id, + ChildProcessId render_process_id, const blink::StorageKey& code_cache_storage_key, storage::mojom::CacheStorageControl* cache_storage_control_for_testing, mojo::ReportBadMessageCallback bad_message_callback) { @@ -258,7 +258,7 @@ void AddCodeCacheReceiver( mojo::UniqueReceiverSet<blink::mojom::CodeCacheHost>* receiver_set, scoped_refptr<GeneratedCodeCacheContext> context, - int render_process_id, + ChildProcessId render_process_id, const net::NetworkIsolationKey& nik, const blink::StorageKey& storage_key, mojo::PendingReceiver<blink::mojom::CodeCacheHost> receiver, @@ -279,7 +279,7 @@ class NoopCodeCacheHost : public CodeCacheHostImpl { public: NoopCodeCacheHost( - int render_process_id, + ChildProcessId render_process_id, scoped_refptr<GeneratedCodeCacheContext> generated_code_cache_context, const net::NetworkIsolationKey& nik, const blink::StorageKey& storage_key) @@ -316,7 +316,7 @@ class LocalCodeCacheHost : public CodeCacheHostImpl { public: LocalCodeCacheHost( - int render_process_id, + ChildProcessId render_process_id, scoped_refptr<GeneratedCodeCacheContext> generated_code_cache_context, const net::NetworkIsolationKey& nik, const blink::StorageKey& storage_key) @@ -433,7 +433,7 @@ // Case 4. std::nullopt otherwise. static std::optional<GURL> GetSecondaryKeyForCodeCache( const GURL& resource_url, - int render_process_id, + ChildProcessId render_process_id, Operation operation) { if (use_empty_secondary_key_for_testing_) { return GURL(); @@ -480,7 +480,7 @@ class CodeCacheWithPersistentCacheHost : public CodeCacheHostImpl { public: CodeCacheWithPersistentCacheHost( - int render_process_id, + ChildProcessId render_process_id, scoped_refptr<GeneratedCodeCacheContext> generated_code_cache_context, const net::NetworkIsolationKey& nik, const blink::StorageKey& storage_key) @@ -663,7 +663,7 @@ CodeCacheHostImpl::ReceiverSet::~ReceiverSet() = default; void CodeCacheHostImpl::ReceiverSet::Add( - int render_process_id, + ChildProcessId render_process_id, const net::NetworkIsolationKey& nik, const blink::StorageKey& storage_key, mojo::PendingReceiver<blink::mojom::CodeCacheHost> receiver, @@ -684,7 +684,7 @@ } void CodeCacheHostImpl::ReceiverSet::Add( - int render_process_id, + ChildProcessId render_process_id, const net::NetworkIsolationKey& nik, const blink::StorageKey& storage_key, mojo::PendingReceiver<blink::mojom::CodeCacheHost> receiver) { @@ -699,7 +699,7 @@ // CodeCacheHostImpl ----------------------------------------------------------- std::unique_ptr<CodeCacheHostImpl> CodeCacheHostImpl::Create( - int render_process_id, + ChildProcessId render_process_id, scoped_refptr<GeneratedCodeCacheContext> generated_code_cache_context, const net::NetworkIsolationKey& nik, const blink::StorageKey& storage_key) { @@ -738,7 +738,7 @@ } CodeCacheHostImpl::CodeCacheHostImpl( - int render_process_id, + ChildProcessId render_process_id, scoped_refptr<GeneratedCodeCacheContext> generated_code_cache_context, const net::NetworkIsolationKey& nik, const blink::StorageKey& storage_key)
diff --git a/content/browser/renderer_host/code_cache_host_impl.h b/content/browser/renderer_host/code_cache_host_impl.h index 11bd58a..f96eee6 100644 --- a/content/browser/renderer_host/code_cache_host_impl.h +++ b/content/browser/renderer_host/code_cache_host_impl.h
@@ -14,6 +14,7 @@ #include "build/build_config.h" #include "components/services/storage/public/mojom/cache_storage_control.mojom-forward.h" #include "content/common/content_export.h" +#include "content/public/common/child_process_id.h" #include "mojo/public/cpp/base/big_buffer.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/receiver_set.h" @@ -72,12 +73,12 @@ CodeCacheHostImpl*, mojo::ReceiverId, mojo::UniqueReceiverSet<blink::mojom::CodeCacheHost>&)>; - void Add(int render_process_id, + void Add(ChildProcessId render_process_id, const net::NetworkIsolationKey& nik, const blink::StorageKey& storage_key, mojo::PendingReceiver<blink::mojom::CodeCacheHost> receiver, CodeCacheHostReceiverHandler handler); - void Add(int render_process_id, + void Add(ChildProcessId render_process_id, const net::NetworkIsolationKey& nik, const blink::StorageKey& storage_key, mojo::PendingReceiver<blink::mojom::CodeCacheHost> receiver); @@ -95,7 +96,7 @@ // should be used by the fetch requests. This could be null in tests that use // SetCacheStorageControlForTesting. static std::unique_ptr<CodeCacheHostImpl> Create( - int render_process_id, + ChildProcessId render_process_id, scoped_refptr<GeneratedCodeCacheContext> generated_code_cache_context, const net::NetworkIsolationKey& nik, const blink::StorageKey& storage_key); @@ -112,12 +113,12 @@ protected: CodeCacheHostImpl( - int render_process_id, + ChildProcessId render_process_id, scoped_refptr<GeneratedCodeCacheContext> generated_code_cache_context, const net::NetworkIsolationKey& nik, const blink::StorageKey& storage_key); - int render_process_id() const { return render_process_id_; } + ChildProcessId render_process_id() const { return render_process_id_; } GeneratedCodeCacheContext* generated_code_cache_context() { return generated_code_cache_context_.get(); @@ -148,7 +149,7 @@ const std::string& cache_storage_cache_name) override; // Our render process host ID, used to bind to the correct render process. - const int render_process_id_; + const ChildProcessId render_process_id_; const scoped_refptr<GeneratedCodeCacheContext> generated_code_cache_context_;
diff --git a/content/browser/renderer_host/code_cache_host_impl_unittest.cc b/content/browser/renderer_host/code_cache_host_impl_unittest.cc index 661bf0b..857cb82 100644 --- a/content/browser/renderer_host/code_cache_host_impl_unittest.cc +++ b/content/browser/renderer_host/code_cache_host_impl_unittest.cc
@@ -63,7 +63,7 @@ ChildProcessSecurityPolicyImpl* p = ChildProcessSecurityPolicyImpl::GetInstance(); - for (int renderer_id : added_renderers_) { + for (auto renderer_id : added_renderers_) { p->Remove(renderer_id); } } @@ -77,7 +77,7 @@ bool IsSitePerProcessOrStricter() { return GetParam(); } - void SetupRendererWithLock(int process_id, const GURL& url) { + void SetupRendererWithLock(ChildProcessId process_id, const GURL& url) { ChildProcessSecurityPolicyImpl* p = ChildProcessSecurityPolicyImpl::GetInstance(); p->AddForTesting(process_id, &browser_context_); @@ -85,8 +85,7 @@ scoped_refptr<SiteInstanceImpl> site_instance = SiteInstanceImpl::CreateForTesting(&browser_context_, url); ChildProcessSecurityPolicyImpl::GetInstance()->LockProcess( - site_instance->GetIsolationContext(), - ChildProcessId::FromUnsafeValue(process_id), false, + site_instance->GetIsolationContext(), process_id, false, ProcessLock::FromSiteInfo(site_instance->GetSiteInfo())); added_renderers_.push_back(process_id); @@ -95,7 +94,7 @@ protected: BrowserTaskEnvironment task_environment_; base::HistogramTester histogram_tester; - std::vector<int> added_renderers_; + std::vector<ChildProcessId> added_renderers_; TestBrowserContext browser_context_; base::test::ScopedFeatureList feature_list_; base::ScopedTempDir temp_dir_; @@ -118,7 +117,7 @@ // The lack of a SetupRendererWithLock call for this process ID means // `GetSecondaryKeyForCodeCache` will return an empty GURL, which causes this // renderer to use the shared context key. - const int process_id = 12; + const ChildProcessId process_id(12); { base::RunLoop runloop; auto quit_closure = runloop.QuitClosure(); @@ -190,13 +189,13 @@ net::NetworkIsolationKey nik(net::SchemefulSite{url}, net::SchemefulSite{url}); - const int locked_process_id = 12; + const ChildProcessId locked_process_id(12); SetupRendererWithLock(locked_process_id, url); // The lack of a SetupRendererWithLock call for this process ID means // `GetSecondaryKeyForCodeCache` will return an empty GURL, which causes this // renderer to use the shared context key. - const int unlocked_process_id = 24; + const ChildProcessId unlocked_process_id(24); // Locked process stores data. { @@ -303,7 +302,7 @@ net::NetworkIsolationKey nik(net::SchemefulSite{url}, net::SchemefulSite{url}); - const int process_id = 12; + const ChildProcessId process_id(12); SetupRendererWithLock(process_id, url); GeneratedCodeCacheContext::RunOrPostTask( @@ -347,7 +346,7 @@ net::NetworkIsolationKey nik(net::SchemefulSite{url}, net::SchemefulSite{url}); - const int process_id = 24; + const ChildProcessId process_id(24); SetupRendererWithLock(process_id, url); GeneratedCodeCacheContext::RunOrPostTask( @@ -383,12 +382,12 @@ const GURL resource_url("https://best.web.site.com/script.js"); // State for a site on the open web that loads the above resource. - static constexpr int kOpenWebProcessId = 12; + const ChildProcessId kOpenWebProcessId(12); const GURL open_web_site("https://best.web.site.com/"); SetupRendererWithLock(kOpenWebProcessId, open_web_site); // State for a WebUI page that also loads the above resource. - static constexpr int kWebUiProcessId = 13; + const ChildProcessId kWebUiProcessId(13); const GURL web_ui_site( base::StrCat({kChromeUIScheme, "://some.chrome.page"})); SetupRendererWithLock(kWebUiProcessId, web_ui_site); @@ -438,13 +437,13 @@ base::StrCat({kChromeUIScheme, "://settings/settings.js"})); // State for a WebUI page that loads the above resource. - static constexpr int kWebUiProcessId = 12; + const ChildProcessId kWebUiProcessId(12); const GURL web_ui_site(base::StrCat({kChromeUIScheme, "://settings"})); SetupRendererWithLock(kWebUiProcessId, web_ui_site); // State for a site on the open web that wants to modify the cached data for // the above resource. - static constexpr int kOpenWebProcessId = 13; + const ChildProcessId kOpenWebProcessId(13); const GURL open_web_site("https://somewhere.com"); SetupRendererWithLock(kOpenWebProcessId, open_web_site);
diff --git a/content/browser/renderer_host/media/video_capture_manager.h b/content/browser/renderer_host/media/video_capture_manager.h index ab1a9a05..0d43f46d 100644 --- a/content/browser/renderer_host/media/video_capture_manager.h +++ b/content/browser/renderer_host/media/video_capture_manager.h
@@ -368,7 +368,8 @@ const std::unique_ptr<VideoCaptureProvider> video_capture_provider_; base::RepeatingCallback<void(const std::string&)> emit_log_message_cb_; - base::ObserverList<media::VideoCaptureObserver> capture_observers_; + base::ObserverList<media::VideoCaptureObserver>::UncheckedAndDanglingUntriaged + capture_observers_; // Local cache of the enumerated DeviceInfos. GetDeviceSupportedFormats() will // use this list if the device is not started, otherwise it will retrieve the
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc index 2e4480b..d0a74d97 100644 --- a/content/browser/renderer_host/render_frame_host_impl.cc +++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -14713,8 +14713,8 @@ const net::NetworkIsolationKey& nik, const blink::StorageKey& storage_key) { // Create a new CodeCacheHostImpl and bind it to the given receiver. - code_cache_host_receivers_.Add(GetProcess()->GetDeprecatedID(), nik, - storage_key, std::move(receiver), + code_cache_host_receivers_.Add(GetProcess()->GetID(), nik, storage_key, + std::move(receiver), GetCodeCacheHostReceiverHandler()); }
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index ffa9cb9..c160b8a 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -1667,8 +1667,7 @@ widget_helper_ = new RenderWidgetHelper(); - ChildProcessSecurityPolicyImpl::GetInstance()->Add(GetDeprecatedID(), - browser_context); + ChildProcessSecurityPolicyImpl::GetInstance()->Add(GetID(), browser_context); CHECK(!BrowserMainRunner::ExitedMainMessageLoop()); RegisterHost(GetID(), this); @@ -1771,7 +1770,7 @@ in_process_renderer_.reset(); g_in_process_thread = nullptr; - ChildProcessSecurityPolicyImpl::GetInstance()->Remove(GetDeprecatedID()); + ChildProcessSecurityPolicyImpl::GetInstance()->Remove(GetID()); is_dead_ = true; @@ -3044,8 +3043,7 @@ } ProcessLock RenderProcessHostImpl::GetProcessLock() const { - return ChildProcessSecurityPolicyImpl::GetInstance()->GetProcessLock( - GetDeprecatedID()); + return ChildProcessSecurityPolicyImpl::GetInstance()->GetProcessLock(GetID()); } bool RenderProcessHostImpl::MayReuseHost() { @@ -3646,7 +3644,7 @@ AppendCompositorCommandLineFlags(command_line); command_line->AppendSwitchASCII(switches::kRendererClientId, - base::NumberToString(GetDeprecatedID())); + base::NumberToString(GetID().value())); // Synchronize unix/monotonic clocks across consistent processes. if (base::TimeTicks::IsConsistentAcrossProcesses()) { @@ -4690,7 +4688,7 @@ // navigation to the home page. This is often a privileged page // (chrome://newtab/) which is exactly what we don't want. TRACE_EVENT1("navigation", "RenderProcessHost::FilterURL - invalid URL", - "process_id", rph->GetDeprecatedID()); + "process_id", rph->GetID().value()); VLOG(1) << "Blocked invalid URL"; base::UmaHistogramEnumeration("BrowserRenderProcessHost.BlockedByFilterURL", BlockedURLReason::kInvalidURL); @@ -4707,7 +4705,7 @@ // confused later. TRACE_EVENT2("navigation", "RenderProcessHost::FilterURL - failed CanRequestURL", - "process_id", rph->GetDeprecatedID(), "url", url->spec()); + "process_id", rph->GetID().value(), "url", url->spec()); VLOG(1) << "Blocked URL " << url->spec(); base::UmaHistogramEnumeration("BrowserRenderProcessHost.BlockedByFilterURL", BlockedURLReason::kFailedCanRequestURLCheck); @@ -5321,8 +5319,7 @@ process_reuse_policy); } MAYBEVLOG(2) << __func__ << "(" << site_info << ") selected process host " - << render_process_host->GetDeprecatedID() - << " using assignment \"" + << render_process_host->GetID().value() << " using assignment \"" << site_instance->GetLastProcessAssignmentOutcome() << "\"" << std::endl << GetCurrentHostMapDebugString( @@ -5548,7 +5545,7 @@ RenderWidgetHost::GetRenderWidgetHosts()); while (RenderWidgetHost* widget = widgets->GetNextHost()) { // Count only RenderWidgetHosts in this process. - if (widget->GetProcess()->GetDeprecatedID() == GetDeprecatedID()) { + if (widget->GetProcess()->GetID() == GetID()) { num_active_views++; } }
diff --git a/content/browser/renderer_host/unassigned_site_instance_browsertest.cc b/content/browser/renderer_host/unassigned_site_instance_browsertest.cc index e9d9e8a..8fa5ccca 100644 --- a/content/browser/renderer_host/unassigned_site_instance_browsertest.cc +++ b/content/browser/renderer_host/unassigned_site_instance_browsertest.cc
@@ -913,7 +913,7 @@ web_contents->GetPrimaryMainFrame()->GetSiteInstance()->GetSiteURL()); EXPECT_EQ(ProcessLock::FromSiteInfo(SiteInfo::CreateForTesting( IsolationContext(browser_context), regular_url())), - policy->GetProcessLock(process2->GetDeprecatedID())); + policy->GetProcessLock(process2->GetID())); // Ensure also that the regular url process didn't change midway through the // navigation.
diff --git a/content/browser/service_worker/service_worker_host.cc b/content/browser/service_worker/service_worker_host.cc index 981320de..e699d19 100644 --- a/content/browser/service_worker/service_worker_host.cc +++ b/content/browser/service_worker/service_worker_host.cc
@@ -215,9 +215,11 @@ std::make_unique<CodeCacheHostImpl::ReceiverSet>( storage_partition->GetGeneratedCodeCacheContext()); } - code_cache_host_receivers_->Add(version_->embedded_worker()->process_id(), - GetNetworkIsolationKey(), - GetBucketStorageKey(), std::move(receiver)); + // TODO(crbug.com/379869738) Remove FromUnsafeValue. + code_cache_host_receivers_->Add( + ChildProcessId::FromUnsafeValue( + version_->embedded_worker()->process_id()), + GetNetworkIsolationKey(), GetBucketStorageKey(), std::move(receiver)); } void ServiceWorkerHost::CreateBroadcastChannelProvider(
diff --git a/content/browser/shared_storage/shared_storage_worklet_host.cc b/content/browser/shared_storage/shared_storage_worklet_host.cc index e78e3aac..fc323fb 100644 --- a/content/browser/shared_storage/shared_storage_worklet_host.cc +++ b/content/browser/shared_storage/shared_storage_worklet_host.cc
@@ -1708,7 +1708,7 @@ if (!blink::features::IsPersistentCacheForCodeCacheEnabled()) { mojo::PendingRemote<blink::mojom::CodeCacheHost> actual_code_cache_host; code_cache_host_receivers_->Add( - rfh.GetProcess()->GetDeprecatedID(), rfh.GetNetworkIsolationKey(), + rfh.GetProcess()->GetID(), rfh.GetNetworkIsolationKey(), rfh.GetStorageKey(), actual_code_cache_host.InitWithNewPipeAndPassReceiver());
diff --git a/content/browser/storage_partition_impl_unittest.cc b/content/browser/storage_partition_impl_unittest.cc index 27317600..806d9ce 100644 --- a/content/browser/storage_partition_impl_unittest.cc +++ b/content/browser/storage_partition_impl_unittest.cc
@@ -568,7 +568,7 @@ // Returns the origin to which the render frame host is locked. GURL GetOriginLock() { return ChildProcessSecurityPolicyImpl::GetInstance() - ->GetProcessLock(render_frame_host_->GetProcess()->GetDeprecatedID()) + ->GetProcessLock(render_frame_host_->GetProcess()->GetID()) .GetProcessLockURL(); }
diff --git a/content/browser/webid/identity_credential_source_impl.cc b/content/browser/webid/identity_credential_source_impl.cc index 401e3d23..f2fd23e1 100644 --- a/content/browser/webid/identity_credential_source_impl.cc +++ b/content/browser/webid/identity_credential_source_impl.cc
@@ -55,6 +55,13 @@ request_service->GetAccounts(); std::vector<IdentityRequestAccountPtr> signin_accounts; for (const auto& account : request_accounts) { + const GURL& idp_config_url = + account->identity_provider->idp_metadata.config_url; + auto it = request_service->idp_infos_.find(idp_config_url); + if (it != request_service->idp_infos_.end() && + it->second->client_is_third_party_to_top_frame_origin) { + continue; + } if (!account->is_filtered_out && account->idp_claimed_login_state.value_or( account->browser_trusted_login_state) == @@ -198,6 +205,8 @@ std::string site = FormatUrlToSite(render_frame_host().GetLastCommittedOrigin().GetURL()); for (const auto& result : results) { + // We did not pass client_id, so we cannot check + // client_is_third_party_to_top_frame_origin here. if (result.accounts.has_value()) { auto potentially_sign_in_accounts = result.accounts->PotentialAccountsForSite(site);
diff --git a/content/browser/webid/identity_credential_source_impl_unittest.cc b/content/browser/webid/identity_credential_source_impl_unittest.cc index 406b1e2..9e0dc0a 100644 --- a/content/browser/webid/identity_credential_source_impl_unittest.cc +++ b/content/browser/webid/identity_credential_source_impl_unittest.cc
@@ -519,4 +519,154 @@ ->SetPendingWebIdentityRequest(nullptr); } +// Tests that GetIdentityCredentialSuggestions() filters out accounts from an +// existing pending request if the iframe is third-party to the top-frame +// origin. +TEST_F(IdentityCredentialSourceImplTest, + GetIdentityCredentialSuggestionsFilterCrossSiteThirdParty) { + GURL config_url(kConfigUrl); + + RenderFrameHost* subframe = + RenderFrameHostTester::For(main_rfh())->AppendChild("subframe"); + subframe = NavigationSimulator::NavigateAndCommitFromDocument( + GURL("https://other.com"), subframe); + + IdentityCredentialSourceImpl* subframe_source = + IdentityCredentialSourceImpl::GetOrCreateForCurrentDocument(subframe); + + auto subframe_network_manager = + std::make_unique<NiceMock<MockIdpNetworkRequestManager>>(); + MockIdpNetworkRequestManager* subframe_network_manager_ptr = + subframe_network_manager.get(); + subframe_source->SetNetworkManagerForTests( + std::move(subframe_network_manager)); + + MockApiPermissionDelegate api_permission_delegate; + EXPECT_CALL(api_permission_delegate, GetApiPermissionStatus) + .WillRepeatedly(Return(FederatedIdentityApiPermissionContextDelegate:: + PermissionStatus::GRANTED)); + + MockAutoReauthnPermissionDelegate auto_reauthn_permission_delegate; + EXPECT_CALL(auto_reauthn_permission_delegate, IsAutoReauthnSettingEnabled) + .WillRepeatedly(Return(false)); + + MockIdentityRegistry identity_registry(web_contents(), nullptr, config_url); + mojo::Remote<blink::mojom::FederatedAuthRequest> remote; + + RequestService& request_service = RequestService::CreateForTesting( + *subframe, &api_permission_delegate, &auto_reauthn_permission_delegate, + permission_delegate_.get(), &identity_registry, + remote.BindNewPipeAndPassReceiver()); + + TestIdentityCredentialSourceImpl::InitializeRequestService( + &request_service, + std::make_unique<NiceMock<MockIdpNetworkRequestManager>>()); + request_service.SetDialogControllerForTests( + std::make_unique<NiceMock<MockIdentityRequestDialogController>>()); + + RequestPageData::GetOrCreateForPage(subframe->GetPage()) + ->SetPendingWebIdentityRequest(&request_service); + + blink::mojom::IdentityProviderRequestOptionsPtr options = + blink::mojom::IdentityProviderRequestOptions::New(); + options->config = blink::mojom::IdentityProviderConfig::New(); + options->config->config_url = config_url; + + auto idp_info = std::make_unique<IdentityProviderInfo>( + options, IdpNetworkRequestManager::Endpoints(), + IdentityProviderMetadata(), blink::mojom::RpContext::kSignIn, + blink::mojom::RpMode::kPassive, std::nullopt); + idp_info->client_is_third_party_to_top_frame_origin = true; + IdentityProviderMetadata idp_metadata; + idp_metadata.config_url = config_url; + idp_info->data = base::MakeRefCounted<IdentityProviderData>( + "idp", idp_metadata, ClientMetadata(GURL(), GURL(), GURL(), gfx::Image()), + blink::mojom::RpContext::kSignIn, std::nullopt, + std::vector<IdentityRequestDialogDisclosureField>(), + /*has_login_status_mismatch=*/false); + + IdentityRequestAccountPtr account = + base::MakeRefCounted<IdentityRequestAccount>( + kAccountId, "test@example.com", "Test User", "test@example.com", + "Test User", "Test", GURL(), "", "", std::vector<std::string>(), + std::vector<std::string>(), std::vector<std::string>(), + std::vector<std::string>(), + content::IdentityRequestAccount::LoginState::kSignIn); + account->identity_provider = idp_info->data; + + IdpNetworkRequestManager::AccountsResponse accounts_response; + accounts_response.site_salt = "fc432178f9155c4e24762de5b9505f2e"; + accounts_response.accounts.push_back(account); + + IdpNetworkRequestManager::AccountsResponse accounts_response_copy; + accounts_response_copy.site_salt = accounts_response.site_salt; + accounts_response_copy.accounts.push_back(account); + + TestIdentityCredentialSourceImpl::SetAccounts( + &request_service, std::move(accounts_response.accounts)); + TestIdentityCredentialSourceImpl::SetIdpInfo(&request_service, config_url, + std::move(idp_info)); + + // If the accounts are filtered out from the pending request, it will + // proceed to fetch. We mock the fetch here. + EXPECT_CALL(*permission_delegate_, + GetIdpSigninStatus(url::Origin::Create(config_url))) + .WillRepeatedly(Return(true)); + + IdpNetworkRequestManager::WellKnown well_known; + well_known.provider_urls = std::set<GURL>{config_url}; + EXPECT_CALL(*subframe_network_manager_ptr, FetchWellKnown(config_url, _)) + .WillOnce(base::test::RunOnceCallback<1>( + FetchStatus{ParseStatus::kSuccess, 200}, well_known)); + + IdpNetworkRequestManager::Endpoints endpoints; + endpoints.token = GURL(kTokenUrl); + endpoints.accounts = GURL(kAccountsUrl); + endpoints.client_metadata = GURL("https://idp.example/client_metadata"); + IdentityProviderMetadata idp_metadata_fetch; + idp_metadata_fetch.idp_login_url = GURL("https://idp.example/login"); + EXPECT_CALL(*subframe_network_manager_ptr, FetchConfig(config_url, _, _, _)) + .WillOnce(base::test::RunOnceCallback<3>( + FetchStatus{ParseStatus::kSuccess, 200}, endpoints, + idp_metadata_fetch)); + + // Mock SendAccountsRequest returning an account that will be filtered out + // in OnAccountsFetchCompleted. + EXPECT_CALL(*subframe_network_manager_ptr, + SendAccountsRequest(_, GURL(kAccountsUrl), _, _)) + .WillOnce( + [&](const url::Origin&, const GURL&, const std::string&, + IdpNetworkRequestManager::AccountsRequestCallback callback) { + base::SequencedTaskRunner::GetCurrentDefault()->PostTask( + FROM_HERE, + base::BindOnce(std::move(callback), + FetchStatus{ParseStatus::kSuccess, 200}, + std::move(accounts_response_copy))); + return true; + }); + + // Mock FetchClientMetadata + IdpNetworkRequestManager::ClientMetadata client_metadata; + client_metadata.client_is_third_party_to_top_frame_origin = true; + EXPECT_CALL(*subframe_network_manager_ptr, FetchClientMetadata) + .WillOnce(base::test::RunOnceCallback<4>( + FetchStatus{ParseStatus::kSuccess, 200}, client_metadata)); + + base::RunLoop run_loop; + subframe_source->GetIdentityCredentialSuggestions( + {config_url}, + base::BindLambdaForTesting( + [&](const std::optional<std::vector<IdentityRequestAccountPtr>>& + accounts) { + ASSERT_TRUE(accounts.has_value()); + // Should be empty because it was filtered out. + EXPECT_TRUE(accounts->empty()); + run_loop.Quit(); + })); + run_loop.Run(); + + RequestPageData::GetOrCreateForPage(subframe->GetPage()) + ->SetPendingWebIdentityRequest(nullptr); +} + } // namespace content::webid
diff --git a/content/browser/worker_host/dedicated_worker_host.cc b/content/browser/worker_host/dedicated_worker_host.cc index 95e329d..7e3f35b 100644 --- a/content/browser/worker_host/dedicated_worker_host.cc +++ b/content/browser/worker_host/dedicated_worker_host.cc
@@ -915,7 +915,7 @@ mojo::PendingReceiver<blink::mojom::CodeCacheHost> receiver) { // Create a new CodeCacheHostImpl and bind it to the given receiver. RenderProcessHost* rph = GetProcessHost(); - code_cache_host_receivers_.Add(rph->GetDeprecatedID(), + code_cache_host_receivers_.Add(rph->GetID(), isolation_info_.network_isolation_key(), GetStorageKey(), std::move(receiver)); }
diff --git a/content/browser/worker_host/shared_worker_host.cc b/content/browser/worker_host/shared_worker_host.cc index 0bd245a..cfaa222848 100644 --- a/content/browser/worker_host/shared_worker_host.cc +++ b/content/browser/worker_host/shared_worker_host.cc
@@ -797,7 +797,7 @@ void SharedWorkerHost::CreateCodeCacheHost( mojo::PendingReceiver<blink::mojom::CodeCacheHost> receiver) { // Create a new CodeCacheHostImpl and bind it to the given receiver. - code_cache_host_receivers_.Add(GetProcessHost()->GetDeprecatedID(), + code_cache_host_receivers_.Add(GetProcessHost()->GetID(), GetNetworkIsolationKey(), GetStorageKey(), std::move(receiver)); }
diff --git a/content/browser/xr/service/vr_service_impl.cc b/content/browser/xr/service/vr_service_impl.cc index 853a53d..fb714ec1 100644 --- a/content/browser/xr/service/vr_service_impl.cc +++ b/content/browser/xr/service/vr_service_impl.cc
@@ -596,13 +596,6 @@ DCHECK(runtime); DCHECK_EQ(runtime->GetId(), request.runtime_id); -#if BUILDFLAG(ENABLE_OPENXR) - if (request.options->mode == device::mojom::XRSessionMode::kImmersiveAr && - runtime->GetId() == device::mojom::XRDeviceId::OPENXR_DEVICE_ID) { - DCHECK(device::features::IsOpenXrArEnabled()); - } -#endif - // Need to calculate the permissions before the call below, as otherwise // std::move nulls options out before `GetRequiredPermissions()` runs. const std::vector<blink::PermissionType> permissions_for_mode =
diff --git a/content/browser/xr/service/xr_runtime_manager_impl.cc b/content/browser/xr/service/xr_runtime_manager_impl.cc index 6e3d0b1..f02d16a 100644 --- a/content/browser/xr/service/xr_runtime_manager_impl.cc +++ b/content/browser/xr/service/xr_runtime_manager_impl.cc
@@ -323,10 +323,9 @@ #if BUILDFLAG(ENABLE_OPENXR) // If OpenXR is available and the runtime supports an AR blend mode, prefer // it over ARCore to unify VR/AR rendering paths. - if (device::features::IsOpenXrArEnabled()) { - auto* openxr = GetRuntime(device::mojom::XRDeviceId::OPENXR_DEVICE_ID); - if (openxr && openxr->SupportsArBlendMode()) - return openxr; + auto* openxr = GetRuntime(device::mojom::XRDeviceId::OPENXR_DEVICE_ID); + if (openxr && openxr->SupportsArBlendMode()) { + return openxr; } #endif
diff --git a/content/gpu/gpu_main.cc b/content/gpu/gpu_main.cc index 7265019..35ec6d4 100644 --- a/content/gpu/gpu_main.cc +++ b/content/gpu/gpu_main.cc
@@ -55,6 +55,7 @@ #include "content/public/gpu/content_gpu_client.h" #include "gpu/command_buffer/service/gpu_switches.h" #include "gpu/config/gpu_driver_bug_list.h" +#include "gpu/config/gpu_driver_bug_workarounds.h" #include "gpu/config/gpu_finch_features.h" #include "gpu/config/gpu_info_collector.h" #include "gpu/config/gpu_preferences.h" @@ -156,7 +157,9 @@ private: // SandboxHelper: - void PreSandboxStartup(const gpu::GpuPreferences& gpu_prefs) override { + void PreSandboxStartup( + const gpu::GpuPreferences& gpu_prefs, + const gpu::GpuDriverBugWorkarounds& workarounds) override { TRACE_EVENT("gpu,startup", "gpu_main::PreSandboxStartup"); // Warm up resources that don't need access to GPUInfo. { @@ -172,10 +175,13 @@ #if BUILDFLAG(USE_VAAPI) #if BUILDFLAG(IS_CHROMEOS) - media::VaapiWrapper::PreSandboxInitialization(); + media::VaapiWrapper::PreSandboxInitialization( + /*allow_disabling_global_lock=*/false, &workarounds); #else // For Linux with VA-API support. - if (!gpu_prefs.disable_accelerated_video_decode) - media::VaapiWrapper::PreSandboxInitialization(); + if (!gpu_prefs.disable_accelerated_video_decode) { + media::VaapiWrapper::PreSandboxInitialization( + /*allow_disabling_global_lock=*/false, &workarounds); + } #endif #endif // BUILDFLAG(USE_VAAPI) #if BUILDFLAG(IS_WIN)
diff --git a/content/gpu/in_process_gpu_thread.cc b/content/gpu/in_process_gpu_thread.cc index 42d0ea2..884a8a4 100644 --- a/content/gpu/in_process_gpu_thread.cc +++ b/content/gpu/in_process_gpu_thread.cc
@@ -13,7 +13,8 @@ #include "content/public/common/content_client.h" #include "content/public/common/content_switches.h" #include "content/public/gpu/content_gpu_client.h" -#include "gpu/config/gpu_preferences.h" +#include "gpu/config/gpu_driver_bug_workarounds.h" +#include "gpu/config/gpu_feature_info.h" #include "gpu/ipc/service/gpu_init.h" #include "media/gpu/buildflags.h" @@ -102,7 +103,10 @@ gpu_preferences_); #if BUILDFLAG(USE_VAAPI) - media::VaapiWrapper::PreSandboxInitialization(); + gpu::GpuDriverBugWorkarounds workarounds( + gpu_init->gpu_feature_info().enabled_gpu_driver_bug_workarounds); + media::VaapiWrapper::PreSandboxInitialization( + /*allow_disabling_global_lock=*/false, &workarounds); #endif GetContentClient()->SetGpuInfo(gpu_init->gpu_info());
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/ThreadedInputConnectionFactory.java b/content/public/android/java/src/org/chromium/content/browser/input/ThreadedInputConnectionFactory.java index 2a7f4e2..e4f4212 100644 --- a/content/public/android/java/src/org/chromium/content/browser/input/ThreadedInputConnectionFactory.java +++ b/content/public/android/java/src/org/chromium/content/browser/input/ThreadedInputConnectionFactory.java
@@ -8,6 +8,7 @@ import android.os.Handler; import android.os.HandlerThread; +import android.os.Process; import android.view.View; import android.view.inputmethod.EditorInfo; @@ -66,7 +67,8 @@ static { HandlerThread handlerThread = - new HandlerThread("InputConnectionHandlerThread", HandlerThread.NORM_PRIORITY); + new HandlerThread( + "InputConnectionHandlerThread", Process.THREAD_PRIORITY_URGENT_DISPLAY); handlerThread.start(); sHandler = new Handler(handlerThread.getLooper()); }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityE2ETest.java b/content/public/android/javatests/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityE2ETest.java index af7b161..667a8e7 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityE2ETest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityE2ETest.java
@@ -19,6 +19,7 @@ import org.junit.After; import org.junit.Assert; +import org.junit.Assume; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -26,6 +27,7 @@ import org.chromium.base.test.BaseJUnit4ClassRunner; import org.chromium.base.test.util.Batch; +import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.Features.EnableFeatures; import org.chromium.base.test.util.MinAndroidSdkLevel; import org.chromium.base.test.util.UrlUtils; @@ -181,6 +183,10 @@ @MinAndroidSdkLevel(Build.VERSION_CODES.BAKLAVA) public void testAccessibilityServiceReceivesInitialEvent_SdkBalklavaAndAbove() throws Throwable { + Assume.assumeTrue( + "Requires Android 16 QPR2 (36.1) or higher", + Build.VERSION.SDK_INT_FULL >= Build.VERSION_CODES_FULL.BAKLAVA_1); + // Load a page. String url = UrlUtils.encodeHtmlDataUri("<p>hello</p>"); mActivityTestRule.launchContentShellWithUrl(url); @@ -296,6 +302,7 @@ @SmallTest @MinAndroidSdkLevel(Build.VERSION_CODES.BAKLAVA) @EnableFeatures({ContentFeatureList.ACCESSIBILITY_EXTENDED_SELECTION}) + @DisabledTest(message = "https://crbug.com/493575785") public void testDumpTreeWithInitialSelection() throws Throwable { // Load a page with an initial selection. String html =
diff --git a/content/public/browser/devtools_agent_host_client.cc b/content/public/browser/devtools_agent_host_client.cc index 808d4a0..a8370fc0 100644 --- a/content/public/browser/devtools_agent_host_client.cc +++ b/content/public/browser/devtools_agent_host_client.cc
@@ -40,6 +40,13 @@ return false; } +// Default is false. Most privileged clients (DevTools frontend, remote +// debugger, pipe handler, etc.) should override this to return true. +// Debugger extension clients should keep the default (false). +bool DevToolsAgentHostClient::MayAccessAllCookies() { + return false; +} + std::optional<url::Origin> DevToolsAgentHostClient::GetNavigationInitiatorOrigin() { return std::nullopt;
diff --git a/content/public/browser/devtools_agent_host_client.h b/content/public/browser/devtools_agent_host_client.h index e72f03be5..a05939c 100644 --- a/content/public/browser/devtools_agent_host_client.h +++ b/content/public/browser/devtools_agent_host_client.h
@@ -45,6 +45,12 @@ // manipulate browser altogether. virtual bool IsTrusted(); + // Returns true if the client has unrestricted access to all cookies + // (i.e., MayAttachToURL() returns true for all possible cookie domains). + // When true, cookie operations like clearBrowserCookies can use a more + // efficient atomic deletion path instead of per-cookie filtering. + virtual bool MayAccessAllCookies(); + // Returns true if the client is allowed to read local files over the // protocol. Example would be exposing file content to the page under debug. virtual bool MayReadLocalFiles();
diff --git a/content/public/browser/prerender_handle.h b/content/public/browser/prerender_handle.h index 4f74a83..404d3eb0 100644 --- a/content/public/browser/prerender_handle.h +++ b/content/public/browser/prerender_handle.h
@@ -25,8 +25,6 @@ PrerenderHandle() = default; virtual ~PrerenderHandle() = default; - // TODO(crbug.com/434826191): Replace this with GetPrerenderHostId(). - virtual int32_t GetHandleId() const = 0; virtual PrerenderHostId GetPrerenderHostId() const = 0; // Returns the initial URL that is passed to PrerenderHostRegistry for
diff --git a/content/public/browser/prerender_host_id.h b/content/public/browser/prerender_host_id.h index 9786d5b..ef68f53 100644 --- a/content/public/browser/prerender_host_id.h +++ b/content/public/browser/prerender_host_id.h
@@ -11,7 +11,9 @@ namespace content { // A strongly-typed identifier for PrerenderHost. -using PrerenderHostId = base::IdTypeU64<class PrerenderHost>; +// -1 is used as the invalid value to maintain compatibility with Android +// WebView APIs which return -1 on failure. 1 is the first generated valid ID. +using PrerenderHostId = base::IdType<class PrerenderHost, int64_t, -1, 1>; } // namespace content
diff --git a/content/public/test/mock_render_process_host.cc b/content/public/test/mock_render_process_host.cc index d96c69e5..695c598 100644 --- a/content/public/test/mock_render_process_host.cc +++ b/content/public/test/mock_render_process_host.cc
@@ -84,19 +84,18 @@ foreground_service_worker_count_(0) { // Child process security operations can't be unit tested unless we add // ourselves as an existing child process. - ChildProcessSecurityPolicyImpl::GetInstance()->Add(GetDeprecatedID(), - browser_context); + ChildProcessSecurityPolicyImpl::GetInstance()->Add(GetID(), browser_context); - RenderProcessHostImpl::RegisterHost(GetDeprecatedID(), this); + RenderProcessHostImpl::RegisterHost(GetID(), this); } MockRenderProcessHost::~MockRenderProcessHost() { - ChildProcessSecurityPolicyImpl::GetInstance()->Remove(GetDeprecatedID()); + ChildProcessSecurityPolicyImpl::GetInstance()->Remove(GetID()); // In unit tests, Cleanup() might not have been called. if (!deletion_callback_called_) { for (auto& observer : observers_) observer.RenderProcessHostDestroyed(this); - RenderProcessHostImpl::UnregisterHost(GetDeprecatedID()); + RenderProcessHostImpl::UnregisterHost(GetID()); } } @@ -342,7 +341,7 @@ for (auto& observer : observers_) observer.RenderProcessHostDestroyed(this); - RenderProcessHostImpl::UnregisterHost(GetDeprecatedID()); + RenderProcessHostImpl::UnregisterHost(GetID()); has_connection_ = false; deletion_callback_called_ = true; } @@ -579,8 +578,7 @@ } ProcessLock MockRenderProcessHost::GetProcessLock() const { - return ChildProcessSecurityPolicyImpl::GetInstance()->GetProcessLock( - GetDeprecatedID()); + return ChildProcessSecurityPolicyImpl::GetInstance()->GetProcessLock(GetID()); } bool MockRenderProcessHost::IsProcessLockedToSiteForTesting() { @@ -619,7 +617,7 @@ void MockRenderProcessHost::WriteIntoTrace( perfetto::TracedProto<TraceProto> proto) const { - proto->set_id(GetDeprecatedID()); + proto->set_id(GetID().value()); } #if BUILDFLAG(IS_CHROMEOS)
diff --git a/content/public/test/test_devtools_protocol_client.cc b/content/public/test/test_devtools_protocol_client.cc index 3f019cbf..0740070 100644 --- a/content/public/test/test_devtools_protocol_client.cc +++ b/content/public/test/test_devtools_protocol_client.cc
@@ -220,6 +220,10 @@ not_attachable_hosts_.end(); } +bool TestDevToolsProtocolClient::MayAccessAllCookies() { + return not_attachable_hosts_.empty(); +} + std::optional<url::Origin> TestDevToolsProtocolClient::GetNavigationInitiatorOrigin() { return navigation_initiator_origin_;
diff --git a/content/public/test/test_devtools_protocol_client.h b/content/public/test/test_devtools_protocol_client.h index df6fdeb4..9f93516 100644 --- a/content/public/test/test_devtools_protocol_client.h +++ b/content/public/test/test_devtools_protocol_client.h
@@ -132,6 +132,7 @@ bool MayReadLocalFiles() override; bool MayWriteLocalFiles() override; bool MayAttachToURL(const GURL& url, bool is_webui) override; + bool MayAccessAllCookies() override; int last_sent_id_ = 0; int waiting_for_command_result_id_ = 0;
diff --git a/content/shell/browser/shell_devtools_bindings.cc b/content/shell/browser/shell_devtools_bindings.cc index 6486639..8ec9dce 100644 --- a/content/shell/browser/shell_devtools_bindings.cc +++ b/content/shell/browser/shell_devtools_bindings.cc
@@ -436,4 +436,8 @@ delegate_->Close(); } +bool ShellDevToolsBindings::MayAccessAllCookies() { + return true; +} + } // namespace content
diff --git a/content/shell/browser/shell_devtools_bindings.h b/content/shell/browser/shell_devtools_bindings.h index f3999a6..66ad0a4b 100644 --- a/content/shell/browser/shell_devtools_bindings.h +++ b/content/shell/browser/shell_devtools_bindings.h
@@ -57,6 +57,8 @@ WebContents* inspected_contents() { return inspected_contents_; } + bool MayAccessAllCookies() override; + private: // content::DevToolsAgentHostClient implementation. void AgentHostClosed(DevToolsAgentHost* agent_host) override;
diff --git a/content/test/fuzzer/code_cache_host_mojolpm_fuzzer.cc b/content/test/fuzzer/code_cache_host_mojolpm_fuzzer.cc index f47c9a0b..98d13c8 100644 --- a/content/test/fuzzer/code_cache_host_mojolpm_fuzzer.cc +++ b/content/test/fuzzer/code_cache_host_mojolpm_fuzzer.cc
@@ -85,7 +85,7 @@ // cache thread. void AddCodeCacheHostImpl( uint32_t id, - int renderer_id, + content::ChildProcessId renderer_id, const net::NetworkIsolationKey& key, const blink::StorageKey& storage_key, mojo::PendingReceiver<::blink::mojom::CodeCacheHost>&& receiver); @@ -95,7 +95,7 @@ // `done_closure`. void AddCodeCacheHost( uint32_t id, - int renderer_id, + content::ChildProcessId renderer_id, content::fuzzing::code_cache_host::proto::NewCodeCacheHostAction::OriginId origin_id, base::OnceClosure done_closure); @@ -120,7 +120,8 @@ using UniqueCodeCacheReceiverSet = std::unique_ptr<mojo::UniqueReceiverSet<blink::mojom::CodeCacheHost>, base::OnTaskRunnerDeleter>; - std::map<int, UniqueCodeCacheReceiverSet> code_cache_host_receivers_; + std::map<content::ChildProcessId, UniqueCodeCacheReceiverSet> + code_cache_host_receivers_; }; CodeCacheHostTestcase::CodeCacheHostTestcase( @@ -212,8 +213,10 @@ switch (action.action_case()) { case ProtoAction::kNewCodeCacheHost: + // TODO(crbug.com/379869738) Remove FromUnsafeValue. AddCodeCacheHost(action.new_code_cache_host().id(), - action.new_code_cache_host().render_process_id(), + content::ChildProcessId::FromUnsafeValue( + action.new_code_cache_host().render_process_id()), action.new_code_cache_host().origin_id(), std::move(run_closure)); return; @@ -248,7 +251,7 @@ void CodeCacheHostTestcase::AddCodeCacheHostImpl( uint32_t id, - int renderer_id, + content::ChildProcessId renderer_id, const net::NetworkIsolationKey& nik, const blink::StorageKey& storage_key, mojo::PendingReceiver<::blink::mojom::CodeCacheHost>&& receiver) { @@ -275,7 +278,7 @@ void CodeCacheHostTestcase::AddCodeCacheHost( uint32_t id, - int renderer_id, + content::ChildProcessId renderer_id, content::fuzzing::code_cache_host::proto::NewCodeCacheHostAction::OriginId origin_id, base::OnceClosure run_closure) {
diff --git a/content/test/fuzzer/file_system_manager_mojolpm_fuzzer.cc b/content/test/fuzzer/file_system_manager_mojolpm_fuzzer.cc index ce6f10c..3f64bbd04e 100644 --- a/content/test/fuzzer/file_system_manager_mojolpm_fuzzer.cc +++ b/content/test/fuzzer/file_system_manager_mojolpm_fuzzer.cc
@@ -176,7 +176,7 @@ // content/browser/file_system/file_system_manager_impl.h for (size_t i = 0; i < kNumRenderers; i++) { // Process IDs must be greater than 0. - uint32_t process_id = i + 1; + content::ChildProcessId process_id(i + 1); p->Add(process_id, &browser_context_); file_system_manager_impls_[i] = std::make_unique<FileSystemManagerImpl>( @@ -211,7 +211,7 @@ ChildProcessSecurityPolicyImpl::GetInstance(); for (size_t process_id = 1; process_id <= kNumRenderers; process_id++) { - p->Remove(process_id); + p->Remove(content::ChildProcessId(process_id)); } GetIOThreadTaskRunner({})->PostTask(
diff --git a/content/test/gpu/gpu_tests/trace_integration_test.py b/content/test/gpu/gpu_tests/trace_integration_test.py index bcf8ce9..41360ec 100644 --- a/content/test/gpu/gpu_tests/trace_integration_test.py +++ b/content/test/gpu/gpu_tests/trace_integration_test.py
@@ -128,7 +128,10 @@ 'GpuChannelMessageFilter::CopyToGpuMemoryBufferAsync' _MFD3D11VC_ALTERNATIVE_MAP_EVENT_NAME2 =\ 'MappableBufferDXGI::MapAsync' -_MFD3D11VC_PRESENT_EVENT_NAME = 'DXGISharedHandleState::AcquireKeyedMutex' +# GPU-process event: fires when accessing a DXGI shared handle backed texture. +# Camera capture textures always have dxgi_shared_handle_state_. +_MFD3D11VC_PRESENT_EVENT_NAME =\ + 'D3DImageBacking::BeginAccessD3D11::DXGISharedHandle' # Caching events and constants _GPU_HOST_STORE_BLOB_EVENT_NAME =\
diff --git a/content/test/gpu/gpu_tests/webgpu_cts_integration_test_base.py b/content/test/gpu/gpu_tests/webgpu_cts_integration_test_base.py index dc39070b..f978b210e7 100644 --- a/content/test/gpu/gpu_tests/webgpu_cts_integration_test_base.py +++ b/content/test/gpu/gpu_tests/webgpu_cts_integration_test_base.py
@@ -100,6 +100,7 @@ _test_timeout = DEFAULT_TEST_TIMEOUT _enable_dawn_backend_validation = False + _enable_default_webgpu_features = False _use_webgpu_adapter: str | None = None # use the default _original_environ: Mapping | None = None _use_webgpu_power_preference: str | None = None @@ -190,6 +191,11 @@ action='store_true', default=False, help='Force use of the unrollConstEvalLoops setting in JavaScript.') + parser.add_argument( + '--enable-default-webgpu-features', + action='store_true', + help='Runs the browser without unsafe or experimental WebGPU features', + ) @classmethod def StartBrowser(cls) -> None: @@ -209,7 +215,9 @@ """ browser_args = super().GenerateBrowserArgs(additional_args) - enable_dawn_features = ['allow_unsafe_apis'] + enable_dawn_features = [] + if not cls._enable_default_webgpu_features: + enable_dawn_features.append('allow_unsafe_apis') disable_dawn_features = [] if host_information.IsWindows(): @@ -226,8 +234,9 @@ browser_args.append( f'--disable-dawn-features={",".join(disable_dawn_features)}') - browser_args.append('--enable-unsafe-webgpu') - browser_args.append('--enable-webgpu-developer-features') + if not cls._enable_default_webgpu_features: + browser_args.append('--enable-unsafe-webgpu') + browser_args.append('--enable-webgpu-developer-features') if cls._use_webgpu_adapter: browser_args.append(f'--use-webgpu-adapter={cls._use_webgpu_adapter}') @@ -276,6 +285,7 @@ if options.override_timeout: cls._test_timeout = options.override_timeout cls._enable_dawn_backend_validation = options.enable_dawn_backend_validation + cls._enable_default_webgpu_features = options.enable_default_webgpu_features cls._use_webgpu_adapter = options.use_webgpu_adapter cls._use_webgpu_power_preference = options.use_webgpu_power_preference cls._use_fxc = options.use_fxc
diff --git a/crypto/kdf.cc b/crypto/kdf.cc index 6f0544d..fab45ad 100644 --- a/crypto/kdf.cc +++ b/crypto/kdf.cc
@@ -11,11 +11,11 @@ namespace crypto::kdf { -void DeriveKeyPbkdf2HmacSha1(const Pbkdf2HmacSha1Params& params, - base::span<const uint8_t> password, - base::span<const uint8_t> salt, - base::span<uint8_t> result, - crypto::SubtlePassKey) { +void Pbkdf2HmacSha1(const Pbkdf2HmacSha1Params& params, + base::span<const uint8_t> password, + base::span<const uint8_t> salt, + base::span<uint8_t> result, + crypto::SubtlePassKey) { OpenSSLErrStackTracer err_tracer(FROM_HERE); int rv = PKCS5_PBKDF2_HMAC_SHA1( base::as_chars(password).data(), password.size(), salt.data(), @@ -24,11 +24,11 @@ CHECK_EQ(rv, 1); } -void DeriveKeyScrypt(const ScryptParams& params, - base::span<const uint8_t> password, - base::span<const uint8_t> salt, - base::span<uint8_t> result, - crypto::SubtlePassKey) { +void Scrypt(const ScryptParams& params, + base::span<const uint8_t> password, + base::span<const uint8_t> salt, + base::span<uint8_t> result, + crypto::SubtlePassKey) { OpenSSLErrStackTracer err_tracer(FROM_HERE); int rv = EVP_PBE_scrypt(reinterpret_cast<const char*>(password.data()),
diff --git a/crypto/kdf.h b/crypto/kdf.h index b83172d..7ebbd589 100644 --- a/crypto/kdf.h +++ b/crypto/kdf.h
@@ -42,25 +42,23 @@ // TODO(https://issues.chromium.org/issues/369653192): document constraints on // params. -// TODO(https://issues.chromium.org/issues/430635195): rename this. -CRYPTO_EXPORT void DeriveKeyPbkdf2HmacSha1(const Pbkdf2HmacSha1Params& params, - base::span<const uint8_t> password, - base::span<const uint8_t> salt, - base::span<uint8_t> result, - crypto::SubtlePassKey); +CRYPTO_EXPORT void Pbkdf2HmacSha1(const Pbkdf2HmacSha1Params& params, + base::span<const uint8_t> password, + base::span<const uint8_t> salt, + base::span<uint8_t> result, + crypto::SubtlePassKey); // TODO(https://issues.chromium.org/issues/369653192): document constraints on // params. -// TODO(https://issues.chromium.org/issues/430635195): rename this. // // Note: this function CHECKs that the passed-in ScryptParams are valid. If you // are not sure if your params will be valid, consult a //crypto OWNER - the // definition of valid is somewhat tricky. -CRYPTO_EXPORT void DeriveKeyScrypt(const ScryptParams& params, - base::span<const uint8_t> password, - base::span<const uint8_t> salt, - base::span<uint8_t> result, - crypto::SubtlePassKey); +CRYPTO_EXPORT void Scrypt(const ScryptParams& params, + base::span<const uint8_t> password, + base::span<const uint8_t> salt, + base::span<uint8_t> result, + crypto::SubtlePassKey); // Derive a key using HKDF with the specified hash kind, into the given out // buffer, which must be the right size for that hash kind. The secret, salt,
diff --git a/crypto/kdf_unittest.cc b/crypto/kdf_unittest.cc index 453d1f5..1ade5b5b 100644 --- a/crypto/kdf_unittest.cc +++ b/crypto/kdf_unittest.cc
@@ -30,9 +30,9 @@ for (const auto& c : cases) { std::vector<uint8_t> key(c.len); - crypto::kdf::DeriveKeyPbkdf2HmacSha1( - c.params, base::as_byte_span(c.password), base::as_byte_span(c.salt), - key, crypto::SubtlePassKey::ForTesting()); + crypto::kdf::Pbkdf2HmacSha1(c.params, base::as_byte_span(c.password), + base::as_byte_span(c.salt), key, + crypto::SubtlePassKey::ForTesting()); std::vector<uint8_t> result_bytes(c.len); ASSERT_TRUE(base::HexStringToSpan(c.result, result_bytes)); @@ -63,9 +63,9 @@ for (const auto& c : cases) { std::vector<uint8_t> key(c.len); - crypto::kdf::DeriveKeyScrypt(c.params, base::as_byte_span(c.password), - base::as_byte_span(c.salt), key, - crypto::SubtlePassKey::ForTesting()); + crypto::kdf::Scrypt(c.params, base::as_byte_span(c.password), + base::as_byte_span(c.salt), key, + crypto::SubtlePassKey::ForTesting()); std::vector<uint8_t> result_bytes(c.len); ASSERT_TRUE(base::HexStringToSpan(c.result, result_bytes)); @@ -83,9 +83,9 @@ for (const auto& c : cases) { std::vector<uint8_t> key(64); EXPECT_DEATH_IF_SUPPORTED( - crypto::kdf::DeriveKeyScrypt(c, base::as_byte_span("password"), - base::as_byte_span("NaCl"), key, - crypto::SubtlePassKey::ForTesting()), + crypto::kdf::Scrypt(c, base::as_byte_span("password"), + base::as_byte_span("NaCl"), key, + crypto::SubtlePassKey::ForTesting()), ""); } }
diff --git a/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothDevice.java b/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothDevice.java index def15c40..6791c419 100644 --- a/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothDevice.java +++ b/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothDevice.java
@@ -112,6 +112,7 @@ // Implements BluetoothDeviceAndroid::GetUUIDs for classic devices. @CalledByNative + @JniType("std::vector<std::string>") private String[] getUuids() { ParcelUuid[] uuids = mDevice.getUuids(); if (uuids == null) { @@ -119,7 +120,7 @@ } String[] uuidStrings = new String[uuids.length]; for (int i = 0; i < uuids.length; i++) { - uuidStrings[i] = uuids[i].toString(); + uuidStrings[i] = uuids[i].getUuid().toString(); } return uuidStrings; }
diff --git a/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattCharacteristic.java b/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattCharacteristic.java index bd72a7f..7171d1c 100644 --- a/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattCharacteristic.java +++ b/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattCharacteristic.java
@@ -8,6 +8,7 @@ import org.jni_zero.CalledByNative; import org.jni_zero.JNINamespace; +import org.jni_zero.JniType; import org.jni_zero.NativeMethods; import org.chromium.base.Log; @@ -18,11 +19,10 @@ import java.util.List; /** - * Exposes android.bluetooth.BluetoothGattCharacteristic as necessary - * for C++ device::BluetoothRemoteGattCharacteristicAndroid. - * - * Lifetime is controlled by + * Exposes android.bluetooth.BluetoothGattCharacteristic as necessary for C++ * device::BluetoothRemoteGattCharacteristicAndroid. + * + * <p>Lifetime is controlled by device::BluetoothRemoteGattCharacteristicAndroid. */ @JNINamespace("device") @NullMarked @@ -115,6 +115,7 @@ // Implements BluetoothRemoteGattCharacteristicAndroid::GetUUID. @CalledByNative + @JniType("std::string") private String getUUID() { return mCharacteristic.getUuid().toString(); }
diff --git a/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattDescriptor.java b/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattDescriptor.java index 5d3a280..ba6b444 100644 --- a/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattDescriptor.java +++ b/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattDescriptor.java
@@ -8,6 +8,7 @@ import org.jni_zero.CalledByNative; import org.jni_zero.JNINamespace; +import org.jni_zero.JniType; import org.jni_zero.NativeMethods; import org.chromium.base.Log; @@ -15,10 +16,10 @@ import org.chromium.device.bluetooth.wrapper.BluetoothGattDescriptorWrapper; /** - * Exposes android.bluetooth.BluetoothGattDescriptor as necessary - * for C++ device::BluetoothRemoteGattDescriptorAndroid. + * Exposes android.bluetooth.BluetoothGattDescriptor as necessary for C++ + * device::BluetoothRemoteGattDescriptorAndroid. * - * Lifetime is controlled by device::BluetoothRemoteGattDescriptorAndroid. + * <p>Lifetime is controlled by device::BluetoothRemoteGattDescriptorAndroid. */ @JNINamespace("device") @NullMarked @@ -92,6 +93,7 @@ // Implements BluetoothRemoteGattDescriptorAndroid::GetUUID. @CalledByNative + @JniType("std::string") private String getUUID() { return mDescriptor.getUuid().toString(); }
diff --git a/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattService.java b/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattService.java index de58b00..bf736b2 100644 --- a/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattService.java +++ b/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattService.java
@@ -6,6 +6,7 @@ import org.jni_zero.CalledByNative; import org.jni_zero.JNINamespace; +import org.jni_zero.JniType; import org.jni_zero.NativeMethods; import org.chromium.base.Log; @@ -16,11 +17,10 @@ import java.util.List; /** - * Exposes android.bluetooth.BluetoothGattService as necessary - * for C++ device::BluetoothRemoteGattServiceAndroid. - * - * Lifetime is controlled by + * Exposes android.bluetooth.BluetoothGattService as necessary for C++ * device::BluetoothRemoteGattServiceAndroid. + * + * <p>Lifetime is controlled by device::BluetoothRemoteGattServiceAndroid. */ @JNINamespace("device") @NullMarked @@ -63,6 +63,7 @@ // Implements BluetoothRemoteGattServiceAndroid::GetUUID. @CalledByNative + @JniType("std::string") private String getUUID() { return mService.getUuid().toString(); }
diff --git a/device/bluetooth/bluetooth_device_android.cc b/device/bluetooth/bluetooth_device_android.cc index 3b0dfe26..ee28e1cb 100644 --- a/device/bluetooth/bluetooth_device_android.cc +++ b/device/bluetooth/bluetooth_device_android.cc
@@ -17,6 +17,7 @@ #include "base/notimplemented.h" #include "base/stl_util.h" #include "base/task/sequenced_task_runner.h" +#include "base/uuid.h" #include "device/bluetooth/android/outcome.h" #include "device/bluetooth/bluetooth_adapter_android.h" #include "device/bluetooth/bluetooth_common.h" @@ -175,13 +176,9 @@ } if (adapter_->IsPowered()) { - // Java type: String[] - base::android::ScopedJavaLocalRef<jobjectArray> sdp_uuids = + std::vector<std::string> sdp_uuids = Java_ChromeBluetoothDevice_getUuids(AttachCurrentThread(), j_device_); - std::vector<std::string> sdp_uuid_strings; - base::android::AppendJavaStringArrayToStringVector( - AttachCurrentThread(), sdp_uuids, &sdp_uuid_strings); - for (std::string& uuid : sdp_uuid_strings) { + for (std::string& uuid : sdp_uuids) { cached_sdp_uuids_.insert(BluetoothUUID(std::move(uuid))); } }
diff --git a/device/bluetooth/bluetooth_remote_gatt_characteristic_android.cc b/device/bluetooth/bluetooth_remote_gatt_characteristic_android.cc index 4cde795..342c5b0 100644 --- a/device/bluetooth/bluetooth_remote_gatt_characteristic_android.cc +++ b/device/bluetooth/bluetooth_remote_gatt_characteristic_android.cc
@@ -14,6 +14,7 @@ #include "base/logging.h" #include "base/notimplemented.h" #include "base/task/single_thread_task_runner.h" +#include "base/uuid.h" #include "device/bluetooth/bluetooth_adapter_android.h" #include "device/bluetooth/bluetooth_remote_gatt_descriptor_android.h" #include "device/bluetooth/bluetooth_remote_gatt_service_android.h" @@ -78,9 +79,9 @@ } BluetoothUUID BluetoothRemoteGattCharacteristicAndroid::GetUUID() const { - return device::BluetoothUUID(ConvertJavaStringToUTF8( + return device::BluetoothUUID( Java_ChromeBluetoothRemoteGattCharacteristic_getUUID( - AttachCurrentThread(), j_characteristic_))); + AttachCurrentThread(), j_characteristic_)); } const std::vector<uint8_t>& BluetoothRemoteGattCharacteristicAndroid::GetValue()
diff --git a/device/bluetooth/bluetooth_remote_gatt_descriptor_android.cc b/device/bluetooth/bluetooth_remote_gatt_descriptor_android.cc index a2bd6db7..31781b6 100644 --- a/device/bluetooth/bluetooth_remote_gatt_descriptor_android.cc +++ b/device/bluetooth/bluetooth_remote_gatt_descriptor_android.cc
@@ -13,6 +13,7 @@ #include "base/location.h" #include "base/notimplemented.h" #include "base/task/single_thread_task_runner.h" +#include "base/uuid.h" #include "device/bluetooth/bluetooth_remote_gatt_service_android.h" // Must come after all headers that specialize FromJniType() / ToJniType(). #include "device/bluetooth/jni_headers/ChromeBluetoothRemoteGattDescriptor_jni.h" @@ -57,9 +58,8 @@ } BluetoothUUID BluetoothRemoteGattDescriptorAndroid::GetUUID() const { - return device::BluetoothUUID( - ConvertJavaStringToUTF8(Java_ChromeBluetoothRemoteGattDescriptor_getUUID( - AttachCurrentThread(), j_descriptor_))); + return device::BluetoothUUID(Java_ChromeBluetoothRemoteGattDescriptor_getUUID( + AttachCurrentThread(), j_descriptor_)); } const std::vector<uint8_t>& BluetoothRemoteGattDescriptorAndroid::GetValue()
diff --git a/device/bluetooth/bluetooth_remote_gatt_service_android.cc b/device/bluetooth/bluetooth_remote_gatt_service_android.cc index f311854..928423a 100644 --- a/device/bluetooth/bluetooth_remote_gatt_service_android.cc +++ b/device/bluetooth/bluetooth_remote_gatt_service_android.cc
@@ -10,6 +10,7 @@ #include "base/android/jni_string.h" #include "base/logging.h" #include "base/notimplemented.h" +#include "base/uuid.h" #include "device/bluetooth/bluetooth_adapter_android.h" #include "device/bluetooth/bluetooth_device_android.h" #include "device/bluetooth/bluetooth_remote_gatt_characteristic_android.h" @@ -112,9 +113,8 @@ } device::BluetoothUUID BluetoothRemoteGattServiceAndroid::GetUUID() const { - return device::BluetoothUUID(base::android::ConvertJavaStringToUTF8( - Java_ChromeBluetoothRemoteGattService_getUUID(AttachCurrentThread(), - j_service_))); + return device::BluetoothUUID(Java_ChromeBluetoothRemoteGattService_getUUID( + AttachCurrentThread(), j_service_)); } bool BluetoothRemoteGattServiceAndroid::IsPrimary() const {
diff --git a/device/vr/openxr/openxr_device.cc b/device/vr/openxr/openxr_device.cc index e4dce75a..20fe467 100644 --- a/device/vr/openxr/openxr_device.cc +++ b/device/vr/openxr/openxr_device.cc
@@ -31,7 +31,10 @@ mojom::XRSessionFeature::REF_SPACE_UNBOUNDED, mojom::XRSessionFeature::ANCHORS, mojom::XRSessionFeature::HAND_INPUT, - mojom::XRSessionFeature::SECONDARY_VIEWS}}; + mojom::XRSessionFeature::SECONDARY_VIEWS, + mojom::XRSessionFeature::HIT_TEST, + mojom::XRSessionFeature::LIGHT_ESTIMATION, + mojom::XRSessionFeature::DEPTH}}; return *kSupportedFeatures; } @@ -90,19 +93,10 @@ mojom::XRSessionFeature::WEBGPU); } - // Only support AR features if AR is enabled. - if (device::features::IsOpenXrArEnabled()) { + // Only support Plane Detection if the feature flag is enabled. + if (base::FeatureList::IsEnabled(features::kWebXRPlaneDetection)) { device_data.supported_features.emplace_back( - mojom::XRSessionFeature::HIT_TEST); - device_data.supported_features.emplace_back( - mojom::XRSessionFeature::LIGHT_ESTIMATION); - device_data.supported_features.emplace_back(mojom::XRSessionFeature::DEPTH); - - // Only support Plane Detection if the feature flag is enabled. - if (base::FeatureList::IsEnabled(features::kWebXRPlaneDetection)) { - device_data.supported_features.emplace_back( - mojom::XRSessionFeature::PLANE_DETECTION); - } + mojom::XRSessionFeature::PLANE_DETECTION); } SetDeviceData(std::move(device_data));
diff --git a/device/vr/public/cpp/features.cc b/device/vr/public/cpp/features.cc index d1d0c6a..55ecf20 100644 --- a/device/vr/public/cpp/features.cc +++ b/device/vr/public/cpp/features.cc
@@ -48,13 +48,6 @@ BUILDFLAG(IS_WIN) ? base::FEATURE_ENABLED_BY_DEFAULT : base::FEATURE_DISABLED_BY_DEFAULT); -// Some WebXR features may have been enabled for ARCore, but are not yet ready -// to be plumbed up from the OpenXR backend. This feature provides a mechanism -// to gate such support in a generic way. Note that this feature should not be -// used for features we intend to ship simultaneously on both OpenXR and ArCore. -// For those features, a feature-specific flag should be created if needed. -BASE_FEATURE(kOpenXrExtendedFeatureSupport, base::FEATURE_ENABLED_BY_DEFAULT); - // Controls whether the OpenXr runtime is allowed to try to use the spatial // entities framework. BASE_FEATURE(kOpenXrSpatialEntities, base::FEATURE_ENABLED_BY_DEFAULT); @@ -67,28 +60,10 @@ BASE_FEATURE(kOpenXrAndroidSmoothDepth, base::FEATURE_DISABLED_BY_DEFAULT); #endif -// Helper for enabling a feature if either the base flag is enabled or if the -// device is an xr device that can have the feature enabled. This is used since -// we don't have a BUILDFLAG that we can use to enable the feature only on those -// devices. -bool IsXrFeatureEnabled(const base::Feature& base_feature) { - // Generally a reboot is required to change the state of a feature; so we - // use statics rather than const's here to give a slight optimization, - // especially in the case of `is_xr_device`. - static bool feature_enabled = base::FeatureList::IsEnabled(base_feature); - static bool is_xr_device = IsXrDevice(); - - return feature_enabled || is_xr_device; -} - bool IsOpenXrEnabled() { - return IsXrFeatureEnabled(kOpenXR); + static bool is_xr_device = IsXrDevice(); + return base::FeatureList::IsEnabled(kOpenXR) || is_xr_device; } - -bool IsOpenXrArEnabled() { - return IsOpenXrEnabled() && IsXrFeatureEnabled(kOpenXrExtendedFeatureSupport); -} - #endif // ENABLE_OPENXR bool IsXrDevice() {
diff --git a/device/vr/public/cpp/features.h b/device/vr/public/cpp/features.h index e85e868..df78c391 100644 --- a/device/vr/public/cpp/features.h +++ b/device/vr/public/cpp/features.h
@@ -23,10 +23,6 @@ // Note that this feature can be overridden by logic contained within // `IsOpenXrEnabled` and therefore should generally not be queried directly. COMPONENT_EXPORT(VR_FEATURES) BASE_DECLARE_FEATURE(kOpenXR); -// Note that this feature can be overridden by logic contained within -// `IsOpenXrArEnabled` and therefore should generally not be queried directly. -COMPONENT_EXPORT(VR_FEATURES) -BASE_DECLARE_FEATURE(kOpenXrExtendedFeatureSupport); COMPONENT_EXPORT(VR_FEATURES) BASE_DECLARE_FEATURE(kOpenXrSpatialEntities); COMPONENT_EXPORT(VR_FEATURES) BASE_DECLARE_FEATURE(kSpatialEntitesDepthHitTest); #if BUILDFLAG(IS_ANDROID) @@ -38,13 +34,6 @@ // the feature by itself. This should be checked instead of a direct query on // the kOpenXR feature being enabled. COMPONENT_EXPORT(VR_FEATURES) bool IsOpenXrEnabled(); - -// Helper method to check if OpenXR AR should be enabled, this is because we -// want the feature enabled on XrDevices, but don't have a buildflag to cleanly -// set the feature by itself. This should be checked instead of a direct query -// on the kOpenXrExtendedFeatureSupport feature being enabled. -COMPONENT_EXPORT(VR_FEATURES) bool IsOpenXrArEnabled(); - #endif // ENABLE_OPENXR COMPONENT_EXPORT(VR_FEATURES) bool IsXrDevice();
diff --git a/docs/webapps/README.md b/docs/webapps/README.md index 7653e43..66e9c08 100644 --- a/docs/webapps/README.md +++ b/docs/webapps/README.md
@@ -1,338 +1,24 @@ ## Web Apps -### What are web apps? +Web apps are websites with app-like qualities or capabilities. Chromium supports 'installing' a web app (or any website), which is sometimes required for some of these capabilities to function (e.g. file handlers or window controls overlay). -Simply put web apps are sites that the user installs onto their machine mimicking a native app installed on their respective operating system. +See [useful concepts and definitions here](concepts.md). -#### User entry points +### User entry points -Sites that meet our install promotion requirements will have an install prompt appear in the omnibox on the right. Users can also install any site they like via `Menu > More tools > Create shortcut`.... +**Desktop**: If a site has a manifest attached with a name, icon, start_url, and display field specified, an installation icon will appear in the omnibox. Users can also install any site they like via `Menu > More tools > Install Page as App`. Apps are visible on chrome://apps on non-CrOS desktop. +**Android**: An ML model is used to selectively show the blocking installation banner for users who are likely to install the app. Otherwise installation is accessible via `3-dot menu > Add to Homescreen`. -- Example site: https://developers.google.com/ +### Developer interface -Users can see all of their web apps on chrome://apps (viewable on non-ChromeOS). - -#### Developer interface - -Sites customize how their installed site integrates at the OS level using a [web app manifest][2]. See developer guides for in depth overviews: +Sites customize how their installed site integrates at the OS level using a [web app manifest](https://www.w3.org/TR/appmanifest/). See developer guides for in depth overviews: - https://web.dev/progressive-web-apps/ - https://web.dev/codelab-make-installable/ -#### Presentation +## Where is the code? -See [https://tinyurl.com/dpwa-architecture-public][3] for presentation slides. +Because Progressive Web Apps spans across Android and Desktop, the code is split across multiple directories depending on its implementation: -### Terms & Phrases - -See [Web Apps - Concepts][4]. - -### Debugging - -Use [chrome://web-app-internals][5] to inspect internal web app state. For Chromium versions prior to M93 use [chrome://internals/web-app][6]. - -To test the behavior of the web app itself, Chrome DevTools Protocol can be used. See [Instruction of using PWA via CDP][59]. - -### Documentation Guidelines - -- Markdown documentation (files like this): - - Contains information that can't be documented in class-level documentation. - - Answers questions like: What is the goal of a group of classes together? How does a group of classes work together? - - Explains concepts that are used across different files. - - Should be unlkely to become out-of-date. - - Any source links should link to a codesearch 'search' page and not the specific line number. - - Avoid implementation details. -- Class-level documentation (documentation in header files): - - Answers questions like: Why does this class exist? What is the responsibility of this class? If this class involves a process with stages, what are those stages / steps? - - Should be updated actively when that given file is changed. -- Documentation inside of methods - - Should explain the "why" of code if it is not clear. - - Should be avoided otherwise. - -### What makes up Chromium's implementation? - -The task of turning websites into "apps" in the user's OS environment has many parts to it. Before going into the parts, here is where they live: - - - -See source [here][7]. - -- The `WebAppProvider` core system lives on the `Profile` object. -- The `WebAppUiManagerImpl` also lives on the `Profile` object (to avoid deps issues). -- The `AppBrowserController` (typically `WebAppBrowserController` for our interests) lives on the `Browser` object. -- The `WebAppTabHelper` lives on the `WebContents` object. - -While most on-disk storage is done in the [`WebAppSyncBridge`][8], the system also sometimes uses the `PrefService`. Most of these prefs live on the `Profile` (`profile->GetPrefs()`), but some prefs are in the global browser prefs (`g_browser_process->local_state()`). - -Presentation: [https://tinyurl.com/dpwa-architecture-public][3] - -Older presentation: [https://tinyurl.com/bmo-public][9] - -### Architecture Philosophy - -There are a lot of great guidelines within Chromium - -- [Style guides][45] -- [Dos and Don'ts][47] -- etc. - -Other than general guidance of minimal complexity and having single-responsibility classes, some goals of our system: - -- Tests should operate on the [public interface][48] as much as possible. Refactors to the internal system should not involve fixing / modifying tests. -- [External dependencies][49] should be behind fake-able interfaces, allowing unit & browser tests to swap these out. However, internal parts of our system should not be mocked out or faked - this tightly couples the internal implementation to our tests. If it is impossible to trigger a condition with the public interface, then that condition should be removed (or the public interface improved). - - Here is a nice [presentation][44] about testing that might clarify our approach. - -### Public Interface - -This public interface should (and will) be improved, however this is the basic state as of 2022/11/09: - -- `WebAppCommandScheduler`. Internally this schedules `WebAppCommand`s to do safe operations on the system. - - This already includes a variety of operations like installation, launching, etc. -- Observers like the `AppRegistrarObserver` or `WebAppInstallManagerObserver`. However, users of these MUST NOT modify the web app system in the observation call - this can cause race conditions and weird re-entry bugs. -- To query for apps with specific capabilities (like being installable, opening - in a window, etc.), use a [`WebAppFilter`][web-app-filter]. This is the - preferred way to find apps that match a given criteria. -- Items exposed from the locks given to commands or callbacks: - - `WebAppRegistrar` - - Writing to the database using `ScopedRegistryUpdate` and the `WebAppSyncBridge`. - - Pref reading & writing - - `WebAppIconManager` supports icon fetch for a given web app. - - etc - see the documentation on the lock for more guidance. - -Some parts of the system that are used within commands: - -- `WebAppUrlLoader` & `WebAppDataRetriever` are used in commands, but this interface could be improved & does not have a formal factory yet. -- `WebAppInstallFinalizer` is used in commands and could be improved. - -### External Dependencies - -The goal is to have all of these behind an abstraction that has a fake to allow easy unit testing of our system. Some of these dependencies are behind a nice fake-able interface, and some are not (yet). - -- **Extensions** - Some of our code still talks to the extensions system, - specifically the `PreinstalledWebAppManager`. -- **`content::WebContents`**: The WebAppProvider system interacts with - `content::WebContents` for various tasks like loading URLs (via - `WebAppUrlLoader`), retrieving web app manifest data and icons (via - `WebAppDataRetriever` and `WebAppIconDownloader` respectively), and observing - navigations and destruction. The `WebContentsManager` serves as a centralized - point of dependency for these interactions and acts as a factory for these - components, allowing for easier management and faking in tests. -- **OS Integration**: Each OS integration has fairly custom code on each OS to - do the operation. This is difficult to coordinate and test. Currently the - `OsIntegrationManger` manages this, which has a fake version. -- **Sync system**: There is a tight coupling between our system and the sync - system through the WebAppSyncBridge. Faking this is easy and is handled by - the `FakeWebAppProvider`. -- **UI**: There are parts of the system that are coupled to UI, like showing - dialogs, determining information about app windows, etc. These are put behind - the `WebAppUiManager`, and faked by the `FakeWebAppUiManager`. -- **Policy**: Our code depends on the policy system setting its policies in - appropriate prefs for us to read. Because we just look at prefs, we don't - need a "fake" here. - -### Databases / sources of truth - -These store data for our system. Some of it is per-web-app, and some of it is global. - -- **`WebAppRegistrar`**: This attempts to unify the reading of much of this data, and also holds an in-memory copy of the database data (in WebApp objects). -- **`WebAppDatabase`** / **`WebAppSyncBridge`**: This stores the web_app.proto object in a database, which is the preferred place to store information about a web app. -- **Icons on disk**: These are managed by the `WebAppIconManager` and stored on disk in the user's profile. -- **Prefs**: The `PrefService` is used to store information that is either global, or needs to persist after a web app is uninstalled. Most of these prefs live on the `Profile` (`profile->GetPrefs()`), but some prefs are in the global browser prefs (`g_browser_process->local_state()`). Some users of prefs: - - AppShimRegistry - - UserUninstalledPreinstalledWebAppPrefs -- **OS Integration**: Various OS integration requires storing state on the operating system. Sometimes we are able to read this state back, sometimes not. - -None of this information should be accessed without an applicable 'lock' on the system. - -### Managers - -These are used to encapsulate common responsibilities or in-memory state that -needs to be stored. - -#### `WebContentsManager` - -* **Purpose**: Manages dependencies on `content::WebContents` for the - WebAppProvider system. It acts as a factory for `WebAppUrlLoader`, - `WebAppDataRetriever`, and `WebAppIconDownloader`. -* **Key Responsibilities**: - * Provides concrete implementations of URL loading and data retrieval - abstractions. - * Enables the use of fakes for these components in unit tests, reducing - the need for a full browser environment. -* **Location**: - `chrome/browser/web_applications/web_contents/web_contents_manager.h` - -### Commands - -Commands are used to encapsulate operations in the system, and use Locks to -ensure that your operation has isolation from other operations. -- If you need to change something in the WebAppProvider system, you should probably use a command. -- Commands talk to the system using locks they are granted. The locks should offer access to "managers" that the commands can use. -- Commands expose a `ToDebugValue()` method that is logged on completion and exposed in the chrome://web-app-internals. This can be very helpful for debugging and bug reports. - -Note: There are DVLOGs in the `WebAppCommandManager` that can be helpful. - -### Locks / `WebAppLockManager` - -Locks allow operations to receive appropriate protections for what they are doing. For example, an `AppLock` will guarantee that no one is modifying, installing, or uninstalling that AppId while it is granted. - -Locks contain assessors that allow the user to access parts of the web app system. This is the safest way to read from the system. - -Note: There are DVLOGs in the `WebAppLockManager` that can be helpful. - -### OS Integration - -Anything that involves talking to the operating system. Usually has to do with adding, modifying, or removing the os entity that we register for the web app. - -## Deep Dives - -- [/docs/webapps/installation_pipeline.md][34] -- [/docs/webapps/manifest_representations.md][35] -- [/docs/webapps/integration-testing-framework.md][11] -- [/docs/webapps/os_integration.md][50] -- [/docs/webapps/manifest_update_process.md][51] -- [/docs/webapps/isolated_web_apps.md][52] -- [/docs/webapps/webui_web_app.md][54] - -## How To Use - -See the [public interface][48] section about which areas are generally "publicly available". - -The system is generally unit-test-compabible through the [`FakeWebAppProvider`][40], which is created by default in the `TestingProfile`. Sometimes tests require using the [`AwaitStartWebAppProviderAndSubsystems`][41] function in the setup function of the test to actually start the web app system & wait for it to complete startup. See [testing.md][58] for more information. - -There is a long-term goal of having the system be easily fake-able for customers using it. The best current 'public interface' distinction of the system is the `WebAppCommandScheduler`. - -To access or change information about a web app: - -- Obtain a lock from the `WebAppLockManager`, or (preferably) create a command with the relevant lock description. -- When the lock is obtained (or the command is started with the lock), use the lock to access the data you need. - - Generally, you should use the `WebAppRegistrar` to get the data you need. This unifies many of our data sources into one place. -- If changing data, change the data depending on the source of truth. - - For information in the database, use a `ScopedRegistryUpdate`. - - Otherwise use the relevant manager / helper to modify the data. - - Some things expect "observers" to be notified. That integration is currently in `WebAppSyncBridge`, but can be pulled out. - -Other guides: - -- [/docs/webapps/why-is-this-test-failing.md][36] -- [/docs/webapps/how-to-create-webapp-integration-tests.md][37] - -## Debugging - -### chrome://web-app-internals - -This page allows you to see all of the internal information about the WebAppProvider system, including a truncated log of the debug information of the last run commands. - -It is often very useful to ask users to attach a copy of this page in bug reports. - -The integration tests will print out the [contents of this page][57] if a test fails, which can help debug that failure as well. - -### DVLOGs - -The codebase has a number of useful DVLOGs: -- web_app_command_manager.cc: These will log various state changes of commands and the debug values on completion. -- web_app_lock_manager.cc: This will log lock requests and any 'held or pending' lock holders for the requested lock at the time of the request. This does not necessarily mean those locks are blocking (as they may be shared locks) so you will have to look at the request locations to determine the status. - -## Testing - -Please see [testing.md][58]. - -## Relevant Classes - -#### [`WebAppProvider`][12] - -This is a per-profile object housing all the various web app subsystems. This is the "main()" of the web app implementation where everything starts. - -#### [`WebApp`][13] - -This is the representation of an installed web app in RAM. Its member fields largely reflect all the ways a site can configure their [web app manifest][2] plus miscellaneous internal bookkeeping and user settings. - -#### [`WebAppRegistrar`][14] - -This is where all the [`WebApps`][13] live in memory, and what many other subsystems query to look up any given web app's fields. Mutations to the registry have to go via ScopedRegistryUpdate or [WebAppSyncBridge][16]. - -Accessing the registrar should happen through a Lock. If you access it through the `WebAppProvider`, then know that you are reading uncommitted (and thus unsafe) data. - -Why is it full of `GetAppXYZ()` getters for every field instead of just returning a `WebApp` reference? This is primarily done because the value may depend on multiple sources of truth. For example, whether the app should be run on OS login depends on both the user preference (stored in our database) and the administrator's policy (stored separately & given to us in-memory using prefs) Historically this was originally done because WebApps used be stored both in our database and extensions, and this served to unify the two. - -#### [`WebAppSyncBridge`][16] - -This is "bridge" between the WebAppProvider system's in-memory representation of web apps and the sync system's database representation (along with sync system functionality like add/remove/modify operations). This integration is a little complex and deserves it's own document, but it basically: _Stores all WebApps into a database and updates the database if any fields change_. Updates the system when there are changes from the sync system. _Installs new apps, uninstalls apps the user uninstalled elsewhere, updates metadata like user display mode preference, etc_. Tells the sync system if there are local changes (installs, uninstalls, etc). - -There is also a slide in a presentation [here][18] which illustrates how this system works, but it may be out of date. - -Note: This only stores per-web-app data, and that data will be deleted if the web app is uninstalled. To store data that persists after uninstall, or applies to a more general scope than a single web app, then the `PrefService` can be used, either on the `Profile` object (per-profile data, `profile->GetPrefs()`) or on the browser process `(`g_browser_process->local_state()``). Example of needing prefs: Storing if an app was previously installed as a preinstalled app in the past. Information is needed during chrome startup before profiles are loaded. A feature needs to store global data - e.g. "When was the last time we showed the in-product-help banner for any webapp?" - -#### [`ExternallyManagedAppManager`][19] - -This is for all installs that are not initiated by the user. This includes [preinstalled apps][20], [policy installed apps][21] and [system web apps][22]. - -These all specify a set of [install URLs][23] which the `ExternallyManagedAppManager` synchronises the set of currently installed web apps with. - -#### [`WebAppInstallFinalizer`][24] - -This is the tail end of the installation process where we write all our web app metadata to [disk][25] and deploy OS integrations (like [desktop shortcuts][26] and [file handlers][27] using the [`OsIntegrationManager`][28]. - -#### [`WebAppUiManager`][29] - -Sometimes we need to query window state from chrome/browser/ui land even though our BUILD.gn targets disallow this as it would be a circular dependency. This [abstract class][30] + [impl][31] injects the dependency at link time (see [`WebAppUiManager::Create()`'s`][32] `declaration and definition locations`). - -#### [`AppShimRegistry`][33] - -On Mac OS we sometimes need to reason about the state of installed PWAs in all profiles without loading those profiles into memory. For this purpose, `AppShimRegistry` stores the needed information in Chrome's "Local State" (global preferences). The information stored here includes: - - - All profiles a particular web app is installed in. - - What profiles a particular web app was open in when it was last used. - - What file and protocol handlers are enabled for a web app in each profile it is installed in. - -This information is used when launching a web app (to determine what profile or profiles to open the web app in), as well as when updating an App Shim (to make sure all file and protocol handlers for the app are accounted for). - -[2]: https://www.w3.org/TR/appmanifest/ -[3]: https://tinyurl.com/dpwa-architecture-public -[4]: concepts.md -[5]: chrome://web-app-internals -[6]: chrome://internals/web-app -[7]: https://docs.google.com/drawings/d/1TqUF2Pqh2S5qPGyA6njQWxOgSgKQBPePKPIH_srGeRk/edit?usp=sharing -[8]: #webappsyncbridge -[9]: https://tinyurl.com/bmo-public -[11]: integration-testing-framework.md -[12]: /chrome/browser/web_applications/web_app_provider.h -[13]: /chrome/browser/web_applications/web_app.h -[14]: /chrome/browser/web_applications/web_app_registrar.h -[16]: /chrome/browser/web_applications/web_app_sync_bridge.h -[18]: https://docs.google.com/presentation/d/e/2PACX-1vQxYZoCyhZ4xHS4pVuBC9YoE0O-QpW2Wj3scl6jtr3TEYheeod5Ch4b7OVEQEj_Hc6PM1RBGzovug3C/pub?start=false&loop=false&delayms=3000&slide=id.g59d9cb05b6_6_5 -[19]: /chrome/browser/web_applications/externally_managed_app_manager.h -[20]: /chrome/browser/web_applications/preinstalled_web_app_manager.h -[21]: /chrome/browser/web_applications/policy/web_app_policy_manager.h -[22]: /chrome/browser/ash/system_web_apps/system_web_app_manager.h -[23]: /chrome/browser/web_applications/external_install_options.h -[24]: /chrome/browser/web_applications/web_app_install_finalizer.h -[25]: /chrome/browser/web_applications/web_app_database.h -[26]: /chrome/browser/web_applications/os_integration/web_app_shortcut.h -[27]: /chrome/browser/web_applications/os_integration/web_app_file_handler_manager.h -[28]: /chrome/browser/web_applications/os_integration/os_integration_manager.h -[29]: /chrome/browser/ui/web_applications/web_app_ui_manager_impl.h -[30]: /chrome/browser/web_applications/web_app_ui_manager.h -[31]: /chrome/browser/ui/web_applications/web_app_ui_manager_impl.h -[32]: https://source.chromium.org/search?q=WebAppUiManager::Create -[33]: /chrome/browser/web_applications/app_shim_registry_mac.h -[34]: installation_pipeline.md -[35]: manifest_representations.md -[36]: why-is-this-test-failing.md -[37]: how-to-create-webapp-integration-tests.md -[38]: /chrome/browser/ui/web_applications/web_app_browsertest.cc -[40]: /chrome/browser/web_applications/test/fake_web_app_provider.h -[41]: https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/web_applications/test/web_app_install_test_utils.cc;l=40?q=AwaitStartWebAppProviderAndSubsystems&ss=chromium -[44]: https://www.youtube.com/watch?v=EZ05e7EMOLM -[45]: /styleguide/styleguide.md -[47]: /styleguide/c++/c++-dos-and-donts.md -[48]: #public-interface -[49]: #external-dependencies -[50]: os_integration.md -[51]: manifest_update_process.md -[52]: isolated_web_apps.md -[54]: webui_web_app.md -[57]: https://source.chromium.org/search?q=WebAppInternalsHandler::BuildDebugInfo -[58]: testing.md -[59]: cdp-integration.md -[web-app-filter]: /chrome/browser/web_applications/web_app_filter.h +* **[Desktop `WebAppProvider`](/chrome/browser/web_applications/README.md)**: Desktop-specific system (Windows, Mac, Linux, ChromeOS) for installing and managing web apps. +* **[Shared `components/webapps`](/components/webapps/README.md)**: Code shared between Android and Desktop, like the `InstallableManager` and `AppBannerManager`.
diff --git a/docs/webapps/concepts.md b/docs/webapps/concepts.md index 77d6fc5..f80825d 100644 --- a/docs/webapps/concepts.md +++ b/docs/webapps/concepts.md
@@ -2,9 +2,9 @@ ### Manifest, or WebManifest -This refers to the document described by the [appmanifest][2] spec, with some extra features described by [manifest-incubations][3]. This document describes metadata and developer configuration of an installable web app. +This refers to the document described by the [appmanifest](https://www.w3.org/TR/appmanifest/) spec, with some extra features described by [manifest-incubations](https://wicg.github.io/manifest-incubations/index.html). This document describes metadata and developer configuration of an installable web app. -For code representations of the manifest see [the list][4]. +For code representations of the manifest see [the list](/chrome/browser/web_applications/docs/manifest_representations.md). ### Manifest Link @@ -14,31 +14,31 @@ <link rel="manifest" href="manifest.webmanifest"> ``` -This link ties the manifest to the document, and subsequently used in the spec algorithms defined in [appmanifest][2] or [manifest-incubations][3] to describe the webapp and determine if it is installable. +This link ties the manifest to the document, and subsequently used in the spec algorithms defined in [appmanifest](https://www.w3.org/TR/appmanifest/) or [manifest-incubations](https://wicg.github.io/manifest-incubations/index.html) to describe the webapp and determine if it is installable. ### Installable -If a document or page is considered "installable", then the user agent can create some form of installed web app for that page. To be installable, [web_app::CanCreateWebApp][5] must return true, where: +If a document or page is considered "installable", then the user agent can create some form of installed web app for that page. To be installable, [web_app::CanCreateWebApp](https://source.chromium.org/search?q=f:web_app_utils.h%20CanCreateWebApp) must return true, where: - The user profile must allow webapps to be installed - The web contents of the page must not be crashed - The last navigation on the web contents must not be an error (like a 404) - The url must be `http, https`, or `chrome-extension` -This is different from [promotable][6] below, which determines if Chrome will promote installation of the page. +This is different from [promotable](#promotable) below, which determines if Chrome will promote installation of the page. ### Promotable A document is considered "promotable" if it fulfills a set of criteria. This criteria may change to further encourage a better user experience for installable web apps. There are also a few optional checks that depend on the promotability checker. This general criteria as of 2022/09/08: - _The document contains a manifest link_. -- The linked manifest can be processed [according][7] to the spec and is valid. +- The linked manifest can be processed [according](https://www.w3.org/TR/appmanifest/#processing) to the spec and is valid. - The processed manifest contains the fields: - `name` - `start_url` - `icons` with at least one icon with a valid response that is a parsable image. - `display` field that is not `"browser`" -- "Serviceworker check": The `start_url` is 'controlled' (can be served by) a [serviceworker][8] with a fetch handler. **Optionally turned off** +- "Serviceworker check": The `start_url` is 'controlled' (can be served by) a [serviceworker](https://developers.google.com/web/ilt/pwa/introduction-to-service-worker) with a fetch handler. **Optionally turned off** - Note: This is expected to be removed in Q4 2022. - _"Engagement check": The user has engaged with, or interacted with, the page or origin a certain amount (currently at least one click and some seconds on the site). **Optionally turned off**_ @@ -50,9 +50,9 @@ ### Manifest id -The `id` specified in the manifest represents the identity of the web app. The manifest id is processed following the algorithm described in [appmanifest specification][9] to produce the app's identity. In the web app system, the app's [identifier][10] is [hashed][11] to be stored to [WebApp->app_id()][12]. +The `id` specified in the manifest represents the identity of the web app. The manifest id is processed following the algorithm described in [appmanifest specification](https://www.w3.org/TR/appmanifest/#id-member) to produce the app's identity. In the web app system, the app's [identifier](https://www.w3.org/TR/appmanifest/#dfn-identity) is [hashed](https://source.chromium.org/search?q=f:web_app_helpers.h%20GenerateAppIdFromManifestId) to be stored to [WebApp->app_id()](https://source.chromium.org/search?q=f:web_app.h%20WebApp::app_id). -If a manifest is discovered during any sort of page load, then the update process is initiated for that manifest. If it resolves to an `app_id` that is installed, then it will perform an update. See [documentation][20] for more information. +If a manifest is discovered during any sort of page load, then the update process is initiated for that manifest. If it resolves to an `app_id` that is installed, then it will perform an update. See [documentation](/chrome/browser/web_applications/docs/manifest_update_process.md) for more information. ### Scope @@ -69,122 +69,8 @@ ### Display Mode -The `display` of a web app determines how the developer would like the app to look like to the user. See the [spec][13] for how the `display` member is processed in the manifest and what the display modes mean. - -### User Display Mode - -In addition to the developer-specified [`display`][14], the user can specify how they want a WebApp to be displayed, with the only option being whether to "open in a window" or not. Internally, this is expressed in the same display mode enumeration type as [`display`][14], but only the `kStandalone` and `kBrowser` values are used to specify "open in a window" and "do not open in a window", respectively. - -#### Effective Display Mode - -The pseudocode to determine the ACTUAL display mode a WebApp is displayed is: - -```js -if (user_display_mode == kStandalone) - return developer_specified_display_mode; -else - return kBrowser; // Open in a tab. -``` - -#### Open-in-window - -This refers to the user specifying that a WebApp should open in the developer specified display mode. - -#### Open-in-browser-tab - -This refers to the user specifying that a WebApp should NOT open in a window, and thus the WebApp, if launched, will just be opened in a browser tab. - -### App Management - -Each app has one or more 'management source', specified by the [`WebAppManagement`][17] enumeration. This signifies the system that is 'managing' the install, AKA responsible for installing or uninstalling the app. Internally, the web app system will ensure that the app will only be uninstalled if there are no sources left in the app. - -When a user installs an app, the `kSync` management source is specified, because user installs are considered 'managed' by the sync system (and installs will by synced to all devices). See the [`WebAppManagement`][17] enumeration for the description of other management sources. - -Installation by certain sources can cause the app to no longer be "uninstallable" by the user. The method [`CanUserUninstallWebApp`][18] function determines if this is the case. - -#### Placeholder app - -There are some webapps which are managed by external sources - for example, the enterprise policy force-install apps, or the system web apps for ChromeOS. These are generally not installed by user interaction, and the WebAppProvider needs to install something for each of these apps. - -Sometimes, the installation of these apps can fail because the install url is not reachable (usually a cert or login needs to occur, and the url is redirected). When this happens, the system [can][15] install a "placeholder" app, which is a fake application that, when launched, navigates to the install url of the application, given by the external app manager. - -To resolve placeholder apps back into the intended installation, another external -install is triggered for the same install URL. The -[ExternalAppResolutionCommand][19] is given the ID of the existing -placeholder app. After the new app is successfully installed, the -placeholder app is uninstalled. - -### Installation State - -A web app can exist in several different installation states, which determine -its capabilities and how it's presented to the user. These states are -represented internally by the [`InstallState` enum][install-state-proto]. - -* **Suggested from another device**: The app is installed on another one of - the user's devices and has been synced to the current device, but it - hasn't been fully installed yet. These apps appear in `chrome://apps` (often - grayed out) but don't have OS integrations like shortcuts or protocol - handlers. They cannot be launched in a standalone window until they are - fully installed. This state corresponds to - `InstallState::SUGGESTED_FROM_ANOTHER_DEVICE`. - -* **Installed without OS integration**: The app is installed on the device, - but without any OS-level integrations. This is common for pre-installed - apps on non-ChromeOS platforms. Like suggested apps, they cannot be - launched in a standalone window until OS integration is enabled. This state - corresponds to `InstallState::INSTALLED_WITHOUT_OS_INTEGRATION`. - -* **Installed with OS integration**: The app is fully installed and - integrated with the operating system. This includes shortcuts, protocol - handling, file handling, and the ability to run on OS login. This is the - state for user-installed apps or apps that have had their OS integration - explicitly triggered. This state corresponds to - `InstallState::INSTALLED_WITH_OS_INTEGRATION`. - -To query for apps with specific capabilities, which often depend on their -installation state, the [`WebAppFilter`][web-app-filter] class should be used. -For example, `WebAppFilter::IsSuggestedApp()` can be used to find apps that are -suggested from another device. - -#### Triggering a full installation - -For an app that is only "suggested" or "installed without OS integration", a -full installation with OS integration can be triggered by: - -* The user installing the app again through a normal installation flow (e.g., - the omnibox install icon). -* The user right-clicking the app on `chrome://apps` and selecting "Install". -* Programmatically, by scheduling an - [`InstallAppLocallyCommand`][install-app-locally-command]. - -This was designed this way because on non-ChromeOS devices, it was considered a -bad user experience to fully install all of a user's synced web apps (creating -platform shortcuts, etc.), as this might not be expected by the user on a new -device. +The `display` of a web app determines how the developer would like the app to look like to the user. See the [spec](https://www.w3.org/TR/appmanifest/#display-modes) for how the `display` member is processed in the manifest and what the display modes mean. ### Isolated Web Apps -See [this document][21] for more information. - -[2]: https://www.w3.org/TR/appmanifest/ -[3]: https://wicg.github.io/manifest-incubations/index.html -[4]: manifest_representations.md -[5]: https://source.chromium.org/search?q=f:web_app_utils.h%20CanCreateWebApp -[6]: #promotable -[7]: https://www.w3.org/TR/appmanifest/#processing -[8]: https://developers.google.com/web/ilt/pwa/introduction-to-service-worker -[9]: https://www.w3.org/TR/appmanifest/#id-member -[10]: https://www.w3.org/TR/appmanifest/#dfn-identity -[11]: https://source.chromium.org/search?q=f:web_app_helpers.h%20GenerateAppIdFromManifestId -[12]: https://source.chromium.org/search?q=f:web_app.h%20WebApp::app_id -[13]: https://www.w3.org/TR/appmanifest/#display-modes -[14]: #display-mode -[15]: https://source.chromium.org/search?q=ExternalInstallOptions::install_placeholder -[17]: https://source.chromium.org/search?q=f:web_app_management_type.h%20WebAppManagement::Type -[18]: https://source.chromium.org/search?q=f:web_app.h%20CanUserUninstallWebApp -[19]: https://source.chromium.org/search?q=ExternalAppResolutionCommand -[20]: manifest_update_process.md -[21]: isolated_web_apps.md -[install-state-proto]: /chrome/browser/web_applications/proto/web_app_install_state.proto -[web-app-filter]: /chrome/browser/web_applications/web_app_filter.h -[install-app-locally-command]: /chrome/browser/web_applications/commands/install_app_locally_command.h +See [this document](/chrome/browser/web_applications/docs/isolated_web_apps.md) for more information.
diff --git a/docs/webapps/installation_pipeline.md b/docs/webapps/installation_pipeline.md deleted file mode 100644 index 7405182ce..0000000 --- a/docs/webapps/installation_pipeline.md +++ /dev/null
@@ -1,146 +0,0 @@ -## [Web Apps][2] - Installation - -Installing a webapp can come from a variety of channels. This section serves to enumerate them all and show how they fit together in the installation pipeline. - -### Flowchart - -Here is a graphic of the installation flow: - - - -[https://tinyurl.com/dpwa-installation-flowchart][4] - -Note: The ExternallyManagedAppManager adds a few steps before this, and will sometimes (for placeholder apps) build a custom `WebAppInstallInfo` object to skip the 'build' steps. - -### Installation Commands - -There are a variety of [commands][5] used to install web apps. If introducing a new installation source, consider making a new command to isolate your operation (and prevent it from being complicated by other use-cases). - -### Installation Sources - -There are a variety of installation sources and expectations tied to those sources. - -#### Omnibox install icon - -User-initiated installation. To make the omnibox install icon visible, the document must: _Be promotable and installable_. NOT be inside of the scope of an installed WebApp with an effective [display mode display][6] mode that isn't `kBrowser`. - -Triggers an install view that will show the name & icon to the user to confirm install. If the manifest also includes screenshots with a wide form-factor, then a more detailed install dialog will be shown. - -This uses the [`FetchManifestAndInstallCommand`][7], providing just the `WebContents` of the installable page. - -Fails if, after the user clicks : _After clicking on the install icon, the `WebContents` is no longer_ [_promotable_][8], _skipping engagement checks_. The user rejects the installation dialog. - -#### 3-dot menu option "Install {App_Name}..." - -User-initiated installation. To make the install menu option visible, the document must: _Be promotable and installable_. NOT be inside of the scope of an installed WebApp with an effective [display mode display][6] mode that isn't `kBrowser`. - -Triggers an install view that will show the name & icon to the user to confirm install. If the manifest also includes screenshots with a wide form-factor, then a more detailed install dialog will be shown. - -Calls [`FetchManifestAndInstallCommand`][7] with the `WebContents` of the installable page, and `fallback_behavior = FallbackBehavior::kUseFallbackInfoWhenNotInstallable`. - -Fails if: _The user rejects the installation dialog_. - -Notably, this option does not go through the same exact pathway as the [omnibox install icon][10], as it shares the call-site as the "Create Shortcut" method below. The main functional difference here is that if the site becomes no longer [promotable][8] in between clicking on the menu option and the install actually happening, it will not fail and instead fall back to a fake manifest and/or fake icons based on the favicon. Practically, this option doesn't show up if the site is not [promotable][8]. Should it share installation pathways as the the [omnibox install icon?][10] Probably, yes. - -#### 3-dot menu option "Create Shortcut..." - -User-initiated installation. This menu option is always available, except for internal chrome urls like chrome://settings. - -Prompts the user whether the shortcut should "open in a window". If the user checks this option, then the resulting WebApp will have the [user display][11] set to `kStandalone` / open-in-a-window. - - -The document does not need to have a manifest for this install path to work. If no manifest is found, then a fake one is created with `start_url` equal to the document url, `name` equal to the document title, and the icons are generated from the favicon (if present). - -Calls [`FetchManifestAndInstallCommand`][7] with the `WebContents` of the installable page, and `fallback_behavior = FallbackBehavior::kAllowFallbackDataAlways`. - -Fails if: _The user rejects the shortcut creation dialog_. - -#### Externally Managed Apps - -These installations are more customizable than user installations, as these external app management surfaces need to specify all of the options up front (e.g. create shortcut on desktop, open in window, run on login, etc). The [`ExternalAppResolutionCommand`][14] is used for this purpose. - -The general installation flow of an externally managed app is: - -1. A call to [`ExternallyManagedAppProvider::SynchronizeInstalledApps`][16] -1. Finding all apps that need to be uninstalled and uninstalling them, find all - apps that need to be installed and: -1. Enqueue an `ExternalAppResolutionCommand` for each app to start resolving - what the final behavior should be. -1. Each command loads the url for the app. -1. If the url is successfully loaded, the command proceeds with a regular - installation pipeline (fetching manifest, icons, etc). -1. If the url fails to fully load (usually a redirect if the user needs to sign - in or corp credentials are not installed), and the external app manager - specified a [placeholder app was required][18] then an `InstallPlaceholderJob` - is used to install a placeholder app. - -These placeholder apps are not meant to stay, and to replace them with the intended apps, the following occurs: - -1. When a new installation is triggered for the same install URL, the - `ExternalAppResolutionCommand` is given the ID of the existing placeholder - app. -1. After the new app is successfully installed, the placeholder app is - uninstalled. - -#### Sync - -When an app is installed via sync on a non-ChromeOS device, it is initially -installed in a "suggested" state (`InstallState::SUGGESTED_FROM_ANOTHER_DEVICE`) -without full OS integration. See [Installation State][23] in the concepts doc -for more details. On ChromeOS, synced apps are always fully installed with OS -integration. - -##### Retry on startup - -Sync installs have a few extra complications: - -- They need to be immediately saved to the database & be installed eventually. -- Many are often queued up during a new profile sign-in, and it's not uncommon for the user to quit before the installation queue finishes. - -Due to this, unlike other installs, a special [`WebApp::is_from_sync_and_pending_installation`][24] (protobuf variable is saved in the database. WebApps with this set to true are treated as not fully installed, and are often left out of app listings. This variable is reset back to `false` when the app is finished installing. - -To handle the cases above, on startup when the database is loaded, any WebApp with `is_from_sync_and_pending_installation` of `true` will be re-installed inside of [`WebAppSyncBridge::MaybeInstallAppsFromSyncAndPendingInstallation`][25] - -### Installation State Modifications - -#### Triggering a full installation - -On non-ChromeOS devices, an app can be in a "suggested" state (e.g. from sync) -or "installed without OS integration" (e.g. preinstalled). To trigger a full -installation with OS integration, the user can: -* Install the app again via a normal installation flow (e.g. using the - omnibox install icon). -* Right-click the app on `chrome://apps` and select "Install". - -Programmatically, this is handled by the [`InstallAppLocallyCommand`][26]. - -#### Creating Shortcuts - - -On non-ChromeOS devices, an app can be [not locally installed][23]. To become locally installed, the user can follow a normal install method (the install icon will show up), or they can interact with the app on `chrome://apps`. - -The `chrome://apps` code is unique here, and instead of re-installing the app, it schedules an [`InstallAppLocallyCommand`][26] to set the app as locally installed and trigger OS integration. - -#### Creating Shortcuts - -Similarly to above, in `chrome://apps` the user can "Create Shortcuts..." for a web app. This should overwrite any shortcuts already created, and basically triggers OS integration to install shortcuts again via an [`OsIntegrationSynchronizeCommand`][27]. - -[2]: README.md -[4]: https://tinyurl.com/dpwa-installation-flowchart -[5]: https://source.chromium.org/search?q=f:install%20f:web_applications%2Fcommands&sq=&ss=chromium -[6]: concepts.md#effective-display-mode -[7]: https://source.chromium.org/search?q=FetchManifestAndInstallCommand&ss=chromium -[8]: concepts.md#promotable -[10]: #omnibox-install-icon -[11]: concepts.md#user-display-mode -[14]: https://source.chromium.org/search?q=ExternalAppResolutionCommand&sq=&ss=chromium%2Fchromium%2Fsrc -[15]: https://source.chromium.org/search?q=f:web_app_install_utils.h%20"ApplyParamsToFinalizeOptions" -[16]: https://source.chromium.org/search?q=ExternallyManagedAppProvider::SynchronizeInstalledApps -[17]: #flowchart -[18]: https://source.chromium.org/search?q=ExternalInstallOptions::install_placeholder -[21]: https://source.chromium.org/search?q=f:install_from_sync_command.h -[23]: concepts.md#installation-state -[24]: https://source.chromium.org/search?q=WebApp::is_from_sync_and_pending_installation -[25]: https://source.chromium.org/search?q=WebAppSyncBridge::MaybeInstallAppsFromSyncAndPendingInstallation -[26]: https://source.chromium.org/search?q=InstallAppLocallyCommand -[27]: https://source.chromium.org/search?q=OsIntegrationSynchronizeCommand
diff --git a/docs/webapps/manifest_update_process.md b/docs/webapps/manifest_update_process.md deleted file mode 100644 index 403c9c0..0000000 --- a/docs/webapps/manifest_update_process.md +++ /dev/null
@@ -1,79 +0,0 @@ -# Manifest Update Process - -High level information: https://web.dev/manifest-updates/ - -The manifest update process is required whenever a new manifest is served to an existing web_app, which would mean that the database entries corresponding to that web application needs to be updated. With the [predictable app updating flag enabled][0], the following information sheds some light on how the -manifest update system works in Chrome. - -## Things to note: -- Updates to security sensitive fields [1] (like `name`, `icon` and `short_name`) require explicit user approval. -- Updates to the app's icon follow the `Cache-Control:immutable` behavior of HTML, where updates are triggered **ONLY** if the icon url has changed. - - If the icon url **HAS** changed, but the a pixel by pixel comparison of the old and new icon shows a difference of <10%, the icon is updated silently. -- Updates to non-security sensitive fields are silent. - -This helps ensure: -- Network resources are saved and that icons are downloaded ONLY if the corresponding metadata for them have changed. -- Developers have a way of choosing when to trigger an update to their app's identities. -- The UX affordances are designed in a way to provide more control to the user on -what to do, should there be user intervention required for an update. - -## Steps to trigger a manifest update: -Whenever the tab has kicked off a [navigation to an url for a web_app][2], a check is kicked off to determine if a manifest update is required or not. The update process is aborted if the following conditions are satisfied: - - If the app is not installed. - - If the installed app is a [System Web App][3], [placeholder app][4] or [Isolated Web App][5]. - -Once the update is allowed to proceed, the following steps happen: - - Wait for the [page to finish loading and the manifest url to be loaded][7]. - - On successful page load, the [`ManifestSilentUpdateCommand`][8] takes over to perform the following tasks: - - Fetching the manifest and all metadata defined in it for the url. - - Identifying if the update can be done silently, or it requires user intervention, or both. - - Parts of the update that happen silently is completed. - - If user intervention is required, pending update metadata is stored in the web app. - - As an implementation detail, for icon changes, the "new icons" are also stored on the disk inside the profile directory to conserve network resources and prevent [redownloading][9]. - -## Steps to apply pending updates: - -If the update requires user intervention, that is surfaced to the user in a non-blocking way -by showing an expanded label saying [`App Update Available`][10] in a standalone app window. Apps running in a browser tab do not see that label. - -Clicking that label triggers the three dot menu dropdown, that has a `Review App Update` entrypoint. Clicking on that triggers the [`WebAppUpdateReviewDialog`][11], which shows the before and after state of the app. The metadata to show on the dialog is collected by the [`AppUpdateDataReadCommand`][12]. - -The user can choose to either: -- Ignore the update: The expanded label on the app window's three dot menu is no longer shown, unless a new update appears. -- Accept the update: The [`ApplyPendingManifestUpdateCommand`][13] is triggered which applies any pending updates to the metadata and icons. -- Uninstall the app: Remove the app if they're not sure if the app update was malicious or not. - -# Testing - -- [`WebAppIntegrationTestDriver`][14] contains browser tests for the entire end-to-end working of the manifest update process. Please look at the [critical user journeys][15] and [integration testing framework][16] for more documentation on how to parse these -tests. -- [`ManifestSilentUpdateCommandTest`][17] contains unit tests for the determination -part of the manifest update operation that determines if the updates need to happen -silently, or if pending data needs to be stored. -- [`ManifestSilentUpdateCommandBrowserTest`][20] contains browser tests for the determination part of the manifest update operation, that requires an active browser window to be available, for example, to check if the expanded label is available for pending updates. -- [`ApplyPendingManifestUpdateCommandTest`][18] contains unit tests for the application of pending updates to the web app database as well as icons stored on the disk. -- [`WebAppUpdateReviewDialogBrowserTests`][19] contains browser tests for the end to end -flow, including the triggering of the dialog and verification of the expanded label -available on the web app. - -[0]: https://source.chromium.org/chromium/chromium/src/+/main:content/public/common/content_features.cc?q=%22kWebAppPredictableAppUpdating%22%20f:.*_features.cc&ss=chromium%2Fchromium%2Fsrc -[1]: https://www.w3.org/TR/appmanifest/#dfn-security-sensitive-members -[2]: https://source.chromium.org/search?q=WebAppTabHelper::PrimaryPageChanged -[3]: https://source.chromium.org/search?q=SystemWebAppManager -[4]: https://source.chromium.org/search?q=Placeholder%20f:webapps%2Fconcepts.md -[5]: https://source.chromium.org/search?q=%22WebAppFilter::IsIsolatedApp%22&sq=&ss=chromium%2Fchromium%2Fsrc -[6]: https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/web_applications/manifest_update_manager.h -[7]: https://source.chromium.org/search?q=ManifestUpdateManager%20PreUpdateWebContentsObserver&sq= -[8]: https://source.chromium.org/search?q=ManifestSilentUpdateCommand&sq= -[9]: https://source.chromium.org/search?q=WebAppIconManager::WritePendingIconData -[10]: https://source.chromium.org/search?q=WebAppMenuButton::CanShowPendingUpdate&sq= -[11]: https://source.chromium.org/search?q=WebAppUpdateReviewDialog&sq=&ss=chromium%2Fchromium%2Fsrc -[12]: https://source.chromium.org/search?q=AppUpdateDataReadCommand&ss=chromium%2Fchromium%2Fsrc -[13]: https://source.chromium.org/search?q=ApplyPendingManifestUpdateCommand&sq=&ss=chromium%2Fchromium%2Fsrc -[14]: https://source.chromium.org/search?q=WebAppIntegrationTestDriver&ss=chromium%2Fchromium%2Fsrc -[15]: https://source.chromium.org/chromium/chromium/src/+/main:chrome/test/webapps/data/critical_user_journeys.md?q=%22App%20identity%20updating%22%20f:critical_user_journeys.md&ss=chromium%2Fchromium%2Fsrc -[16]: https://source.chromium.org/chromium/chromium/src/+/main:chrome/test/webapps/data/critical_user_journeys.md?q=%22App%20identity%20updating%22%20f:critical_user_journeys.md&ss=chromium%2Fchromium%2Fsrc -[17]: https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/web_applications/commands/manifest_silent_update_command_unittest.cc -[18]: https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/web_applications/commands/apply_pending_manifest_update_command_unittest.cc -[19]: https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/ui/views/web_apps/web_app_update_review_dialog_browsertest.cc -[20]: https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/web_applications/commands/manifest_silent_update_command_browsertest.cc \ No newline at end of file
diff --git a/docs/website b/docs/website index 42a6e5a..86cb4eb 160000 --- a/docs/website +++ b/docs/website
@@ -1 +1 @@ -Subproject commit 42a6e5a316866471cb6a8792794523e4520b8d90 +Subproject commit 86cb4eb2aa8ddc985c6ffd29bb696398dbc0a8d6
diff --git a/gpu/command_buffer/service/dawn_context_provider.cc b/gpu/command_buffer/service/dawn_context_provider.cc index f4b915f..e2d38f8 100644 --- a/gpu/command_buffer/service/dawn_context_provider.cc +++ b/gpu/command_buffer/service/dawn_context_provider.cc
@@ -59,6 +59,8 @@ #if BUILDFLAG(DAWN_ENABLE_BACKEND_OPENGLES) #include "third_party/dawn/include/dawn/native/OpenGLBackend.h" +#include "ui/gl/gl_bindings.h" +#include "ui/gl/gl_context.h" #include "ui/gl/gl_surface_egl.h" #endif @@ -835,6 +837,8 @@ #if BUILDFLAG(DAWN_ENABLE_BACKEND_OPENGLES) dawn::native::opengl::RequestAdapterOptionsGetGLProc adapter_options_get_gl_proc = {}; + dawn::native::opengl::RequestAdapterOptionsAngleVirtualizationGroup group = + {}; if (adapter_options.backendType == wgpu::BackendType::OpenGLES) { adapter_options_get_gl_proc.getProc = gl::GetGLProcAddress; gl::GLDisplayEGL* gl_display = gl::GLSurfaceEGL::GetGLDisplayEGL(); @@ -845,6 +849,12 @@ } adapter_options_get_gl_proc.nextInChain = adapter_options.nextInChain; adapter_options.nextInChain = &adapter_options_get_gl_proc; + if (gl_display->ext->b_EGL_ANGLE_context_virtualization) { + group.angleVirtualizationGroup = static_cast<GLuint>( + gl::AngleContextVirtualizationGroup::kGraphiteDawnSharedContext); + group.nextInChain = adapter_options.nextInChain; + adapter_options.nextInChain = &group; + } } #endif
diff --git a/gpu/command_buffer/service/shared_image/d3d_image_backing.cc b/gpu/command_buffer/service/shared_image/d3d_image_backing.cc index 9dbc64d7..40ead17 100644 --- a/gpu/command_buffer/service/shared_image/d3d_image_backing.cc +++ b/gpu/command_buffer/service/shared_image/d3d_image_backing.cc
@@ -1405,10 +1405,14 @@ // D3D11 access is allowed without shared handle for single device scenarios. CHECK(dxgi_shared_handle_state_ || d3d11_device == texture_d3d11_device_); - if (dxgi_shared_handle_state_ && - !dxgi_shared_handle_state_->AcquireKeyedMutex(d3d11_device)) { - LOG(ERROR) << "Failed to synchronize using keyed mutex"; - return false; + if (dxgi_shared_handle_state_) { + // Trace event for backings with DXGI shared handles (e.g. camera capture + // textures). Used by the MediaFoundationD3D11VideoCapture trace test. + TRACE_EVENT0("gpu", "D3DImageBacking::BeginAccessD3D11::DXGISharedHandle"); + if (!dxgi_shared_handle_state_->AcquireKeyedMutex(d3d11_device)) { + LOG(ERROR) << "Failed to synchronize using keyed mutex"; + return false; + } } if (is_overlay_access && dcomp_texture_) {
diff --git a/gpu/config/gpu_driver_bug_list.json b/gpu/config/gpu_driver_bug_list.json index b5ffa6f..699e7e3 100644 --- a/gpu/config/gpu_driver_bug_list.json +++ b/gpu/config/gpu_driver_bug_list.json
@@ -3748,6 +3748,19 @@ "features": [ "validate_max_per_stage_uniform_blocks_at_compile_time" ] + }, + { + "id": 473, + "cr_bugs": [330694403], + "description": "The AMD Radeon 610M Integrated Graphics chip seems to reliably crash when attempting to initialize VAAPI", + "os": { + "type": "linux" + }, + "vendor_id": "0x1002", + "device_id": ["0x1506"], + "features": [ + "disable_vaapi" + ] } ] }
diff --git a/gpu/config/gpu_workaround_list.txt b/gpu/config/gpu_workaround_list.txt index 6d97bc70..8f60279f 100644 --- a/gpu/config/gpu_workaround_list.txt +++ b/gpu/config/gpu_workaround_list.txt
@@ -63,6 +63,7 @@ disable_svc_encoding disable_texture_storage disable_timestamp_queries +disable_vaapi disable_video_overlay_if_moving disable_vp9_hmft_temporal_encoding disable_vp_auto_hdr
diff --git a/gpu/ipc/common/dxgi_helpers.cc b/gpu/ipc/common/dxgi_helpers.cc index 0b6e0a5..8c1cea8 100644 --- a/gpu/ipc/common/dxgi_helpers.cc +++ b/gpu/ipc/common/dxgi_helpers.cc
@@ -10,6 +10,7 @@ #include "base/debug/dump_without_crashing.h" #include "base/logging.h" #include "base/metrics/histogram_functions.h" +#include "base/synchronization/waitable_event.h" #include "base/time/time.h" #include "third_party/libyuv/include/libyuv/planar_functions.h" @@ -138,6 +139,11 @@ d3d11_device->GetImmediateContext(&device_context); HRESULT hr = S_OK; + // Keyed mutex synchronization is still needed for non-camera textures (e.g. + // tab capture via WebContentsVideoCaptureDevice) which are created with + // D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX in D3DImageBackingFactory. + // Camera textures (created in GpuMemoryBufferTrackerWin) use + // D3D11_RESOURCE_MISC_SHARED without keyed mutex and take the else branch. if (texture_desc.MiscFlags & D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX) { Microsoft::WRL::ComPtr<IDXGIKeyedMutex> keyed_mutex; @@ -247,6 +253,12 @@ d3d11_device->GetImmediateContext(&device_context); HRESULT hr = S_OK; + // Keyed mutex synchronization is still needed for non-camera textures (e.g. + // tab capture via WebContentsVideoCaptureDevice) which are created with + // D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX in D3DImageBackingFactory. + // Camera textures (created in GpuMemoryBufferTrackerWin) use + // D3D11_RESOURCE_MISC_SHARED without keyed mutex and take the else branch, + // which uses EnqueueSetEvent for GPU synchronization instead. if (texture_desc.MiscFlags & D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX) { Microsoft::WRL::ComPtr<IDXGIKeyedMutex> keyed_mutex; @@ -275,6 +287,17 @@ } else { device_context->UpdateSubresource(output_texture, 0, nullptr, src_buffer, texture_desc.Width, copy_size); + + // Use EnqueueSetEvent to wait for the GPU to finish the copy. This + // replaces keyed mutex synchronization for camera capture textures. + Microsoft::WRL::ComPtr<IDXGIDevice2> dxgi_device2; + hr = d3d11_device->QueryInterface(IID_PPV_ARGS(&dxgi_device2)); + CHECK_EQ(hr, S_OK); + base::WaitableEvent event; + hr = dxgi_device2->EnqueueSetEvent(event.handle()); + if (SUCCEEDED(hr)) { + event.Wait(); + } } return true;
diff --git a/gpu/ipc/service/gpu_init.cc b/gpu/ipc/service/gpu_init.cc index 05c976f..a45a1c7 100644 --- a/gpu/ipc/service/gpu_init.cc +++ b/gpu/ipc/service/gpu_init.cc
@@ -406,6 +406,8 @@ #endif // IS_WIN || IS_MAC #endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CASTOS) + GpuDriverBugWorkarounds workarounds( + gpu_feature_info_.enabled_gpu_driver_bug_workarounds); gpu_info_.in_process_gpu = false; DCHECK_EQ(gl::GetGLImplementation(), gl::kGLImplementationNone); @@ -442,7 +444,7 @@ if (gpu_sandbox_start_early) { // The sandbox will be started earlier than usual (i.e. before GL) so // execute the pre-sandbox steps now. - sandbox_helper_->PreSandboxStartup(gpu_preferences); + sandbox_helper_->PreSandboxStartup(gpu_preferences, workarounds); } // watchdog_init will call watchdog OnInitComplete() at the end of this @@ -567,7 +569,7 @@ // restarting the GPU process will not help. if (!attempted_startsandbox) { // The sandbox is not started yet. - sandbox_helper_->PreSandboxStartup(gpu_preferences); + sandbox_helper_->PreSandboxStartup(gpu_preferences, workarounds); } #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
diff --git a/gpu/ipc/service/gpu_init.h b/gpu/ipc/service/gpu_init.h index 6973092..13231a42 100644 --- a/gpu/ipc/service/gpu_init.h +++ b/gpu/ipc/service/gpu_init.h
@@ -11,6 +11,7 @@ #include "base/memory/raw_ptr.h" #include "base/memory/scoped_refptr.h" #include "gpu/config/device_perf_info.h" +#include "gpu/config/gpu_driver_bug_workarounds.h" #include "gpu/config/gpu_feature_info.h" #include "gpu/config/gpu_info.h" #include "gpu/config/gpu_preferences.h" @@ -40,7 +41,9 @@ public: virtual ~GpuSandboxHelper() = default; - virtual void PreSandboxStartup(const GpuPreferences& gpu_prefs) = 0; + virtual void PreSandboxStartup( + const GpuPreferences& gpu_prefs, + const GpuDriverBugWorkarounds& workarounds) = 0; virtual bool EnsureSandboxInitialized(GpuWatchdogThread* watchdog_thread, const GPUInfo* gpu_info,
diff --git a/infra/config/generated/builders/ci/Dawn Linux x64 Builder/targets/chromium.dawn.json b/infra/config/generated/builders/ci/Dawn Linux x64 Builder/targets/chromium.dawn.json index 9736446e..d2bc362 100644 --- a/infra/config/generated/builders/ci/Dawn Linux x64 Builder/targets/chromium.dawn.json +++ b/infra/config/generated/builders/ci/Dawn Linux x64 Builder/targets/chromium.dawn.json
@@ -277,6 +277,46 @@ "--stable-jobs", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --enable-features=Vulkan", "--enforce-browser-version", + "--enable-default-webgpu-features", + "--jobs=4", + "--use-webgpu-power-preference=default-high-performance" + ], + "ci_only": true, + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "module_name": "//chrome/test:telemetry_gpu_integration_test", + "module_scheme": "webgpucts", + "name": "webgpu_cts_default_features_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "dimensions": { + "gpu": "8086:9bc5-23.2.1", + "os": "Ubuntu-22.04", + "pool": "chromium.tests.gpu" + }, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 14 + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "webgpu_cts", + "--show-stdout", + "--browser=release", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --enable-features=Vulkan", + "--enforce-browser-version", "--jobs=4", "--use-webgpu-power-preference=default-high-performance" ],
diff --git "a/infra/config/generated/builders/ci/Dawn Linux x64 Release \050Intel UHD 630\051/targets/chromium.dawn.json" "b/infra/config/generated/builders/ci/Dawn Linux x64 Release \050Intel UHD 630\051/targets/chromium.dawn.json" index 30aa918..e74114e 100644 --- "a/infra/config/generated/builders/ci/Dawn Linux x64 Release \050Intel UHD 630\051/targets/chromium.dawn.json" +++ "b/infra/config/generated/builders/ci/Dawn Linux x64 Release \050Intel UHD 630\051/targets/chromium.dawn.json"
@@ -201,6 +201,46 @@ "--stable-jobs", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --enable-features=Vulkan", "--enforce-browser-version", + "--enable-default-webgpu-features", + "--jobs=4", + "--use-webgpu-power-preference=default-high-performance" + ], + "ci_only": true, + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "module_name": "//chrome/test:telemetry_gpu_integration_test", + "module_scheme": "webgpucts", + "name": "webgpu_cts_default_features_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "dimensions": { + "gpu": "8086:9bc5-23.2.1", + "os": "Ubuntu-22.04", + "pool": "chromium.tests.gpu" + }, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 14 + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "webgpu_cts", + "--show-stdout", + "--browser=release", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --enable-features=Vulkan", + "--enforce-browser-version", "--jobs=4", "--use-webgpu-power-preference=default-high-performance" ],
diff --git a/infra/config/generated/builders/ci/Dawn Mac arm64 Builder/targets/chromium.dawn.json b/infra/config/generated/builders/ci/Dawn Mac arm64 Builder/targets/chromium.dawn.json index 6c50fbd1..38b56b2 100644 --- a/infra/config/generated/builders/ci/Dawn Mac arm64 Builder/targets/chromium.dawn.json +++ b/infra/config/generated/builders/ci/Dawn Mac arm64 Builder/targets/chromium.dawn.json
@@ -258,6 +258,50 @@ "--stable-jobs", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu", "--enforce-browser-version", + "--enable-default-webgpu-features", + "--jobs=4", + "--use-webgpu-power-preference=default-high-performance" + ], + "ci_only": true, + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "module_name": "//chrome/test:telemetry_gpu_integration_test", + "module_scheme": "webgpucts", + "name": "webgpu_cts_default_features_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "dimensions": { + "cpu": "arm64", + "display_attached": "1", + "gpu": "apple:m2", + "hidpi": "1", + "mac_model": "Mac14,7", + "os": "Mac-14.4.1", + "pool": "chromium.tests.gpu" + }, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 14 + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "webgpu_cts", + "--show-stdout", + "--browser=release", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu", + "--enforce-browser-version", "--use-worker=service", "--jobs=4", "--use-webgpu-power-preference=default-high-performance"
diff --git "a/infra/config/generated/builders/ci/Dawn Mac arm64 Release \050Apple M2\051/targets/chromium.dawn.json" "b/infra/config/generated/builders/ci/Dawn Mac arm64 Release \050Apple M2\051/targets/chromium.dawn.json" index 0e129b0..3fae8f290 100644 --- "a/infra/config/generated/builders/ci/Dawn Mac arm64 Release \050Apple M2\051/targets/chromium.dawn.json" +++ "b/infra/config/generated/builders/ci/Dawn Mac arm64 Release \050Apple M2\051/targets/chromium.dawn.json"
@@ -217,6 +217,50 @@ "--stable-jobs", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu", "--enforce-browser-version", + "--enable-default-webgpu-features", + "--jobs=4", + "--use-webgpu-power-preference=default-high-performance" + ], + "ci_only": true, + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "module_name": "//chrome/test:telemetry_gpu_integration_test", + "module_scheme": "webgpucts", + "name": "webgpu_cts_default_features_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "dimensions": { + "cpu": "arm64", + "display_attached": "1", + "gpu": "apple:m2", + "hidpi": "1", + "mac_model": "Mac14,7", + "os": "Mac-14.4.1", + "pool": "chromium.tests.gpu" + }, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 14 + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "webgpu_cts", + "--show-stdout", + "--browser=release", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu", + "--enforce-browser-version", "--use-worker=service", "--jobs=4", "--use-webgpu-power-preference=default-high-performance"
diff --git a/infra/config/generated/builders/ci/Dawn Win10 x64 Builder/targets/chromium.dawn.json b/infra/config/generated/builders/ci/Dawn Win10 x64 Builder/targets/chromium.dawn.json index 22f3f6a7..aab757a 100644 --- a/infra/config/generated/builders/ci/Dawn Win10 x64 Builder/targets/chromium.dawn.json +++ b/infra/config/generated/builders/ci/Dawn Win10 x64 Builder/targets/chromium.dawn.json
@@ -2021,6 +2021,47 @@ "--stable-jobs", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu", "--enforce-browser-version", + "--enable-default-webgpu-features", + "--jobs=4", + "--use-webgpu-power-preference=default-high-performance" + ], + "ci_only": true, + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "module_name": "//chrome/test:telemetry_gpu_integration_test", + "module_scheme": "webgpucts", + "name": "webgpu_cts_default_features_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-31.0.15.4601", + "os": "Windows-10-19045", + "pool": "chromium.tests.gpu" + }, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 14 + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "webgpu_cts", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu", + "--enforce-browser-version", "--use-fxc", "--jobs=4", "--use-webgpu-power-preference=default-high-performance"
diff --git "a/infra/config/generated/builders/ci/Dawn Win10 x64 Release \050NVIDIA\051/targets/chromium.dawn.json" "b/infra/config/generated/builders/ci/Dawn Win10 x64 Release \050NVIDIA\051/targets/chromium.dawn.json" index 3d67592..915d99e 100644 --- "a/infra/config/generated/builders/ci/Dawn Win10 x64 Release \050NVIDIA\051/targets/chromium.dawn.json" +++ "b/infra/config/generated/builders/ci/Dawn Win10 x64 Release \050NVIDIA\051/targets/chromium.dawn.json"
@@ -199,6 +199,47 @@ "--stable-jobs", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu", "--enforce-browser-version", + "--enable-default-webgpu-features", + "--jobs=4", + "--use-webgpu-power-preference=default-high-performance" + ], + "ci_only": true, + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "module_name": "//chrome/test:telemetry_gpu_integration_test", + "module_scheme": "webgpucts", + "name": "webgpu_cts_default_features_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-31.0.15.4601", + "os": "Windows-10-19045", + "pool": "chromium.tests.gpu" + }, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 14 + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "webgpu_cts", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu", + "--enforce-browser-version", "--use-fxc", "--jobs=4", "--use-webgpu-power-preference=default-high-performance"
diff --git a/infra/config/generated/builders/try/dawn-try-mac-arm64-rel/targets/chromium.dawn.json b/infra/config/generated/builders/try/dawn-try-mac-arm64-rel/targets/chromium.dawn.json index 0da72d51..089b8da 100644 --- a/infra/config/generated/builders/try/dawn-try-mac-arm64-rel/targets/chromium.dawn.json +++ b/infra/config/generated/builders/try/dawn-try-mac-arm64-rel/targets/chromium.dawn.json
@@ -218,6 +218,50 @@ "--stable-jobs", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu", "--enforce-browser-version", + "--enable-default-webgpu-features", + "--jobs=4", + "--use-webgpu-power-preference=default-high-performance" + ], + "ci_only": true, + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "module_name": "//chrome/test:telemetry_gpu_integration_test", + "module_scheme": "webgpucts", + "name": "webgpu_cts_default_features_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "dimensions": { + "cpu": "arm64", + "display_attached": "1", + "gpu": "apple:m2", + "hidpi": "1", + "mac_model": "Mac14,7", + "os": "Mac-14.4.1", + "pool": "chromium.tests.gpu" + }, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 14 + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "webgpu_cts", + "--show-stdout", + "--browser=release", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu", + "--enforce-browser-version", "--use-worker=service", "--jobs=4", "--use-webgpu-power-preference=default-high-performance"
diff --git a/infra/config/generated/builders/try/linux-dawn-rel/targets/chromium.dawn.json b/infra/config/generated/builders/try/linux-dawn-rel/targets/chromium.dawn.json index 5cefe570..c4b5ef65 100644 --- a/infra/config/generated/builders/try/linux-dawn-rel/targets/chromium.dawn.json +++ b/infra/config/generated/builders/try/linux-dawn-rel/targets/chromium.dawn.json
@@ -202,6 +202,46 @@ "--stable-jobs", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --enable-features=Vulkan", "--enforce-browser-version", + "--enable-default-webgpu-features", + "--jobs=4", + "--use-webgpu-power-preference=default-high-performance" + ], + "ci_only": true, + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "module_name": "//chrome/test:telemetry_gpu_integration_test", + "module_scheme": "webgpucts", + "name": "webgpu_cts_default_features_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "dimensions": { + "gpu": "8086:9bc5-23.2.1", + "os": "Ubuntu-22.04", + "pool": "chromium.tests.gpu" + }, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 14 + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "webgpu_cts", + "--show-stdout", + "--browser=release", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu --enable-features=Vulkan", + "--enforce-browser-version", "--jobs=4", "--use-webgpu-power-preference=default-high-performance" ],
diff --git a/infra/config/generated/builders/try/mac-arm64-dawn-rel/targets/chromium.dawn.json b/infra/config/generated/builders/try/mac-arm64-dawn-rel/targets/chromium.dawn.json index 0da72d51..089b8da 100644 --- a/infra/config/generated/builders/try/mac-arm64-dawn-rel/targets/chromium.dawn.json +++ b/infra/config/generated/builders/try/mac-arm64-dawn-rel/targets/chromium.dawn.json
@@ -218,6 +218,50 @@ "--stable-jobs", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu", "--enforce-browser-version", + "--enable-default-webgpu-features", + "--jobs=4", + "--use-webgpu-power-preference=default-high-performance" + ], + "ci_only": true, + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "module_name": "//chrome/test:telemetry_gpu_integration_test", + "module_scheme": "webgpucts", + "name": "webgpu_cts_default_features_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "dimensions": { + "cpu": "arm64", + "display_attached": "1", + "gpu": "apple:m2", + "hidpi": "1", + "mac_model": "Mac14,7", + "os": "Mac-14.4.1", + "pool": "chromium.tests.gpu" + }, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 14 + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "webgpu_cts", + "--show-stdout", + "--browser=release", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu", + "--enforce-browser-version", "--use-worker=service", "--jobs=4", "--use-webgpu-power-preference=default-high-performance"
diff --git a/infra/config/generated/builders/try/win-dawn-rel/targets/chromium.dawn.json b/infra/config/generated/builders/try/win-dawn-rel/targets/chromium.dawn.json index 82fc914..f3d3d13 100644 --- a/infra/config/generated/builders/try/win-dawn-rel/targets/chromium.dawn.json +++ b/infra/config/generated/builders/try/win-dawn-rel/targets/chromium.dawn.json
@@ -548,6 +548,47 @@ "--stable-jobs", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu", "--enforce-browser-version", + "--enable-default-webgpu-features", + "--jobs=4", + "--use-webgpu-power-preference=default-high-performance" + ], + "ci_only": true, + "merge": { + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "module_name": "//chrome/test:telemetry_gpu_integration_test", + "module_scheme": "webgpucts", + "name": "webgpu_cts_default_features_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "dimensions": { + "display_attached": "1", + "gpu": "10de:2184-31.0.15.4601", + "os": "Windows-10-19045", + "pool": "chromium.tests.gpu" + }, + "hard_timeout": 1800, + "idempotent": false, + "io_timeout": 1800, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 14 + }, + "test": "telemetry_gpu_integration_test", + "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" + }, + { + "args": [ + "webgpu_cts", + "--show-stdout", + "--browser=release_x64", + "--passthrough", + "-v", + "--stable-jobs", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu", + "--enforce-browser-version", "--use-fxc", "--jobs=4", "--use-webgpu-power-preference=default-high-performance"
diff --git a/infra/config/generated/cq-builders.md b/infra/config/generated/cq-builders.md index d49dda4..db57fb5c 100644 --- a/infra/config/generated/cq-builders.md +++ b/infra/config/generated/cq-builders.md
@@ -951,6 +951,9 @@ as required builders. ### chrome +* [android-internal-desktop-x64-rel](https://ci.chromium.org/p/chrome/builders/try/android-internal-desktop-x64-rel) ([definition](https://source.corp.google.com/search?q=+file:/try/.*\.star$+""android-internal-desktop-x64-rel"")) + * Experiment percentage: 5.0 + * [linux-perf-trigger](https://ci.chromium.org/p/chrome/builders/try/linux-perf-trigger) ([definition](https://source.corp.google.com/search?q=+file:/try/.*\.star$+""linux-perf-trigger"")) * Experiment percentage: 100.0
diff --git a/infra/config/generated/luci/commit-queue.cfg b/infra/config/generated/luci/commit-queue.cfg index 9f6bc29..2e05987 100644 --- a/infra/config/generated/luci/commit-queue.cfg +++ b/infra/config/generated/luci/commit-queue.cfg
@@ -80,6 +80,25 @@ owner_whitelist_group: "project-chromium-robot-committers" } builders { + name: "chrome/try/android-internal-desktop-x64-rel" + result_visibility: COMMENT_LEVEL_RESTRICTED + experiment_percentage: 5 + location_filters { + gerrit_host_regexp: ".*" + gerrit_project_regexp: ".*" + gerrit_ref_regexp: ".*" + path_regexp: "infra/config/.+" + exclude: true + } + location_filters { + gerrit_host_regexp: ".*" + gerrit_project_regexp: ".*" + gerrit_ref_regexp: ".*" + path_regexp: "docs/.+" + exclude: true + } + } + builders { name: "chrome/try/android-internal-rel" includable_only: true result_visibility: COMMENT_LEVEL_RESTRICTED
diff --git a/infra/config/generated/testing/mixins.pyl b/infra/config/generated/testing/mixins.pyl index ff284015..0469bd5 100644 --- a/infra/config/generated/testing/mixins.pyl +++ b/infra/config/generated/testing/mixins.pyl
@@ -155,6 +155,9 @@ }, }, }, + 'ci_only': { + 'ci_only': True, + }, 'crosier-no-arc': { 'args': [ '--test-launcher-filter-file=../../testing/buildbot/filters/chromeos.reven.chromeos_integration_tests.filter',
diff --git a/infra/config/generated/testing/test_suites.pyl b/infra/config/generated/testing/test_suites.pyl index 407d869..c8a32b4 100644 --- a/infra/config/generated/testing/test_suites.pyl +++ b/infra/config/generated/testing/test_suites.pyl
@@ -2799,6 +2799,7 @@ }, 'chromeos_system_friendly_gtests_fails_vmlab': { 'mixins': [ + 'ci_only', 'experiments', 'skylab-rdb-gtest', ], @@ -2816,6 +2817,7 @@ }, 'chromeos_vaapi_gtests': { 'mixins': [ + 'ci_only', 'experiments', 'skylab-rdb-gtest', ], @@ -2893,6 +2895,7 @@ }, 'chromeos_system_friendly_gtests_fails_vmlab': { 'mixins': [ + 'ci_only', 'experiments', 'skylab-rdb-gtest', ], @@ -2910,6 +2913,7 @@ }, 'chromeos_vaapi_gtests': { 'mixins': [ + 'ci_only', 'experiments', 'skylab-rdb-gtest', ],
diff --git a/infra/config/main.star b/infra/config/main.star index 26bf320..66e7a95 100755 --- a/infra/config/main.star +++ b/infra/config/main.star
@@ -235,6 +235,7 @@ "chrome-swarming-pool": True, "chrome-tester-service-account": True, "chromeos-betty-finch": True, + "ci_only": True, "crosier-no-arc": True, "experiments": True, "gce": True,
diff --git a/infra/config/subprojects/chrome/try.star b/infra/config/subprojects/chrome/try.star index 41c30777..2187ef6 100644 --- a/infra/config/subprojects/chrome/try.star +++ b/infra/config/subprojects/chrome/try.star
@@ -60,6 +60,13 @@ ) chrome_internal_verifier( + builder = "android-internal-desktop-x64-rel", + tryjob = try_.job( + experiment_percentage = 5, + ), +) + +chrome_internal_verifier( builder = "linux-chromeos-compile-chrome", tryjob = try_.job(), )
diff --git a/infra/config/subprojects/chromium/ci/chromium.dawn.star b/infra/config/subprojects/chromium/ci/chromium.dawn.star index 044a95f..e87d2d9 100644 --- a/infra/config/subprojects/chromium/ci/chromium.dawn.star +++ b/infra/config/subprojects/chromium/ci/chromium.dawn.star
@@ -1198,6 +1198,7 @@ "dawn_chromium_isolated_scripts", "gpu_common_gtests_passthrough", "gpu_dawn_compat_telemetry_tests", + "gpu_dawn_webgpu_cts_default_features", ], mixins = [ "linux_intel_uhd_630_stable", @@ -1212,6 +1213,9 @@ "webgpu_cts_compat_min_es31_tests": targets.remove( reason = "Limited capacity, and already many suppressions in default compat, so remove.", ), + "webgpu_cts_default_features_tests": targets.mixin( + ci_only = True, + ), "webgpu_cts_dedicated_worker_tests": targets.remove( reason = "We only need coverage on one GPU per OS, so remove from lower capacity configs.", ), @@ -1530,10 +1534,16 @@ "dawn_chromium_isolated_scripts", "gpu_common_gtests_passthrough", "gpu_dawn_telemetry_tests", + "gpu_dawn_webgpu_cts_default_features", ], mixins = [ "mac_arm64_apple_m2_retina_gpu_stable", ], + per_test_modifications = { + "webgpu_cts_default_features_tests": targets.mixin( + ci_only = True, + ), + }, ), targets_settings = targets.settings( browser_config = targets.browser_config.RELEASE, @@ -2857,10 +2867,16 @@ "dawn_chromium_isolated_scripts", "gpu_common_gtests_passthrough", "gpu_dawn_telemetry_win_x64_tests", + "gpu_dawn_webgpu_cts_default_features", ], mixins = [ "win10_nvidia_gtx_1660_stable", ], + per_test_modifications = { + "webgpu_cts_default_features_tests": targets.mixin( + ci_only = True, + ), + }, ), targets_settings = targets.settings( browser_config = targets.browser_config.RELEASE_X64,
diff --git a/infra/config/targets/bundles.star b/infra/config/targets/bundles.star index b8e1c7c..291b4e5 100644 --- a/infra/config/targets/bundles.star +++ b/infra/config/targets/bundles.star
@@ -4195,6 +4195,25 @@ ) targets.bundle( + name = "gpu_dawn_webgpu_cts_default_features", + targets = [ + "webgpu_cts_default_features_tests", + ], + per_test_modifications = { + "webgpu_cts_default_features_tests": [ + targets.mixin( + swarming = targets.swarming( + shards = 14, + ), + ), + "gpu_integration_test_common_args", + "webgpu_telemetry_cts", + "linux_vulkan", + ], + }, +) + +targets.bundle( name = "gpu_dawn_webgpu_cts_fxc", # We intentionally do not have fxc + worker tests since dxc + worker # should provide sufficient coverage.
diff --git a/infra/config/targets/matrix_compound_suites.star b/infra/config/targets/matrix_compound_suites.star index cf7b2d0..eea8caf 100644 --- a/infra/config/targets/matrix_compound_suites.star +++ b/infra/config/targets/matrix_compound_suites.star
@@ -69,6 +69,7 @@ "chromeos_system_friendly_gtests_fails_vmlab": targets.legacy_matrix_config( # TODO: remove experimentals after stablization. mixins = [ + "ci_only", "experiments", "skylab-rdb-gtest", ], @@ -79,6 +80,7 @@ "chromeos_vaapi_gtests": targets.legacy_matrix_config( # TODO: remove experimentals after stablization. mixins = [ + "ci_only", "experiments", "skylab-rdb-gtest", ], @@ -202,6 +204,7 @@ "chromeos_system_friendly_gtests_fails_vmlab": targets.legacy_matrix_config( # TODO: remove experimentals after stablization. mixins = [ + "ci_only", "experiments", "skylab-rdb-gtest", ], @@ -212,6 +215,7 @@ "chromeos_vaapi_gtests": targets.legacy_matrix_config( # TODO: remove experimentals after stablization. mixins = [ + "ci_only", "experiments", "skylab-rdb-gtest", ],
diff --git a/infra/config/targets/tests.star b/infra/config/targets/tests.star index 63cd5f995..5069fb8 100644 --- a/infra/config/targets/tests.star +++ b/infra/config/targets/tests.star
@@ -3317,6 +3317,18 @@ ) targets.tests.gpu_telemetry_test( + name = "webgpu_cts_default_features_tests", + telemetry_test_name = "webgpu_cts", + mixins = [ + "has_native_resultdb_integration", + ], + args = [ + "--enable-default-webgpu-features", + ], + module_scheme = "webgpucts", +) + +targets.tests.gpu_telemetry_test( name = "webgpu_cts_fxc_tests", telemetry_test_name = "webgpu_cts", mixins = [
diff --git a/internal b/internal index 102d89f..4bac053 160000 --- a/internal +++ b/internal
@@ -1 +1 @@ -Subproject commit 102d89f4b1f0fab6a3b07a16e128345053b6db9d +Subproject commit 4bac053d081d6987ceef3dd358e4c5ac84caab58
diff --git a/ios/chrome/app/resources/BUILD.gn b/ios/chrome/app/resources/BUILD.gn index ba0e7ec..6cfe3f9 100644 --- a/ios/chrome/app/resources/BUILD.gn +++ b/ios/chrome/app/resources/BUILD.gn
@@ -77,6 +77,7 @@ "$root_gen_dir/components/optimization_guide_internals_resources.pak", "$root_gen_dir/components/policy_resources.pak", "$root_gen_dir/components/regional_capabilities_internals_resources.pak", + "$root_gen_dir/components/safe_browsing_resources.pak", "$root_gen_dir/components/signin_internals_resources.pak", "$root_gen_dir/components/sync_service_sync_internals_resources.pak", "$root_gen_dir/components/translate_internals_resources.pak",
diff --git a/ios/chrome/browser/first_run/interactive_lens/ui/BUILD.gn b/ios/chrome/browser/first_run/interactive_lens/ui/BUILD.gn index 597dfb1..2328cd8 100644 --- a/ios/chrome/browser/first_run/interactive_lens/ui/BUILD.gn +++ b/ios/chrome/browser/first_run/interactive_lens/ui/BUILD.gn
@@ -17,6 +17,7 @@ "//ios/chrome/browser/bubble/ui_bundled:bubble_view", "//ios/chrome/browser/bubble/ui_bundled:constants", "//ios/chrome/browser/first_run/interactive_lens/ui/resources", + "//ios/chrome/browser/first_run/interactive_lens/ui/resources:animation_files", "//ios/chrome/browser/lens_overlay/ui:protocols", "//ios/chrome/browser/lens_overlay/ui:results_page_presenter", "//ios/chrome/browser/lens_overlay/ui:view_controller", @@ -27,6 +28,7 @@ "//ios/chrome/common/ui/promo_style", "//ios/chrome/common/ui/promo_style:utils", "//ios/chrome/common/ui/util", + "//ios/public/provider/chrome/browser/lottie:lottie_animation_api", "//ui/base", ] frameworks = [ "UIKit.framework" ]
diff --git a/ios/chrome/browser/first_run/interactive_lens/ui/interactive_lens_overlay_promo_view_controller.mm b/ios/chrome/browser/first_run/interactive_lens/ui/interactive_lens_overlay_promo_view_controller.mm index 05410e01..e27e33664 100644 --- a/ios/chrome/browser/first_run/interactive_lens/ui/interactive_lens_overlay_promo_view_controller.mm +++ b/ios/chrome/browser/first_run/interactive_lens/ui/interactive_lens_overlay_promo_view_controller.mm
@@ -16,12 +16,15 @@ #import "ios/chrome/common/ui/util/constraints_ui_util.h" #import "ios/chrome/common/ui/util/pointer_interaction_util.h" #import "ios/chrome/grit/ios_strings.h" +#import "ios/public/provider/chrome/browser/lottie/lottie_animation_api.h" +#import "ios/public/provider/chrome/browser/lottie/lottie_animation_configuration.h" #import "ui/base/l10n/l10n_util.h" namespace { // Static image assets. NSString* const kLensImageName = @"mountain_webpage"; NSString* const kHUDImageName = @"lens_overlay_hud"; +NSString* const kCirclingHandAnimationName = @"cursor+line"; // Corner radius for the top two corners of the Lens view. const CGFloat kLensViewCornerRadius = 45.0; // Multiplier for the top padding for the Lens image. @@ -57,18 +60,27 @@ UIImageView* _backgroundImageView; // The heads-up display view that sits on top of the Lens view. UIImageView* _hudView; + // Layout guide to handle the static positioning for the bubble view. The + // bubble view has an animation, and that animation uses constraints between + // the bubble view and this layout guide. + UIView* _bubbleContainerView; // View for the tip bubble. BubbleView* _bubbleView; + // Bottom anchor constraint for the tip bubble's positioning container view. + // The bubble should be constrained to the lens view, but kept within the top + // padding area of the Lens image. + NSLayoutConstraint* _bubbleContainerViewBottomConstraint; + // Bottom anchor constraint for the bubble itself, that can be animated to + // move the bubble inside its container. + NSLayoutConstraint* _bubbleViewBottomInnerAnimationConstraint; // View controller for the interactive Lens instance. LensOverlayPromoContainerViewController* _lensViewController; // Scroll view containing the screen's title and subtitle. UIScrollView* _textScrollView; - // Bottom anchor constraint for the tip bubble. The bubble should be - // constrained to the lens view, but kept within the top padding area of the - // Lens image. - NSLayoutConstraint* _bubbleViewBottomConstraint; // Whether the bubble is currently being hidden. BOOL _isBubbleHiding; + // Lottie object for the circling hand animation. + id<LottieAnimation> _circlingHandAnimation; // The primary action button. ChromeButton* _actionButton; // The footer view containing the action button. @@ -79,6 +91,8 @@ NSMutableArray<UIGestureRecognizer*>* _disabledGestures; // Whether the user has interacted with the Lens view. BOOL _interaction; + // The remaining number of times the bubble animation should run. + int _bubbleAnimationCyclesRemaining; } @synthesize lensContainerViewController = _lensViewController; @@ -103,8 +117,6 @@ [self setUpViews]; [self setUpConstraints]; - - [self startBubbleAnimation]; } - (void)viewWillDisappear:(BOOL)animated { @@ -121,7 +133,8 @@ // Anchor the bubble to the top of the Lens image container. The 0.7 // multiplier ensures the bubble appears within the top padded area of the // image (slightly below the middle of the padded area). - _bubbleViewBottomConstraint.constant = [self lensImageTopPadding] * 0.7; + _bubbleContainerViewBottomConstraint.constant = + [self lensImageTopPadding] * 0.7; if (!_lensSearchImage) { _lensSearchImage = [self createLensSearchImage]; _backgroundImageView.image = _lensSearchImage; @@ -144,6 +157,9 @@ gesture.enabled = NO; } } + + [self startBubbleAnimation]; + [_circlingHandAnimation play]; } #pragma mark - LensInteractivePromoResultsPagePresenterDelegate @@ -163,6 +179,7 @@ - (void)lensOverlayPromoContainerViewControllerDidBeginInteraction: (LensOverlayPromoContainerViewController*)viewController { [self handleHideBubbleAnimation]; + [self hideCirclingHandAnimation]; _interaction = YES; } @@ -215,8 +232,15 @@ [self.view addSubview:lensView]; [_lensViewController didMoveToParentViewController:self]; + _bubbleContainerView = [[UIView alloc] init]; + _bubbleContainerView.translatesAutoresizingMaskIntoConstraints = NO; + [self.view addSubview:_bubbleContainerView]; + _bubbleView = [self bubbleView]; - [self.view addSubview:_bubbleView]; + [_bubbleContainerView addSubview:_bubbleView]; + + _circlingHandAnimation = [self createCirclingHandAnimation]; + [self.view addSubview:_circlingHandAnimation.animationView]; } // Sets up the layout constraints for the view hierarchy. @@ -304,21 +328,36 @@ CGSize bubbleViewPreferredHeight = [_bubbleView sizeThatFits:CGSizeMake(view.bounds.size.width, CGFLOAT_MAX)]; - _bubbleViewBottomConstraint = - [_bubbleView.bottomAnchor constraintEqualToAnchor:lensView.topAnchor]; + _bubbleContainerViewBottomConstraint = [_bubbleContainerView.bottomAnchor + constraintEqualToAnchor:lensView.topAnchor]; [NSLayoutConstraint activateConstraints:@[ - [_bubbleView.centerXAnchor constraintEqualToAnchor:view.centerXAnchor], - [_bubbleView.leadingAnchor + [_bubbleContainerView.centerXAnchor + constraintEqualToAnchor:view.centerXAnchor], + [_bubbleContainerView.leadingAnchor constraintEqualToAnchor:view.safeAreaLayoutGuide.leadingAnchor], - [_bubbleView.trailingAnchor + [_bubbleContainerView.trailingAnchor constraintEqualToAnchor:view.safeAreaLayoutGuide.trailingAnchor], - [_bubbleView.topAnchor + [_bubbleContainerView.topAnchor constraintGreaterThanOrEqualToAnchor:_textScrollView.bottomAnchor constant:kBubbleViewTopMargin], + [_bubbleContainerView.heightAnchor + constraintEqualToAnchor:_bubbleView.heightAnchor], + _bubbleContainerViewBottomConstraint, + ]]; + + _bubbleViewBottomInnerAnimationConstraint = [_bubbleContainerView.bottomAnchor + constraintEqualToAnchor:_bubbleView.bottomAnchor]; + [NSLayoutConstraint activateConstraints:@[ + [_bubbleView.leadingAnchor + constraintEqualToAnchor:_bubbleContainerView.leadingAnchor], + [_bubbleView.trailingAnchor + constraintEqualToAnchor:_bubbleContainerView.trailingAnchor], + _bubbleViewBottomInnerAnimationConstraint, [_bubbleView.heightAnchor constraintEqualToConstant:bubbleViewPreferredHeight.height], - _bubbleViewBottomConstraint, ]]; + + AddSameConstraints(lensView, _circlingHandAnimation.animationView); } // Returns a new image with the Lens search image padded at the top with white @@ -346,6 +385,24 @@ return newImage; } +// Creates and returns the LottieAnimation view for the circling hand animation. +- (id<LottieAnimation>)createCirclingHandAnimation { + LottieAnimationConfiguration* config = + [[LottieAnimationConfiguration alloc] init]; + config.animationName = kCirclingHandAnimationName; + // The hand should circle maximum 3 times, which is built into the animation + // already. + config.shouldLoop = NO; + id<LottieAnimation> animation = + ios::provider::GenerateLottieAnimation(config); + + animation.animationView.translatesAutoresizingMaskIntoConstraints = NO; + animation.animationView.contentMode = UIViewContentModeScaleAspectFit; + animation.animationView.userInteractionEnabled = NO; + + return animation; +} + // The height of the white space above the Lens search image, relative to screen // size. - (CGFloat)lensImageTopPadding { @@ -417,21 +474,60 @@ // Starts the animation for the tip bubble view. - (void)startBubbleAnimation { - CGFloat originalY = _bubbleView.frame.origin.y; - CGFloat floatHeight = 18.0; + _bubbleAnimationCyclesRemaining = 3; + [self runBubbleUpAnimation]; +} - __weak __typeof(_bubbleView) weakBubbleView = _bubbleView; +// Run the portion of the animation to move the bubble up. +- (void)runBubbleUpAnimation { + _bubbleViewBottomInnerAnimationConstraint.constant = 18; + + __weak __typeof(self) weakSelf = self; + __weak __typeof(_bubbleContainerView) weakContainerView = + _bubbleContainerView; [UIView animateWithDuration:1.5 - delay:0.0 - options:UIViewAnimationOptionAutoreverse | - UIViewAnimationOptionRepeat | - UIViewAnimationOptionCurveEaseInOut - animations:^{ - CGRect frame = weakBubbleView.frame; - frame.origin.y = originalY - floatHeight; - weakBubbleView.frame = frame; - } - completion:nil]; + delay:0.0 + options:UIViewAnimationOptionCurveEaseInOut + animations:^{ + [weakContainerView layoutIfNeeded]; + } + completion:^(BOOL success) { + if (!success) { + return; + } + [weakSelf runBubbleDownAnimation]; + }]; +} + +// Run the portion of the animation to move the bubble down. And if the +// animation has now shown enough times, stop. +- (void)runBubbleDownAnimation { + _bubbleViewBottomInnerAnimationConstraint.constant = 0; + + __weak __typeof(self) weakSelf = self; + __weak __typeof(_bubbleContainerView) weakContainerView = + _bubbleContainerView; + [UIView animateWithDuration:1.5 + delay:0.0 + options:UIViewAnimationOptionCurveEaseInOut + animations:^{ + [weakContainerView layoutIfNeeded]; + } + completion:^(BOOL success) { + [weakSelf completeBubbleDownAnimation:success]; + }]; +} + +// Completion block for the bubble down animation. +- (void)completeBubbleDownAnimation:(BOOL)success { + if (!success) { + return; + } + _bubbleAnimationCyclesRemaining -= 1; + if (_bubbleAnimationCyclesRemaining <= 0) { + return; + } + [self runBubbleUpAnimation]; } // Creates and returns the footer container view, which holds the action button @@ -546,4 +642,9 @@ _isBubbleHiding = NO; } +// Hides the circling hand animation. +- (void)hideCirclingHandAnimation { + _circlingHandAnimation.animationView.hidden = YES; +} + @end
diff --git a/ios/chrome/browser/first_run/interactive_lens/ui/resources/BUILD.gn b/ios/chrome/browser/first_run/interactive_lens/ui/resources/BUILD.gn index 3564a82fd..b6e26f1 100644 --- a/ios/chrome/browser/first_run/interactive_lens/ui/resources/BUILD.gn +++ b/ios/chrome/browser/first_run/interactive_lens/ui/resources/BUILD.gn
@@ -14,3 +14,8 @@ "Assets.xcassets/mountain_webpage.imageset/mountain_webpage@3x.png", ] } + +bundle_data("animation_files") { + sources = [ "cursor+line.json" ] + outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ] +}
diff --git a/ios/chrome/browser/first_run/interactive_lens/ui/resources/cursor+line.json b/ios/chrome/browser/first_run/interactive_lens/ui/resources/cursor+line.json new file mode 100644 index 0000000..0e5f2b8 --- /dev/null +++ b/ios/chrome/browser/first_run/interactive_lens/ui/resources/cursor+line.json
@@ -0,0 +1 @@ +{"v":"5.9.0","fr":30,"ip":0,"op":256,"w":1125,"h":2434,"nm":"Cursor + line","ddd":0,"assets":[{"id":"image_0","w":250,"h":271,"u":"","p":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAPoAAAEPCAYAAABrxNkjAAAACXBIWXMAAAABAAAAAQBPJcTWAAAAJHpUWHRDcmVhdG9yAAAImXNMyU9KVXBMK0ktUnBNS0tNLikGAEF6Bs5qehXFAAAgAElEQVR4nOy9a5RjV3Uu+q2tqi5VqfS01HKXq6sFVtwQ2W2IwCE2OAXh5BJCPHIvtzoQDOZeEl6BMXgFTMhJq2EkhGMgJxm2CQlkxIEbwEpOYg7hBJvBKfzCrwo2bmG3Xd2ubqurWy21HqVSSaou7XV/aM2luVep2rva7mrH1hxDQ/ulvdfe2nPN1zfnBAY0oAENaEADGtCABjSgAQ1oQAMa0IAGNKABDWhAAxrQgAY0oAENaEADGtCABjSgAQ1oQAN6IZE43wPYCpJSOu5TCCH5tn7r/He03zzubM5HywMa0FbSC5rRz8R8fJsQQh3eXZZSgr7ZsY51fg5+PToXW+973efmDgc0IHdkne8BPBsiBuonZYkU4wF9JrVMJmOp3+v9xOSZTEbs379fCCE0k/P1/fv30/mElFKwsYDW1TF8snGM+5nua0ADGpAixmSaqfgEIKUUmUzGymQyFi1DMSdt4+u0DMbA/KOOsdj1ODML/ns6H98G54TTd7zn8HENaEDPf+rHCP2Y0WRizsCc4Z6JuQFYxNh8woAxURi/2XASMa8BNlHwfXiBm1QDGtCZyGQG9GM2MObpJ8WxnsnXMTp6ElszOjvWMhmen5Of12Tefsxu3oM5FuPeBjSgs6L/TC+P2MAZpp1kpiON2dHYt2+f3L9/v8hkMqAPAMc3LZu/yeVyIpvNSn68Sf3OJ6WUe/futQAglUpJNgZJ4wTgGD9fZ/c4cN4N6FnRfwpnnJJomhGYg02vK+82lJt73TmI4TKZDHK5nMhkMpiZmREAkMvlBC0To+ZyOSGEsDKZjGM7rRPlcjm93zxm//79IpvNylQqJWld3Y9j2bwf476A9er+gAa0KRo63wNwQ/1CW+QZVzExgDEAMVE/KQ10pStjUJHJZEhai5mZGeRyOWSzWQDAzMwMLQtap+OI6Fyc1MQh0VXZJW1LpVJy7969ViqV4hOT5NKcaSKyz6Q1kO4D2jQ976VDnxi0Y5UzCbpMBaDLfNlsVhJzEdMTU2azWUxPTwsAiMViMpvNYmZmBsViUdD69PS0iMViko4HoLdls1li5HXH8XWgO7HQmMx1ZRJIpjk4mHuDSW7A7APaFD0vGZ2AJmx5HYhl//79Yt++fZIke7/zMKaWpJoDQLFYFLOzs5ientbHmutAdwIoFotio/20nWiD/ZopSQvIZrNgWsQ6+x5MavP7zWQyNpivYsDwA3JLzysbnaS3YmiRyWQsjjRT+/QyAVK4pAZANrhe50xOkjmdTovZ2VkBAPV63TFRzM7OYnZ2Vk8IJtXrdb19enp63YRB55udncXMzIz+cDJtf1qemZkRCnTDQTp60stkMkK4BN4MaEBEzytGN+Gi+/btIzXWgToj7znQZWKDWbQtXSwWRbFYFNlsFvRN6vrc3JwEIIkpp6eniYFFOp0W6XRa1Ot1kU6nNRimWCxa9XpdzM3NIZ1O63X6Pf3W7/fL2dlZOkZks1lBY6GxgU1enOlTqZQUQhCqDvv27dN2vhBCmqo9nqda2YCeX/R8e0kEV9G5Pc7WHXa4sr8dzjGys2n98OHDlt/vl0BXyqbTaTE3N6evCUCm02nHQFqtFtcQkEql4PV65dzcHFKp1Lrn5vV6JQCoSQAAQNcEulqAmlwwMzMjgZ5TkMZLvgR1v5LMEz3QPqYL2zdQ4we0IT1fJDqFj3SYDNASvHuAYYsbsW3HS052MZeis7OzDgmdTqeRTqeRSqWQSqVEq9USrVZLzM3Nibm5OQEA7XZbtNttkUwmRbvdFor5LdpOH6A7MczNzYl0Oq0nCZL2XOozDUHfz+zsrCSmJzNj7969FjG9UMTvnzM5f4Zn+wcM6IVNz4vwGldFmZ2u1XjT3lbhLwlAzM7Oai85mIZSLBYBdJlMMZ4kaculNRExLAAkk0nkcjnH/mQyqY9ZW1sTCwsLku3T3vRWqyXUb/X50uk0SXoxNzcn/X4/qfAym82KmZkZh2SfmZkRt956q63sc5HJZDR4Z6PsOgA8+jCgATnovL4ZfUJnMpPJWBxBRvv6AFfWxa+5hxyAVtFTqZTwer2SM3i73Rbz8/NafU4kEmJhYQHJZFJfc35+XiQSCSwsLCCRSDjGvrCwACg7W/1WJpNJ+p1MJpNiZGREAuvVer/fr30DpN5zU0NNWhLKrODXJabvh6ojjWjjJz6gFyudd0Y3w2hsn1bXCU7KgDD6QHKu9Qt/zc7OilQqJbiN3Wq1BDE5AJFMJuXa2tqGz4H2DQ0NSWJ4/k2/p21DQ0PrGG1+fl4CQDqdlq1WSxDjA9BM/9KXvtSmbRQZUPeqMQBAX5VdkwEHHjD8gDSdVxudwzvpJeXqaCaTEQRX5bh1CldxYIoR4hIkMXO5HJLJpMjlcqjVapapBczPzwugK6GVlNbMvbCwIPL5vN42OTkp1tbWRCKR0OutVsviEwWdz7zVZDIpiMlJs5ibm9P2O0UG1H2vk+I8srB//36dK8+f5ZngtAN6cdN5fysMQIxEz/MuuBTnHnagJ8mBrh2uQlpienpaMrvcYXuTKk60trYm8vm8BCAmJycBALZti8XFRWmsY2JiAouLi5icnNRMaNu2AADLsvS2fD6PRCKxTpqSpJ+fn5epVArqngDl8VdRAKnCdNJA22nAD3nmCRHIJ0Zm7gyk+YAcdF6ccaZtzl5W8ixLkuLE4ORsY9hzTaT+ptNp7nxzEEliUrFJCk9OTgoAyOfzYmJiAgAQj8etfD4vaR2AWFxclACEbXc17MXFRX56/dvJyUmHKcAYHMlkkhx3WpWn41RITu8zEHWChd5EJpOhCXA9EF7hDnidO/OYAb346Lyp7kIISS8hob8ymYwjNrxv3z6d+WUiy4i4mg50w1zkMVe2uFhbWxPKjhaTk5OCVHLbtoVt24IzOVE8HheLi4ui0+mIeDwOACIej6PT6YhOpyPA8t7j8bgAusxP5+PnUpML+QXQaDQsGuvc3JyemGjCMtF02WzW4Xjct28fSXXHmAlU4+oPGNCLirZcojOnG8E5JVRhRigJtXfvXovCZ/0yw0htJwafm5sTqVRKh8TUskgmk9pbns/nMTExIdS3lsiLi4siHo9jcXER8XgchUKBvgUAFAoFxGIxAABJc8uyZCwWE8ViUU5MTEhifjUR8OthYWEBygyQxOyJRAKNRsNinnptt7daLXH48GFrbm5OzszMyOnpaUHSnST7/v37xczMjKMQJWlCYObYwF4fENGWvwlcbSevuhkuEkKImZkZAsRoCOrMzIwsFouCYKgA1sXFaWJIJpMgSQ707OnFxUXNELFYTFiWJWkfjY9HAkqlEqLRqI7rl0olSYxP6/F4XHY6Hcvj8WjPOQB4PB4tXS3Lkvl8npge+Xxe8lAeAIyMjEiv1ysJQjs9Pe0IuxGRlgP0ClzwJB+jkMVAwg/o/Njohodd7t+/Xzve9u/fDyjmnp6etkzHFJEJWSVKJpOYn59f53hTEluQtFbfMhqNWsTY5PX+27/929Bb3/rW3xwZGbncsqyAx+PZxW3e06dPP9poNB599NFH73rDG95wtNPpCCGEJC0AgNYCDNL3kEgktIc+lUrZHGFH90d4AJrgCBikQDbIZrMyk8k4ctqZZB944Qd0XknbtkY9NIFeIUcLgCeTyVgzMzMeAJ7p6ekhdCemoXQ6Pcw/qVRqWzKZHEmlUtsAjADwJhIJL4DRiYmJMQBj6tsXi8XGzQ8A/0033bSzWq1+anV19S65Cep0OkeKxeL7f/CDH1wKwB+Lxcaj0ahfnXc8FouNx+NxHxvD2OTk5CiAUQBe9dFjZ/cxDGCY7pt/z8zMeOgDwJqZmfFk+tTHM57vgF7EdF5eAP7i9csrp3RNXgzCRLupkBSp6fp8pK4bqjri8bhW3+n6pVIJN910U+i66677wNjY2AeFEMFnc1+NRuPz99xzzz++4x3vOAL0QCs8/Gaq80BXjedgG4bYo2MdyTD0XIh4PTralslkbOYPGajvL3LaMkYntde00QGsY3DAmdlFx6s0UACguLPgjjdS18kuP336tKWcaUJh3wUARKNR2LYtDh8+/IFAIPDpZ8vgnGzbPnrixInrL7roon+LxWLEbGQaYGJiwqa4PNBldmJwDqMdGRmRuVwO6XRazs3NYXp6WmffEcPTc6JlCkUC6xF0A2/8i5u2lNGB9ZVaibg0AtYBZMhu1dh1QrwBXQmYSCQ0mm1iYkIor7oAgFgsJqSUwrZtUS6X8aUvfSn44Q9/+B+Hh4dfe67ut16v/3kikfi8ZVmyVCrpxwAA8XhcAkChUJAEwOFSncJwAKSayAj9p510s7OzkqQ6MTdPcQUGzD2gHm1ZHN3wqjuKIHImz+VygiQ5edAJ3mrmghNDEJMrSU6quo5/cy3ijjvu2PWRj3zk7nPJ5ADg9/uvP3z48KeVuSAikYiIxWKIxWLgTrt8Pi8Umg5ra2uCHHQMXKPvmdJsFbNr6KxZhINhYwd2+oC2nshZRM43aXRDUR9yMg0xB9wwgOF0Oj0MQDutksnkSCKR8CYSCe/k5OToxMSEdrqBOd4ikUgAQODf/u3fLut0Okc242x7tlQul68Ph8PBcDgcBBCActgBGI/H4z7uoJucnByl+wHgTSaTI+p+6TM8PT2tnwt3ymX6NI0wnvOA2V/EtJXIOJ2wQQKHgB90AF9W6ikv1EAFIRzYdVomTDo535Rdzm188aY3vel7lmVNnasb7EfhcPjzd9xxx2U0hmg0CjU+GrMjzs8z4YAu+IeIQm6kvnP/BSX/KEeII6zGzaQBs784aSv/dGJ0nmdOnVOESscU/FgiYnZidALDAF2bnH5DUFTbtrX0ouWjR49+fnx8/APn9hb7k23bRz0ez+UAEIlE7HK5DACSgDiEsAM0hl5OTk7C6/XaGyXB9Mtj5445HslgiS46xj6gFxdtGWBG9hxvct++fQAABY6BapqgGZYKNRJCDOgCSchmJSanb+V8c0hGzuzf/OY3p84XkwOAZVlT1Wr1+lAo9OdSShGJRCQAUSqVyDnHD5cKqkseeEHOOJVTTxEHLdVNMFEulxP79++nDDfJcvoBlfBy7u96QM8n2vKkFjOPmiqfmsdR2il52nO5HObn5x2ZYSpXfJ1WQiptpVIBALzpTW/63tmOt91uLywvL99Xq9VmW63W47ZtV8/mPIFA4P2f//znQ1JKUS6XBQBEIhERjUaFbdvi9OnT1uLiopiYmBCWZcmJiQmC7wqOE2DQ33X3Tfn72WwWLK4uWTXdgSf+RUpbaq/JPlVkuMd9dnZWTzyUbkrVWKgyjFq28vm8nJyc1MAYlVGGTqdjlUolRCIRIaUU99577+te9rKX/c/NjNO27Va9Xr+vWCze12q1WnSNoaEhads2duzY8YpQKDTt8XhCmzlvrVb7QigU+vNQKATLsuxyuYxoNCoJP8+BNYVCwZ6cnNSYeDPkRs+Faz0UdkMPAivNcOaA0V+ctGUSnZhcOiu7arudZ6mZaadzc3NCSXTMz8+LjZi8UCjQNq22JxKJt29mnO12e+HJJ5/8yyNHjvx4ZWWlbdu2sKzuYyLE3bFjxx554oknvtpoNB7ezLl9Pt+bg8GgqFar2hNeKpVENBoVxWJRp80WCgU5MTFB48fa2pogIA3Z6+q56HPPzMxIiq3zajTMCce3DRxyLzLayji65N5g/uIR8IM8yn6/X87NzclcLiep3DIAK5FIUKKKyOfzjuIPxOCWZclIJAIppahUKsLr9f6u2zGura2dOHjw4C3tdrtlbNcpqvTdbrdbhw4duq3dbi+4Pf/Q0NBl99xzz2vV/VN8HebkFI/HRafTEbZt6+y7+fl5oarTCgAaRKOq6pC5QvvEzMyMoJJTwPqU1QGzv7hoyyU6J6qFRjY6b2+UTqdFKpUS8/PzcmRkRKd0Mi87uJcd6EJbS6WSkFKKarUqDxw48Dq34+t0OtUjR458R50Ptm3rIhMUk6Zl+gaAfD5/m23brTOfvUdTU1O/GQgERLVaFaFQCOVy2SKbndTqQqEgCoWC/g1n9kQiQcUuBdWmJ+rX+w1wApL6/Q8DeuHTljrjSIpzSUNqJnmPlVQnyUSFHalCDABgcnISExMTolAooNPpiGKxiGKxKEqlkohEIgCAUCgkLrzwwkvdjq3dbi8sLS3VOGM/0286nY5YWlqqLS0t3e/2OuPj42/7wz/8wyAAVKtdv144HEYkEtEx/2g0KmKxmGMSA6BLYXHnXKvV6tsfDujl5hPuXQgBw0cy4PgXCW0pBJZsdG5DUkNE6lzKY+apVErXWgOgQSS2bfMSTwC60pyoUqkIABgbG7sMLun48eMPkC2+WXr66addM7oQInjNNddcFggERDAYFKFQz58XjUZ1MQvLsiSFDPP5vJicnNTazNramvZpeL1e2c8Dz8E0gMYvCPX8BTOhHNK+35D77es3GQ4mjucvbaVEl+RlN8sXT09PO7LUqFUSAM3kqq66rtZK6Z62besQFdRLGQqFUK1WxWZQcEtLSyfM+Dydn6PWzP0AsLq62tqMrb579+5PLi0tAXAyjIoYCHSLUAp0i1LqcQDQteOTySRqtZpFTrl6vS7q9brIZrMim82K2dlZSS2rzD5t6roANGqOl9zWz5Exrhl7N+1++v3Ao/88pfMCgVXfOj2VAz64JxnoJa7Mz88LFW7C4uIiOp2OtmMpOywcDjt+y8NVbsi2bQcTKy+7dsDRNhVm00UnLcvC8ePH73R7nZGRkas+97nPBbkELJfLVqVSQSQS0Wp8LBaj5BwdW6cxqAQYtNttkUqlxNzcnE7dVb4OAVVzT0lwoYA0ukklt93NbEKTaDKQvR55fLtjwnD7HAa0dXQ+4ugO2zyTyQheo53sczY2wbPTjIIS2qblRSWUM040m81ver3eN7sZ29zc3GdZnXZeCFIfwxnepJGREe+ll176YcuyvG6uVywWP7N9+/avApDBYFDWajUZDod5gQpbwWMRj8dloVCQQLectKpFD4qvkzOTp7MCvQmUcvuBXrsnQtDwgh/Axp1gzFp0/SYF4xhJTG/G8M3JwKxTYJ5voCk8e9pyZBxX2fkLBvTi58qjLFOplE5BBQAjpEbaAIQQkktv5eQSnU5nye24xsfHQ1QAgjM0SfQzMTnQDbctLy8/4vZ6gUDgzX6/H36/X9RqNREMBgWFBIUQ0rZtUSwWRTQa1SE3NR5Btegp5Eak0ll1+WtK6qHOs1SZZmZmRuzdu9dS0l1PvISPF0KsSyE2GZtrA7z5IxGZAsSk3CzgIT+qCMzPudE1B3T2tOXhNVLdlYSRPIYOdKVRLpeTCiQjFhYWKKNLTE5OYnJyUqoSzbqgo+wVlRCVSkUEg0ERCASwurp61O34otHo7n492AymF/2Wicrl8kG31xsZGbnqu9/97mXElKSFhEIhrZVEIhFRKpVEp9OxgF58XTnndIuoXC63rtUUBx1ls1kxPT1tsXWwltMOhqVtzMTS3Ma99tREQteqYtKen4dUe9rHnbEmmIe0Cbqm6QOg59RneWAuPANtuUSnPzWVSuk2Q6rSK+8yKnh6Jqmq5Bgjb3ssFtPedpURBgCo1WpYWlpCu912zeg+n+9lfJ0AK5Zl8WVJKDwaD//NqVOnjmwmpr5nz543+/1+ABBLS0tQ8XVUKhVRqVTWqbOFQgHKL0GNJ6huvEgkErqXO1WSnZ2dtXhPeACiWCxSgwiRyWQEJRRR0QpifKUya/ueltEtu21xaUvpsaQhmPXraDv39lOIlU8CNEmYabacuG+AHSO5D8Ht838x0Zbb6LyXWp/ijw77PJlMaocX0A0zAT01ttPpWIwBLSUVQWrwV7/61V1ve9vb/sPt+H72s5/dQKg4VcKZxq2P6fcCqtrwsCwLyWTy6nA4/Ksun0ctGAwmobDpQnWvIXudbFePx2ObeHgFk+UFJpFQPd8WFhakssvBcfFEL33pS21ePpqIUoXNwpO0jZesYpETSjF2mGV0HH3zenaclLkguM+AMbqAitaYPgLSOvg2eo4DWk9byeimiqdVLpPZqXQStVQivDfFzz0ej1RedwuATmAx1bqlpSWxtrb2U4/Hs9PNAMvl8p1PPvnknc9kG9JLR+MAeuE+n88X+sVf/MUPu30oDz/88G9fffXV9wCQ9XpdBgIBELObyS/KOUeYAzkxMSGp0CSvKAv0HHVAl1l5EgzgbDNttpxmnWHof5EzRkssmqRVKSvHZEBFPskJSMcAPRAPVa7lNjq6PffO+E6qdFuz8CVflYBu1ClZ2E/QPrwIJ4QtY3QWpyWVUEt1wNlmSfVPo7ixIPU0n88jHo9bQE9tLhaLVjgcJgeWZTL8wsLCpyKRyB+6GWOr1Try8MMPfwNwvjwbMb4pZYguv/zyd3q93l1urlmv178aCAT+K7ovnwQgA4EAAMCyLJukPB1vWZYk52OhUAAxu/LGC3aedV55AFq6U8lsYnzV/UZDkdn4BB0D9Hwp9GhogZieMbtDM1BNJ2SfCcIh8fkkQb/lkwPgjAyYWpfpFOT7TVWfTwQcB/BCxARsueoOaJtNl45SziJ62ahmO/kPRCKRwOrqqgX0MtUAQEl0QUksJpMvLS2Jhx566HXpdPpf3I7x0KFD3ygWi0eA7mSy2Vg8ALzkJS+5Ih6P/7qbY6WUtU996lPpv/7rv67V63WSuqjX63YwGIQQQlarVUQiERvo+iJUaiugmJp6xlGVGl5CGuh1dKUS0oCzkysnYnZAV96FGpOk0l6c8Tci1vIZQE876Ndiio7LZDKSm3Rn2K/P0cdcWKfqq/fN5vY7Y+51E/kL0QzYcmecsq/0rJ3NZnV9uLm5OUkvlqqC2huoYjhSkQuFgojFYjIajTrsWwBYWlrC0tKSACBe//rX391qte51O75wOLwL2JjJ+3nbSVKQQ+nYsWM/28TzCH7oQx96s5Kcwu/3QwghA4GANkG4J94Yg4hGoxZ3UJJXfnV11TKjCI1Gw0omkyKVSjk6ubJvpNNpoT7gNfSLxaJFRUAIhcc72TL8A4Du5J3NZpFOpy0oJyBtLxaL4vDhw5YJ01X7N+ycy6U+0GNykvjkM+BeOrWdN7Pgob6+JLup1C8op96WI+Og6sRls1kN4qBZnquMKvcc3D4nRJz6jePkxAi1Wg1AVyr6/X5IKcXKyso9bgcZCoWuAJyoOvL2E/ObDjkpJZWuAtCFxLZarSNur7l9+/a3Abpyq7W0tOTQTqrVqn7xwuGwDilRxKFYLIpCoUDtnLWzUo3FarVa1vz8vLWwsCDW1tZEu93WHnqWBqwbVpof8pnQMm/1DPSYfHZ21ioWi9rTT+YYTeT1el2w0t2yXq9rhp+ZmaHCI6JYLIpsNksTA11GZLNZzM7OWhQl4M+QTACKHhhSWmMGuLOPe/0B54St/tcXDLOfl/7oZJvx2Vu9DMLv90tVHw7JZBJDQ0NyaGhILi4uysnJSclbGlH8HOileAaDvaYr9Xody8vL8oYbbvgbt2OzLMsbi8Uc9rXH45GWZckzqfHmvs1AYr1e75XXX399AGoy9Pv9ol6vO04PdJN1FKgG6AKCCBsPqJCbKlyhJTv1bAcz06h+/NramhgZGdHjrtVqFlXx4T3m2+229pnQfrom+6bfSZogyN8yOztrUYiPNAEAjsIZhw8fXhcKVMyumZ6abRLzE7yXjqflXC6nQ4I8t0LZ9uvi/vSdyWQEnxDUcS8IZt9yG50eKNALsake4LoTC1Qcvd1u6/RUqiijvO0iFotpRi+Xy1rSKakuAoGARmJJKUWxWPxXr9d7pZtx1uv1n+Vyue9y9X2jZVqnZY/HI6WUGB4eHn3lK1/5B24hsaVS6YuxWOyG8fFxCQDLy8vkmJNLS0sIBoPaRAG66L9wOCwVPl5SRxizsqyqQ7fOOw/0bHfVHYZCmno/zxwkjD/35FMaMesVp5F6ZvVaWjZDfcrxKqH+c6/XK01HIftfHAVDiXhPOk48r8L4Jqcb1DPta6ez/dpbb9r5+E9CW4qM4+ukviuVDQSYocNJoiwsLEjyuANd0Eg8HpfFYhGlUgl9oK9gTK6pUqn8L7dj9fl8l2zbts0LdP9wnr1GiS60zvDxEugBbdrtdmtpacm1rT4+Pn6lz+cTy8vLYnl5GePj48Lv9wsppf4GANu2rWq1qiGzoVBIlMtlYds2Ien0BHf69GkL3Qw4LXEJi6DANmJtbU20Wi2LkHbz8/P6A4CSZ/T9A6BKNxadUxXDsBKJhKCJgOoIKA2AtAK0Wi1BWXeKyQEmcFR6MmkCgvwB5KglQBUVKVGefKEcumJ6elp7+6nrD6n5VPteXc8EAmG/UY2HS3VC+XHm/s8k7be0lBRfVw9f23CAbjmEVColSFIAoBpxAHpdUTkqDuhWfOW53XQ9chb9xV/8xXds23aFfbcsyzs5ObmHkHB8MrEsC5ZlgbLWGBaeGFGf59SpU64hsV6v98of/ehHV6KnBjvaSZPdrqQ7arUaqtWqftF4ZVlKdS0Wi1AZcIjH4yCpTqr8xMSE4NoIw9GLRCIBVehCQ215pRt1nHb4Ua2ARCLBjyUcBGkLotFoWEDPJEgmk4IchJxogiAnIfcJpFIpzfzZbNYCuu+QMgsoiqOPV5KeQnaa8WdmZvSyEEKn8iqYrgOhx7QDayPU3vOZttRGJwCUGRIBnPFZr9dL5aOQTCYlvURAFxFGjCeEkFRVhlJUzQmFtISvfOUrtWaz+X23Yw0EArtNDztnbGB9Nhuh44iKxeKmILG7d+9+k8/nAwyTStnrgiIJyjQRwWCQvPIiFAppqR8Oh8lZp/MA1ORoLS4uWsppJzqdjlhcXBSnT5+2yCyie15YWBC8bBdpAgAs0rCoGAYxNuUk0LKC5gLoTg78OMDpKyA/gNIELEBrBUilUoLScTnD89LXptffUO/1PorzU1vubDarvfi88qRJ4mIAACAASURBVBGtc0gw0EMPAj2V/j+DZN/KAXJcs55RGdJLj6VYLFoAoNRBrK2tiXw+j4mJCWHG0akFcrlc1i97rVYTAIRyamlnzdzc3FW/9Eu/9D/cDvg//uM/vri6utpSjOJg4mci27YxNDQkL7nkkqsjkcjVLn+zFAgEdjcaDQCQPp8PQgi5vLwsVR6Aw25VcXdJDkiKuXPbnY5lXV0lRSxUK2l9TDwe12g/ckCakx3tA+AozkmAHeoOS0QTApletExwXSLehmpoaEiqSUOqdtjg30AXEwB07f90Oi2ZrU8kTbSf8gVp1B/gjM/3a0HNcfu0zKG3RM93e33LGN1ExtGMSg+cQ2ApzENqHnfGAc4a7kDPGcZDUsTsAMT4+LiQUlqNRgOdTucJy7ICbsZcKpXufOKJJ+5S1wDQy0/fKG3VzGX3+XzByy+//ENun9N999331je+8Y33NhoN7a8YHx8n5xwl/oCWGXZAEsCGzlWtVvU5qJZeuVwG9W1X96gZnzP2RhEGhsYTqr+ddvrRtQA4+r+fPn3a4hMHtZ1SxzmuxycEVVUIAMiM0M5CYnoCAVF7aQoFcgQgtZs2nXYmszP7XXKtsx8IxyQDZvu8oy1ndKg4Os2Y3PNODhc2Lt1njTu+qLpMNBoltJzFr0NQWDpPvV7XzL6wsPDxaDT6CTdjJkgst7+JkTlDA+gr7em4V77yldeOjo66gsS2Wq17R0dH/2+fz6ehrEqqA4rpAaxjfIWmoxCjrNVqEoAIh8N2pVJBOBxGpVLRDA/0UHaArtIjAYh4PG6r8Ws7v1gsSgBCLQPoYhnMSARV/eH1/Pg20gZMbcGyLIdGQJoALQOQxOz0rbZpyU9Mn06n5dzcnCD0X6vVErFYzDYx/Rylx1V4VqRDe+15gc0+iTQaW//M//D5oS0tDqkekMxkMpIjnMjzboZTODJOFZ1wqJlA9wWtVCqS2i+pa5Gkk2DM0Wg05OHDh12j5Lxe765oNJrg2WncPifH3JlUetu2Ua1Wn3B7zW3btl36gQ98gDQO0Wg0IKUU6h40Y4yPj4vx8XFuosDv92vNBuq/tW3bAqBj71L2WkKFw2Fh27Z23kUiESsSiYhOp2N1Oh1CrgkppYhGoxaFNIFuVR8pJQF1LGanilgspuP5DLWn4/udTociAlo7Uz4Akc/nLTLTVCquUFV/LbL76RmQk4++FYOKubk5K5VKYW5uzqrVapbX65UM1AP65uG46elpi7z0gMbV81Ca1kh5YYxMt121PowjGJ9PtNUDorxkaarwQK+5ItBrwUSed/qD6YVQ+G5dgaVUKlmhUMiR3AJ0X/p6vW4ppqAqq//DbUy9Wq0+8Pjjj98O9IpC9is1dSYbfmRkxJtOpz/u9iHl8/l9O3fu/Fsl1QFAp6wyqeGYFJeXl2mi1FoAFaAMBoNaxafzsFLT+jx0DOX2K0y9MLUAg6Q6FhTHL5VKWlqqKjn6/FxDoJLW6jhJk7fH45GLi4sa4cdBUgD6YgG4ik/xfpLyQA8ApKS9Y+xAr50VV+dV8s06yC19cykP9BJnno/SfcvruvOGfxnVvGFmZkaHRwgZl8vlQJ537nUn249CbLQMxgyAxrvrS9NCo9HA8vKya6keCAT2MPirQ3XnXnjTdufe+Waz2Wo2m0fcXjMajf4f6nnpxB7yMQBdpobyPywvL2tm4eaK+q0GDtGnUqlYhJ/nGHr62LZtKa89SqWSBUCUy2WtCSimF+FwWITDYRGJREQkEnFU4Y1Go1AagcVDoFQaS0opOJPTumpcITqdjojFYhY1sqC+92bRD8ICUAiQ9lHcH3Ag+bQAQVeo6DLZBNHl1Ygpww5wJs5IKSXrRU/7hcHkbv/qLaMta5sM5Wxns52QUsq9e/daQM9eUiqWTKVSIpfLabWMSM30ACBt2xZCCKmQcXrSqtVqCAaDktRWtVlKKS2fz4c/+ZM/+drNN9/syk63LMsbj8enVKhMS3RgvYOOL5uS/tixY3clk0lXdrrX673yxhtvnPrkJz/5dKPRsMbGxuTKygrQZWwJQCpQjVQgGyhEnVmdxYHlBjSYiPL1Te1ABINBAXQbYPC0TTBbVEU3tHZQqVREOByW4XAYSgOQABCJRGiy0OFP27ZNrYHse60N2LYNJvkFYSds29YVdiYmJqRql42JiQmQur+2tkZajeC5Eui+UwC6/esULFdyLRKGlqQgtwB6cfS9e/daqVSKzkXPSEL5ngCdLv+8SnXd8rruPHNo//79umhhNptFLBaTVMEU6P4hCwsLWi0DuhKdtyuSqraaEMJhpwM6/kyQUm27/8M//EN1Mxlt27dvv/xM+/sVkDTj7ZVKpbCZmPpb3/rWvSsrKxgdHRUAxNjYmBgbGwMA+Hw+sp2tRqOB8fFxSCmtG2+8ceeDDz745gMHDrz9wIEDbz948OCb77777qs+/vGPB6WUlmJusbS0ZEkpRSAQECpLTgQCASsQCFhAL3phmkChUIiQeQB62HvarxpniHK5bNFvw+GwZvJwOOwA9jBwj04coiYWYIAhcgoqEgr8Y3U6HTExMaGBQIB24jkkPND19zCkHqDei9nZWdFqtUQ6ndbJOYStn52dlWaGHa+oC/Sk+b59+2SmV0fPMdm6/c/PJZ03CKwhaaRSlQTQzaJimGgbAE9uAQDJmZ1sNnqhQqGQBIBAICCN5BAsLy+LRqOBxcXFW92OnUNi+TX7SXJTlafvzUJit2/f/nujo6OCmyMrKyuaAcbGxsQPf/jDK4vF4ieKxeK/LC0tPXHdddc99LKXvezvp6am/mpqauqvLrnkklv27Nlz2759+w6dOnXqfx87duxPv/GNb2itghgfgKNgBy/gQZ1fWdhSl+oKBoPCtm0rk8mEbrnllqnbbrttCsqkoIw7fs5KpWIpyK5l27ZVLpeFcgjqCYUcgeFw2CJYr4qqOBpdxGIxkHMPPZgv0HXoCUL5KdVed6Rl7acFwW2BLvQ2nU5r6a66BlmM2XVdPZPZeVosN03Bokfn20F3XiCwxowHFlOXKi9dQx4VRFIC2hkmJyYmuNedgCAAerFjVSBSApB+v1+So2p8fNwGgC9/+cv/62wgsfQxQkPrvPAkzbldWSqVXHvfLcsK/PCHP/yVlZUVq9lsSgAYGxvD2NiYuOOOO648derUP73mNa/552g0+gmv13vlM2EDhoeHL/X7/e+79tpr51qt1r/efPPNu8iOV6E5Ua/XsbS0JOr1un4x/X6/VavVNMN+7nOfC915552vy+fzf1YsFu+sVquH9+3b99Q111zzyDXXXPOIlLJ8+vTpH7darW8+9thjv3vLLbdM0bmCwSAIpw90zQNqn6V8ABbTDBw5+FCSndfwB2CpBCcBhfRTDjxH1p5ieLLdCZ9BKDzysjuQdkC3tp7Kp9cVkICeb4mvE2ae2+38+Z9vNX7Lve6G00Jfn5idx9Op0gyPpQ8NDcnV1VWLATaALtwTpVLJUvFierF4tRlrfHxcJ4xIKcXi4uJfBQKBvW4GzstMmWgxon5xdtNWf81rXvNxtxlt5XL5a5OTk/uh1Mwf/OAHv/KqV73qY6Ojo7/i5vfPRMvLy9/+7Gc/+8c33HDDEoUgWY6A49h/+qd/2vnGN77xfYFA4G1CiOD6s21MjUbjW9///vf/2969e48GAgHtJKX6eEB3YgagcfyklQHdyZu0NY7447X0VAxfAL1aBWqb5OAdhtQz/RNSgW7O6JlX56fimxpNR7XsOKObsffzCarZ0sITxOQ021GhAJZkAACOeHoqldKpkfl8Xq6trQlyyFmWJePxuDTLE1HIqFar6RdJlVWGQpkBAB5//PFvux281+vd5fV6vYBW2zfMUTe7uxiJLg+6vWYoFNp77bXXBt/1rncF8/l85nWve132uWJyoNvZ9fOf//z//vu///spku5MigoA4tvf/vZUq9X617e+9a3/EQwG37dZJgcAn8/39pmZmZ/W6/WbPvaxj4VUJR2H1CZ/Abf5+ViUpEc4HNZmIPWWJ3WfQq1EStpbPFZPSDx1f0gkEiKRSOjiG0RUYUcV0NDbCUIL9EA29FF2FiiETJqr6RA9H7RlEl3K9fW5eOlnoFc7DugViaT9iT5tmYBeWmixWBSRSKTfSwITDgsAy8vLBNjYFCR2fn7+TiEEjFAPgP7eeMKG0za/378pSOzx48f/IhaLzQwNDU26/c1mqdPpPH3LLbf8X+95z3uOAhA+nw8f/vCH/ddff/0fBoPB9z6X17Jt++itt9762+9973ufJkQfjOqsDNar8/BrtZoklZ8BogAAlUpFhsNhKosNoCt1yYFHzT6UX0cS+o7H4KmQphF716XNgF7dPBqnWeRSSimpoaXZ2LJPfvuW0pYyOoC+3kg1IwoqIEgOkbm5OZ25xIEzJuadClFwhFalUhGqq6pFyLHx8XGLVHeg65grFouf2CwkFuhBPk01vl/ITdWI16GqV73qVe9wC4ndKmLMnr///vt/JZ1O/6XbMtlnc6277rrrXa9//etz4+Pj/V58+clPfjKQSqUCF1988S4OmFlZWandfvvtR774xS/WgJ5az+G9ZhEO/j8NDw9r9YqKaBKslhfUHBkZkaoIhiBVXpmS+hjCzpv2ugmZNUBi50W8b7knkEt21rqHj0cj5FqtlqCHDYZ7V+mTYmJiQkt0QPcEF0qlswCgWq1ayi7U6qLCvkNKaf3oRz+68oorrnCd0UZVYk1G74d/N++blpPJ5Kt37NjxXzb35M49nT59+sDy8vJPwuHw75/ra3U6nae/+c1v/p/vfve7nx4fH5ezs7NXTU5OpoLB4JXDw8OXPdMkI6Wsra6u3l2pVL7/wAMP3H3dddcd5ei/crmMSCRCTC8BULNKXS0XgIZVUxKNWUUH6En2ubk5SYUupqenHVh5s7lFv2aVZtGKrWT68+LyJ2aHAhmw9D9tq5NkJ/WdpLpKYhCTk5PaKXb69GmrWCyCwWEFlZZSxRkEMTuU+r68vCx8Pp9oNBqi2Wz+s1tIbK1We+Cxxx67natiGyW90DYppVbfpZTC6/WOvPrVr3YNiX2hkppY7g0Gg29zaz6d4Vx3VyqVf9y9e/e3TIYnhx0xF+tQq5l+cXFRUupsPwgt0M2I61fqmpW21nBZrr5zNZ4SYbaa0c9H7zXubOfdOgAVT2cpq/B6vZLDYQHorCagqxarzCodaotEIjo3OxgMajuPKsMuLy9LUhl9Pp/cDCTW7/fvUfeht5FTjlQ/Do2lP7TT6Qhi+Far1d4MJPaFSsPDw5eGw+H3PlsmV+d67fbt228+derUI48//vjvVioVUS6XLYXO040qSbOisNzi4qJQDTB0LoMivZzL5XRLaqpiYxJpk0BXqlNRSiG6lWsMx5wDH7EVdD4kOjldOFxTPyDyxBOzU0yTklyAXikjVvWE1zW3KBGjj1POMtR3IaUU7373u4M33nij67JPvMmDSVRiCnDmrDMfhZRSih07dkwlk8lr3V5zQJsj27aP3n777b/1G7/xG0eALphKSXgJOJx1OhEI6PWfN232+fl5SWmvKvTmKGzBqtM6ctmJTFV+q51z5w2tw2GwtI2jjVjxfwC6WqgOidDsSyWQAJjZbAKApRxyQFd9FyqMpIsMAl1I6WYy2hqNxsEDBw5kuVTnTrl+dro5e4+MjHhf9apXfdBtTP2ZqNlsHq1WqwdbrVat0+m0PB6PNxKJXOLz+aaGhoZCz3yGFybVarU/TyQSXwC6DKVg0jYl23g8HltFbSRvbwWACl844u3kmJuenpbUxoqccrxxpVmBFtD6ukOSkyp/bp/CebbR2YyGmZkZ60wVZ+bm5hwFI9H1wPdldKW+6/JSdE2gG2rz+/2kxlnLy8vw+XziwIEDv5NIJP7Szfht2249/PDDN7ZarfZGZZ85KYfhujTWVCr1XyKRyKtdP7g+4zh16tSDTz311IPtdrulPMwOvwAAXHzxxVfEYrHXPVeTCr9+s9k80ul0qp1OpzU0NBQeGxub8ng8z6uJZW1t7dHvf//711533XVHq9WqJMANrz04PDxs8xJaANCvrdX8/LxmfKNdFTc7Je8+269oBacXqkQnNd3hqFCGu8MZB8CRn051xAklRygnYnbufSekXCgU0q2UFfpKx9RVJxdLSine9773BW+44YYH3dqLJ0+evP3w4cMPAM5Qm1l1hiahfowej8enLrnkkrNS36vV6gNPPPHE3dTmmZ/fyDoD0I3fX3rppe94LqR7q9U6cuzYsTuLxeIRnosNdHPHo9FoYnJy8teHh4fjZzrPVpJt20e/973v/RYxO1flSY2PxWIYHh62WdNKJBIJaZSw0pKdokLkoOP95liaq85uA0vsMuiFx+g8nm6E2OhhAN0EAkdMHYCj5C+vK86LRtrd1kiOZeV9J2ZfVzQSXZCIOHbs2GfdAkR4TJ2uZR5DTN/P6UKMedVVV31sM5LWtu3Wk08++c8nTpw4wj38BA82JxSuKvr9/uCePXvec7aSvdVqHXnqqafuqFQqOqPIUi2quHZGy8lk8upoNOqqMOZWEGd2oNutFgCI2YFuwcyJiQm70+kIirmz2nUykUgIn89n86YUsVjMJjWeClgAGlCjNYANpPmWFKo4H00WHWihTCYjSbXhpaUA6PJSDCGHXC6HdrtNZYR1vfdCoeDIaOOJLgB0zXdqSUyQWEUSAA4ePPjvbu/D6/Xu4hltrHYa+Hc/OKzaR74E15DYtbW12sMPP/x3J06cOGIbPgG6vukI5Ai+er1eO3HixN1ur8fO3zp+/PgdDz300Dc5k6t9wmRyGtv8/PydpVLJdWuqc02WZU295S1v+Z+33HLLVLVaBWXQRSIRUSwWqSAGKBOOUmcBQJWudkzYuVwOXq9XktDgBSzoGIJ3q4QXEzQGtX7OJfp56b3GkvUdNotCD0maBenBsTY9MpVKYX5+HkNDQzKRSOiqoUQcFWVZlqxUKo4ySktLSxBCyHq9Lv1+P8bHxzE+Pi4ajYb85V/+5XvdZrQBwNTU1BXmtn5xdL6PvqkO3eLiouvUVcuyRmq1Wo1MBXV+Xbed10w3iSaYQ4cOPbC2tlZ1e81Op1N99NFHv37o0CEyU9ZV0SFYcj/n5BNPPHHXZhpOnmsiZr/tttumKK9e5cgLJhxEoVDA6dOnrcXFRSwsLFA1GwC95hIAdCNKALyAhYN4CSpq7KjCbZwPzql2fd687kAPHSSldBTOB7oeeHLIcaQc7W80GhaVgQbO7H0Ph8OCILE895lCbFSayefziYWFBdeQ2NXV1RM//elPv9YPOAM4a8udSX1Pp9PXjo2NTbm55sGDB/+/xcXFo0Cv/jn5B8xvU5WnsfzCL/zCFRMTE290c71arfazn/3sZ98DQHBSBz7APJ5NZho1GI/Hpy6++OJ3urkeUafTqS4vLz/Rbrertm23Wq1WdXR0NDg6OnrhyMhIfGRkJLGZ85l0+vTpA1/60pd+69Of/nQVgLbZaQJVaDrZB0VH1Wg1rkPZ7RIq5EZxdoWio59L0t1ZFhuncyrVz3t4jROz13X/LECDETA7Oys49r1fogtPX6XcZVXgYF19NADaVieGv//++6/aLCS2UCgc5c64fsUjZbf4wrrf27aNZDJ5xUUXXeSK8crl8oOPPPLID2mdmJmr8jQBqOvrF4jGNTo66jq0Z9t266GHHrp5dXW1aWIBOAb9TKm5tm0jnU67LnldKpXump+f/7EQQms+dE51v2J8fDy4Y8eOXx4fH7/8bH0Oy8vLX5mcnPwMJclUKhVEo1GbNEIWerN5qisASnOVAKi5hFShN0d8Heg56VTlY2maOnz5XKnx50V1B9bb6gCoHI+OQRaLRcFRclRHbn5+XvJS0JwIOEMSvVwuU9IDgF7eM3U54ZDG8fFxvOENb/jJZspMXXDBBbu5JDUrywDdF57u10xbtSwLTz/9tGv1PRQKXTY6OjoyNDREyRoOJuehITYuh9nQbDZb7Xa7sMElHGRZlvfCCy+8hDM5nYtKN5uTm3mPAHDs2LG73N7j+Pi41m5o/KZPYmVlpXrw4MHbn3zyyb9ZXl5+xO25jet84NChQ+/n21S6q05/Bbrly1iq6zpzcWRkRNejI4lO7yzHw1M5aq698qjFubTVzxujA72b5NU4CB3Ha24TOs7r9cpUKoVUKoWRkRGp6skJ6p9OxxeLRVkqlaQQQkYiEVGpVPS+UCikbXaqKaeKLkigWyX21KlTrp1ygUBgD90HD6/xl19K6ahgaobZms2ma0isZVneHTt27CYGN89FtjrbLznj0fajR4+6dsrFYrHLAKcHn54hl+q8wg4bDwBsqmYeOTplt4ilw+HHgVIAsLS0VHvssce+WywWb3d7P5wikcin/u7v/m4X1bujc5Ovp1gs6hr0qjadAHrtpZPJpK40Sz3hp1WnV06pVIqANCZKjurMnVNI7HlldHJKGHh3vXt6etoGNCCBurjoGt0AZDKZtIEe/p0871RB1LIsnb5YrVZRrVZRq9W0971er4vl5WXdCcXn88kvf/nL33F7D5ZleaPR6C4DOOOQoB6PR7IOJeDHkcd8M4y3ffv2S/k5TGAH73vOJwMal2VZUnnuXTHe6OjorpGRES/H7dM+jhPgUpy/tJZlodVqtavV6qNu73FqauoKM2TZrwYA3efRo0fvO3To0N+4vSciIUTwLW95y43BYFCEQiFHwUvzXqjOvKo26/DCs6KToHbP/ByqfTMArGsAoRj/nDL7VpZ7XkfcRlFML5QBQ+E0Qc3xFDpO99cyce9ArxQ0MTvBHFU5aHUZKUhSAN0wGz1cqpH+5S9/ufanf/qn97qFxF544YVXkJ0OYF36qrrwuj+SMz1JPDf2JjFes9lsUwzdPIbZy30dZna3Mu2jF1xwgStk3s6dOy+bn59/kDvheEENnshjWZaW/jziUSqVDrpFAo6Pj++yLOtOAA47ljd5NMwFsbS0dOKpp576h5e85CXv2ozdPjw8/NrHH3/87Tt27PgWlbCyu/Xp6H+UgO47B8uyJOEW6Ht+fh6pVIqwHjoBRkFi6f+x1bLDGcfsc47teE7V+PMu0UltUeuS56hTcweKp1N5H7O5w9DQkCS7SdUII88pAOhsNvP6VN2E7/P5fPD5fJuqEjs6OrrL6/WOMOeR4AwA9GxbcvyY42m3261KpeJa4u3cuXOP4WiT9AJyp2A/nwGtb6Z/eygUuoSPmzsXN3LCEUPS+smTJ4+4De15vd5dsVhsl92t3e8QCqpnfd+cAmJ2t/dFFI/H/+yP//iPQ9VqVZBUp1LU6h6ozLRuM80rzCYSCS18SCj5/X5ZLBa1Kq/KpunYOqBrzUE903NWeuq8MjqgY+fC7E1NsUdVMBIANHiGHB+clOouAWjAAzUEKJfLolwuC7PuuyKS5pJXOzmbKrFG6ioAp4pJqar0MZ1ym6kSGw6HLyGtgTM8OeFMxuZE1y0UCkfdOuVGR0d3hcPhuOl550zOJxc+CfB91WrVteORHJ1cAyMzqI8TUv9uaWnpxKlTp37g9jrqfoKf+MQn3hcMBqFUeOozrxGWVHySA7OoQcTCwoKkPu9mnfhYLCZZdpsmcj6r6wNYVwb9OaPzwuj97BDytBNRppqS6HJ2dhb1el3kcjlJOerz8/Ng2UVghf8AQPcCA7ppilRJlIAz5HmniqfUoRQAbrrppqVarebaVg8EArv7bedS1ZTkpr2+Gbt5bGxsKhaLbedq+5mYm1/HYArXk0s8Hr+EO9/oXvppDcayjr8/9dRTrpGAgUBgz0b7yNcA6PCqY//Ro0fvX1paut/ttdT13v/Rj340CPQ61fB3NRqN6tLSqr+AIDAN2etUnYb8SfV6Xbd5IiKG5wUpNsDAP2d0XgpPqEWHBDcQcjrzR6k+gjzvPJNNqe6Cd3KJx+O8r5fk31QGulqtamccEaHkgK7n3efzYX5+ftOQWNM276deAuthjzQhbAYSu3379ku4I+5M1+PX4LQZxotEIhoJaJ7L9AWQKaHGRJoH2u12yy1SzrIsbywW28UZgJKXuG1O+0xk4JEjR37c6XRcowCFEMGPfOQj77dt21IJL6JSqaBcLqNUKglWeBJgNjYvhEIdYagxBKA7twoAgux13r9NdEkz+7lg+HPO6HxG5AktlL3GHC3aNqdikZlMRsRiMY0l9vv9UhWM1CV+ODpOzbKOl87udvuAEEKGw2GqOiOALu6de0eXl5d1KWgAmJ6e/olb9R0AEomEgxHYGPQ27qgyAScAkM/nXau20Wj01aaEdiPVObXbbdcNICnCYGzT90Apnv18B3x8lUrFtRZhtsPifhDz+pZlabCQ3YXmto4dO/Zdt9cCulL905/+dIC6yoRCIWomCWoXRb0EFIhGg7b4N0WGFHRbALouvE5hnZmZIcew5gP1Tff0nHH8OWV0YmxCoQHatkMmk7ENib7OOOFtmgCgWCxa5IwDug9VVZoBsL4vWzQaFeVymbqA9A2b8FbDCvcOn88HAFhZWUGpVPpbt/cbDAa1qmna39wrTWTG1m3bRr1er22G8S688MJd9HtOBiBJejwebTbwcJ8QQp46dcq1E3D79u2XkNpsSnHuHe8zVj0JHD9+/BG3JorP57tkeHjYK4QAzxXvo0Fo3L3yUwAAKpXKwmYANUKI4Ac+8IH3q64yVLREv8uqJbRuEgF0axbycygwl0gmkzrDMp1Oi9nZWZ2+msvlRDabxd69ey3lkNZCEOi1cHquwm3nlNGZh5mr5voGuF3Ove2qnJTDETc3Nyd5cgsALCwsyHw+L7nqBDgADzISicAAzACA7haiaotrSOzy8jKoPbHP55Pz8/M/cXu/Ho8nFI/HpwCn3doPDcfDTuq3kiaESqXypNtrxuPxXzC38XNzzzdtIzQb0P0fjh8/ftAt4wUCgT1er3eEJCpJ2D5jV9t+HwAAIABJREFUcKxzFXt1dbXVaDRcSXXL2Q6r7zHkgKRl47o4cuTIDzYTXw8EAu+//vrrg2DvaqVSoapFGpJNfd8KhYIkoBKAdeFO1vUFQC87k95xpdk6xk3P77lCy50zRue2OL8HE+onhOjH5NoRx0jb6LVazWq32yKZTIIkOr1IBIEtFAoiEolYQDe8Rr+vVqtCCCF5uqrpjCOJ3mg0xFVXXXXvZiCx0WhUO+VMld30xHOpyieCzajvxHi0bjr7CFDDx2BK9na73XILZrEsyxsMBuNKQ+grxfn/TccRI9JxJ0+edC1lydFpTpZExGTE5GZ4c3V1tbUZx5wQIvj7v//7bw8Gu01pqtUqwuEwSH2PRqMoFosgLzzv5Erdf3lDR6pEk06nBddQFUllowvKbKPtz6UH/pwxugGX1B/F1MTYQn0AQLdnojbK5J2kGDrQ7Xo5Pz+vZ00u0clG1zdnWZL6cIdCIUgpRSgUWoc+ovLPpLqTRKc2xaVSyXWoxu/372HSpa80p28ejiJwiRBCrq2tNTejvhPjca2AqdfrsuoY4+uEkXK57DqmftFFF10tpYSlik6QSk1j4Ov0GzoO6DK/qo3vSsoODw+vawPFnylNZjyRx5xUn3766fs3I9XHx8d/kzrH0rtTLpd18lQsFtP5FJ1ORzB4rPa+J5NJat4oVG8Cba+bxKGxmW4r5ufUI3euGF3fMJGyy7UDjkILxOTKZtGxxpmZGUyzBP5WqyXIEZdMJkFABd4HOx6PC4aKE0BXmstuhRlZq9VAbYC56q5i6JKQcT6fz8HsX/jCF1yDZ8hTDDggp6B1ItM7bjrmnn76addJIDt37nwdX2dqusM2NhJdHKruyZMnXTPetm3b4mNjYyP8POz+1x1P1+bHezweWS6XH3BzPSEE9bxbt4+r6jRxmdBZAFhbW9uUVB8ZGbnqwIEDr6UkKNNWLxaLolQqSY7EpHtLJBJkp5MHXlejIRBNNptFsVjUQo5y1dWy1n447sLt2PvRc87oakCSxwU5pp2AMVQnjtR08kICvZpxFDsnzzgPWXDK5/Oi0+kQk+uHwqvMqCKR+qUww2tnoq9//ev1ZrPp2la/6KKLribmMqX5Ruon36YmppObwaJz9Z2k9UaqXz+bGujWoXNzPeUEvNxgMgBnVK/1dWnyW15eXnBzvdXV1QIfNwMFrYPCck2Fj0MIITcr1Xft2vVmoGvuAdCFRkulklD4DJLuYmJiAna3JzvW1taEatHsSHohoio0PLNNSql7rmdY+2XTl3O29FwzurbLaaA0aMLykhQXQuim8nRcsVgUhl0OwOnMYCWfwePnHo9HxmIxEYvFCFcNMKYXQshQKIRgMIilpSVIKQU54qCccEA3xCa6jR2wsrICAKLZbMonnnjia24fwrZt2+Lbtm3zMg+wKVU3/K2tUlpXV1ebm0kCMfu3c3OJ1Gn28jhsalKzi8Wi67BXIBDYbWolvIEFd5DR/dK9kzlTqVQW2u32wjNdq1qtPmJqIFxTIlV9aKiXumFOMkoqNjfjgff5fG9XDUAAOD3gxOykpfCahTRG0ylH2W2m+k7SPJVKScYjmpfMa58NPSd2AEte4LY3j5HTcY4OqtRjms5DPa14J4x0Oi14BVjaTskspKYp2KugrDVV7hnUmonGycdMnnbeiw0Aqe1kfoixsTFce+21ga985Sv3W5uoEvvUU089IFWaJb2otGzAN/VsTQ0gbNvG9u3bd7mtEsuLVXLnl6leq4aPHIkloRymHo9HXnbZZe/yer27+l7EoIMHD/7VysrKOkCKqbn0IzJrxsbGQslk8l0blYgul8t3HjlyZLbfPvM6Ho9HMxxfBnoS8YILLkjs3LnzOhe3BwDI5XLXXHXVVXfTOQQrUMHPTc+4UChIqFqG+XxeUjrryMiIZFmXNlTiCtWEB5xtmFVGkMOx+Wyk+rNmdMlaLG0UR2Uvlfaus+++1WSIZmdnRTqd1g0cUqmUbDQaFi/3TEkGxu91t5ZKpSIIJKNSVB19t4GuJPf5fJrRfT4fTQ66lU8+n89EIpHfc/NciPGI0cw/zdzOGZ+DYF7zmtd83HKZiZXL5W5cXl6u8omkn5puqrqcWXbt2vXL27dv/3U31ysUCrctLi5uKCFNCOlGNDY2Frrooot+dWxsbDfd69ra2olarfbI0aNHtV1NKjhnYM7QJiPQtekYwsi//OUvv85tKapWq/X90dHRdwaDQUftQereqsK4ACCpPTOvHgsAPp/PMet5vV4JdO11XiI6w9ov0yTMhOizorNW3YlRCABjYnVpG5PieqcZRuPOCTqGbHPG5Egmk2g0GhbQDWVMTEw4eqXLbhVP/VAIJBMKhVCr1WjMFjniGJBH900Hup1bGo2GkFKKlZUVUuGRy+Vce9/NKrEb2cumxDfjxW4dVgCwY8eOPfw827Zt4y2CwcJPvAKNQx0uFAoPu73etm3bQoAzXk/AHJ5Kyr3xtI+vN5vNyuHDh//1kUce+W+HDh36yyeffPIvf/7zn3+VmJyOk1JKMm14cgtNAGYYk35LEwGb1F1HGEZGRq7KZDIh7hCjIhUU0YFictu2RaFQkASgYSg50W63dXYbZbbx68zMzGizlBqO8hC12/FuRGfN6IzBdQiNvg1ngiNGTstElIYKdTPkgKP9VBCSurRQVRmgG05bXFxEoVAANb2XUopIJCLC4bB2nlCzRWJwZpdLAJLDXhuNBhqNBsbGxrCysiJUiE0AwNVXX33fZiCxU1NTV3CJatrFG/2OO5qOHz/uOqbOkXm8+IQJKDFtaX782tpay43dDADNZvMEhfSAXuSAhxA9Ho9jsjH9E3ybx+ORjUaj2mw2q7TOz9mPkbldbp6XS39SuwHg5MmTD7t1ygkhgh/60Id+h9aVY44SpCiVVRQKBUt1aRWFQkFraMqPJAA4OrMC3XedCzdVU85RAh3QQuJZed7P+oemXd7PHieHGxHNWNSjCoCGuKbTaYKjakanJvStVkuQJAd6xSApHTUWi1H+MCKRyDqbnL6peQONWQFluLYhmMruUO2bzSZGR0fF4cOHP3rhhRd+zM0zWltbqz3wwAM3nompTdBJP8n/ile84p1u7eaFhYV/KBaLR0zN4ExkqvLhcDgxNTX1rjP9ptPpVBcWFm5pt9uVjeLX5vUJyML9B8Y4eIhx3bvJY+UbEXe+srEKkvhEu3fvdq2+t9vte7xe7zUAZDAYRK1Wk+FwWAIg1KVWwcmxqaJANvVdB7oqvLLTJQBMT09LACToaLySYupKSEp1X8/KRn+2XnfN5GYmGke7AT3nG+BoXaOT8onJKYcXAIENLJogeHYSgWPi8bi2kyKRCKlWfDYUpLZTJ1Wgy+Tj4+OCMtboXpREd6jsADA6OgoA4p577nFdm2xoaCgYj8enaPLjL6/p1zCX+XG1Ws21qhmJRHabnn1TrQY2Tn6RUspqtfrUM0n1Wq12f6PRqAIOrQG0fqZ4OpPMjogE1KRLmoYZsXBz/1xyA70ohjmekydP/tjN+YCe+h4IBATQA1+xOnOOVFQW6nWg5XhhinQ6rQXadLcoBXhRCsU/5NDeehvdDN7Ty0l136gjBVfTiVEJyE80MzMjKTuN2+QcSQRgXSqqbduUOaTXo9EoKIElFApZlUpFEMghEAhwgIwAumg4oNeOScFeBdAFyRAqDuhK82azKZrNpnznO9/5883E1C+44ILdph1uEg+DcfWelo8dO+Zafff7/Zer30qyjwGnWm3aynyZGOLw4cPfabfbj5vnl1K2KpXKv584ceInJq6cGJSktsmotM2E5JqMb56Tq+v0e/6h42j/Rr/lVKlUFjYTU//IRz7iaNWl3i0ZiUQkz2xTdjri8biuj8BBXclkUszNzQkCgFG/dT5RUAorD7GRY/Ns1fdNMzrNmPQSGo0XBHkOAWeVGKqCSWCYbDYrqJyzCfpXKCKRy+VEIpEQQ0NDkh4W9UTnbXPIPjcTWMjTDnTtcsK0Ey0vL2tVj3LQoZifxdBJmtO6LBQKrqV6IBDYs23bNq/5ApvSmzvROIwUADqdTtOt3SyE8AYCgSDZqHROYiQ6zmASh50+NDQkO51O8+DBg99ZXFz8+1qtNruysvJwpVL590OHDv3348eP38fPxRnZRAOasFz+m35Sm08I5rn57/g9q/V1v+Hb+lGj0XDtePR6va8FuuYfd5IxcBbPV9fvHTF7IpEwz6dh3RRSJo2XYUscmqnbsfajs/kxqeT0rVFwtI0QcBnWiIF3mOTQVqCnrhPyjTdoINDJwsKCmJiYEIuLi4ISV6juNi2r8j+ELHM0VVTjlvV63RofHwdh25nnHY1GQygnHACI0dFR/YcSwzebTbznPe8Jfe1rX3MNZjl06NA3isXiEWC9ys6hr2eiWCy2K5FInNFuJjp48OAXTp8+3SLJSja4wWjPGOvudwxjOKj7cR0C6nc+blOb9rX5cvN7oA41ltW/OCYR7etn319wwQWJiy66aFMx9SuvvPIebh5QqA0AotGoBIBSqUQ3KakrK7oVi/UzooYPQC/Mxn1X5Jjj8Eam7W1alT8bG11KKbFv3z7JC0cYgX1B6noqlZKkliibXKgC94J72Kk5A9kxVJonn89rJge6NrlSj0SpVEKpVIJt26JSqUgqFQV0pTm9KPV6HfV6XUopOZOvi/GSh31sbAzE5M1mkzO7GB0dtb7+9a8vbRYSazqXTAbv543mEm9paclVXfROp1M9ffp0E0qa0Xm3bdvmkN48xMalJbu+loj8QxKae8Tp21TLaZmH9bh0p/PxLD4+YdCyGbLjIUHmROz78vPrm8dUKpVn9EVwmpiYeK3y+QjyvgNAKBSy1FiEylfXVY7y+byYmJgQk5OTYn5+nkNjHS3GstmsoC6sTKKbQ5A4S3v9rGx0wAmjFCzVVJGW9szO0KQccJKXh2KN63R6H4UmJicntfONVPVYLEbON4caRZ9arSaArsru9/sppEYlncXy8rIFQFDySqPRgHLAyZWVlXUSanR0VDIVHj//+c//zu0z27ZtW5yw6IQtANYnsgAOhnfYmp1Op1mpVO58pmtVKpVZ+o2pBnPGM6Gk5j5T1TalmJEJ51CRDfjrujAf+zjG2M92N0tK8+fGbXu6Vh+/wbpJhpFotVoLz/RMiUKh0PvoGZBjTvmCZCQSAYurw7IsSXXgLcuiXuvgSDmgG1Onpg8AdFEKoMfoBj6Fv/Ou6axsdHZRxzcASrWT2WxW5nI5LcEBELyVpKx2uNVqNcc4lPNNTE5OCgLFxONx3e0kGo2us5PC4TA+8YlPBB977LHfzefzf9ZsNr9x8uTJ7xaLxduKxeJtJ0+evOWJJ55430MPPXQlGBOxTDXtiFP3JABw+xwA0Gw2JQDceOON97uNqVuqeALfRrXPaJ2njqqXcd2fefTo0fvOlIHVarUeP3ny5MPGy9/32I2kJ+D0ztNxJgP2i80z6blOE+CTiBnbp3FyxufMyxmUxkISnr7pGGau9NWYjAlIHj9+/L6NnmefZxa89957r/L7/UIIIavVKiEuhcJv6GKkBtJRJBIJCYASXtButwnp6RCQ5MNi19Q7CYXK8Suux76Zg/v9LmO0UwK6eeWEY+dxcjpubm4O09PTcnZ21qL0PdUdVQIQKmFFTE5OQsXLEY/HNWOoB6Ehrvfff/9rE4nE9cPDw691M/hOp/N0o9G49zvf+c6XPvrRjz5t2uZ0jxRSoxg60FXlifmPHDmyLxaL/b9urtlqtY488sgj36D1M6maADaMgXs8HnnhhRe+4oILLvhVwoe32+2FRqPx0xMnTjxCXm86F2dg45wUzuqX+dW3Qyv9kKec8oIPfD+Lrfez88/oH+CFI/i5zJwBfo5+9jwdZ243n+3FF1/8brcx9Uaj8a0dO3Z8WHQrCUsAMhQKQUl1PcEQ/l31GQDQ7cZKDD80NCRJqnu9XkcPQCoNTc44+jYduJuJq7tmdBMBZ+yDEIKKRtDF181OSoqDYK2A0/EGdGc8grfS76hDKgfFAMCDDz74up07d7pm8H5Uq9Vu/Zd/+Zcv/sEf/MGxlZUVzdwAZLPZpGW+HUCX4X/4wx++5td+7de+7fZauVzuxnq9XqVn2I/ZeYYXJ5Jk/EU1c7HVt+MFIKbc6Hr9iM7fj0E3Okcfm3ndMRvto3s60+TAO6P0Oa+esPpJuo1y1Om627dvf0U0Gv3tfvdlkpSy9kd/9Ee/dPPNN1eXlpYk7+UHQCMBla2+jtm3bdtmLywsUPaldtqRB/6lL32pzR3X6luSM4wkOmHh3YwZOAuJTg+S16Q2wDEOTzu7hlBSXADQTRgUo+sQBP8jbdXznNvlnU7HKpfLYmVl5c9GR0c/uNnx96NOp/P0U0899eU9e/ZkufSmcfNv/iK1Wi10Op2fWS4z2srl8p1PPvnknVJlivF9/WLSUsqNgCeAIfWZyt8drBDrij3Qb00JDjhKMnNJDnQBLH0npDMx9WbIkNT6mjyTz9wHONNAaaLYyKt/pklkaGjIm0wmP2K5TB5aXFz80Mtf/vJvCSFkrVbTjTtVgxDJvO860QVwJruoclNyZGRE8iQXVUBS8iQXXn2GaLOM7vof4i+4Cp1JvkxJKjQTAb2ab9PT0xoJlEqlBIUVmDQH0JPmtm2LfD5vcTuW7PJvfetbU6dPn77ruWJyAPB4PDuTyeRfHD16NHMGJpfNZhOtVkt/vF4vjh8/7topFwgELt8ouaUfbWSHmUxN62RPezwe2cfmdzjO+tjI6wosmhJ8g/2O328UF+f76XxsPCYe3nEuc585nj6Tl2PyMZN4TFpbW2u1Wq114KCN6IILLng70I2p0zb1X8lIJKJj6tFo1OGHIQyIauGkz9dqtQQx+fT0tNaCeQo34Mwn2cx7BGyC0Vm8lKpW8oQVXUSCmDybzQqCuAJdu5yy0CjlFOih3hh6yCHRi8UiisWisG1bZLPZXW984xv/bWho6LJN3aVLikajv1etVv/92muvDSokHICumi676arC63VO+j/+8Y/vcHv+oaGhIDUk6Gc7mutnssF4WImr64aU7qvm03FsXBtVa1nnEecee77NYPoNPwDg9XptE9F2JufZtm3b+jrx6Nr8/szzcJOH35P5PKvVqmvwzMjIyFUf/OAHQwCgykITCtOBXOMVjlSeOgDo/uoUXcrlcg7PeywW07XfuTQn5uZJY25pU0dzrx+R0S9NZDIZhxNuenoa9XpdF49IpVJot9vC7KpBdjkHxChGFwDETTfdFHz/+99/t2VZU5u6w7Og1dXV3Hvf+97fufXWW+vd25bmhCgAkFQXp06d+sexsbHXuDl3rVZ74PHHH7/dfNk4I/L0S06mJCf12Qg3bXhe07G2GZVb/UZAmQym2s5U+WdMXOFmArfN+xGfAM1z8d+Z59jIWUf2Opk//Jwvf/nLrxeqPt0zUbFY/Mz27dv/OhgMSgCo1WoSChILAOVyWcZiMan8SnY8Huf/kwO+Oz8/L1OpFHK5nGO2JxUeLOGF7PPNJrlsyhlnziKUvEJ2BElpss1phuJ2Oa+f1Wq19JtGD5wlBFhAt1Gibdvi2LFjX/F6vb/rdrzPlprN5k/GxsbeNjo6SsUntJPROFQcOHDg/7n44ov/q5vz2rbdevjhh2/sdDpNvp3+9H5x436xYdpnHs/3baTmbkScOek8nFnO9Nt+UFPTzu5nHxs2uDAnCG6P8yiAOuaMzG+uKyy6tudpcqJz7Ny5c9rv909veJOM2u32Pdu3b78GAJT3HVCAlnA4DI/HY5NDju6DMzo9s4WFBZlMJmHa6kBXslP0KpVK6dTVzdrnwCZVd/SyaZDJZBy900x7QsXMdVkoswMqOeD0QCyLUvsQi8V08b1SqSQee+yxd2wlkwPA6Ojor5w6depLANBqtSS64ArTfhcA8JnPfOaf3Z7XUuWZ+TbOJNQSmDOrwWzSYA5HDJod0y9G7RiLabOzY00fwP/P3rtHR3aVd6K/fUqP6la9u6rVrla35KaM2xZJzMghTnjccpJhbO7KBOemgzN3CDhrkVyTBGZYMAtCnJZvmFyCM4tAIGDwuhfHwbEtnhkYspJLUIjtyQ0RD9My2BZY7pZl5FLXW209z75/1P7t+s6uU+qqdrvdGL61tFSP89jn1Pn2/h6/7/eFmthuYYlznbQe7Arm7jM0NCSBM3BfS2Sfe338zB2Di8bjdu5r3ldfcLw1Go3FsN8sTIaHh1/+hS984Sfq9TpMB1adSqVIQsrJw5ryKysrtj6DYqLvamFhwSo5hYUurl4BOKc8+jkF44Syd/zANLVnZ2eZO1dMHbCv+cLCgg1GLC0tqaWlJVv146TR8MUvfnE8m82+s5+LcmVnZ6faT7M9SiaT+dVHHnnkP6Ol5DD+uVpfX1fr6y006vr6Oj7/+c/Xz5w50zPw4uDBg6+SdEhSkeUKbb5TroKGmfWULim3wASwi3K6/8OKSzo+d753wS5d3QrpN0uldld/aWHwT16D7/tuBD4wGfG/BAnJCYX71uv1viCxP/mTP3k9AMlehGq1CrbnNo1DoLVWpppNy94DExMTGBgY0IVCQbmgMaCdT2fcK8Qx77marZ8VnefSIurOGceWnzJySCIJlp0CsP55oVDQLDtlfpHtbViJxrLTa6+99p3n4pdvbGwsnjp16s75+fn3PfTQQx/8+te//ucPPfTQbT/4wQ/+ph+lP3To0H9aWlp6K4NwRuE7zPj777//A70eU0JipbiEhq5yuEEvWWcdsgprAB1glpCxdIWkyvPKfVyXIgwyGzY5iWvqGAf9eqnAxOc7k03oMd0IvbAm7Ptu94Dn9H1fnTlzpufoezwe/3XShpueAQBa7DPlchme1+JJWF1dxcrKiu21J6PvnGQWFhY0S1dpBc/MzAT4FCX23YnAn1XZ+1nRLaUN3zPSzqJ5oBVA4D4MwgGtVNra2ppngP0eo+xUcPFDKBaqpNNpNTw83BcYZmdnp3rq1Kk7H3744b9cXV19YnNzc503c2NjY/3UqVPf+trXvvahp59++u/8HuuRDx48+J++9rWv/SqvfX19XUWjUQXht995553f7QcSm8/nf8q8DsQnZE04nFx5mH9r/oetrrtOEtzOsQ7cSHhAqV3ll+6DDMCFmOEdZbGu2e0eX4wtYBWgXazTYaJDTGxhFgbvwW5BrNOnT3+j23eueJ53+J/+6Z9ekUgklKGFtgqXTqfV6uqqymQy1g31DZQbaAWfTcEWgLZra6xfVWyRUWignaZ2c+lEpfZUOdjrRfFgjKyLk9ltJMEjWxzzIphKkPlDPuCMsrNQhXRQDz300P/az2q+s7NTXVhY+MvV1dUnxDk6ViSlFL7//e//y/z8/B29ru4veclLbvv85z//MwBglJzoPqW1Vp/5zGfqpVKpZ1/d8KJ3ADx2izI716ClcnFfowwd8Q+g06ynEko/31VG19ym4nCfLqk1qVgd+fqQsQSuPcwyCEnH2W26pdaAAFBG8357nhdaEWf+98yZBwCHDh16OdDKqddqNZBiSl6vVMSVlRXk8/lA+yag5dZubGyo9fV1NTU1FeCTCzPdzUKr0WNQrm9Ik2ypxM8kqQRgObCAlmkPALaNksSwi4u3qDNZAZTJZPpazU+fPv2P6+vrVnHND6sYsSXSjt+vra1VH3744b/a3t7uSdl/8Rd/8fa77rrrSsCa8BgeHlYbGxsaAL75zW/+v72ONRqNjsfj8Y6eYvLBDlEyAO1J11UW6deKz63CSuBImKLIfZw0nHuegHK4fjm3lWM5W8DP+TwU8CNX6LAJPOzeuZObfO8ytnjGX+8HPLN3796Xy/eVSqUjl27qzAG0qc/4/cTEBPu0qYWFBbBjMIPZ1CtJrmraLPcFmuk3vaZhJgd5YqBVyMI2Sjy2JJIA2k0XANhilXw+j+XlZU80rPMYzNjc3PxCrzj2jY2Nxe985zt3KqWUG5yhCEZQe5O2t7fVvn37Ri+//PL/6PUAgdze3l667bbb/sPv//7vPxmNRq3C8//a2to3vD4gsd/73vf+EehMmQHBh5SmMk1Pd+U0x4BzrEB0mscKUeSzFp64cNrt7W01NDRkxxS2v9xWBM46ILXd4Kl8z31kcYv5D743nwXy4lzBu+Hjub/MsZtxRwuFwrvcfbrJLbfccuQ973lPDeZ+ExIrGX6AYKELgisx3+vJyckO3ndZn64d7e6V+KNf093mzGWlGtAyL1g4z0q1+fn5QNptYmLCooKo5FtbWx5nu9XVVaVarZNUMpn0lFIdK143WVtbe4R5UlcklJZKzpUeACqVysojjzzyV7347AMDA2PveMc77v7jP/7jg2HfLy8v/z+9jjmVSr3MDRq5D4d8LVfAboop9usa7XaPH3bPuGKG+dacOKSPTgmD10qa47CxcD90oX5y9+mCqguzEOxEKI+7m0sEtCCxm5ubi7ttI+Utb3nLryeTSW1SbBpor+zSQgVgGzLC8CywEzAAVSgULHIUaFvGxl220XDn9D2x+4STYocLezfbABSVWDZiEANk4QrbLnXcXBLdSymXy4p+jud5/Sj6D8I+548qa+dd33hnZ0edPn16ZWFh4VO9tEAaGBgYe9vb3vbREydO/O+f+cxn6lzNtdbqzjvv/My73/3ut/YyZs/zoqOjo4dJMzU4OOg+jIEUUpgfLLaX4+v6w3dzB4Q5rsK2CzsPzyVBKGF+9s7Ojn0diUQC7+UxAKjt7e2w76xvLQN/nCTldwMDAx3FMPJYbiGMb6DGWutAGnNzc/PxoaGhibB74EoikXh5rVb7qCEh9U0+HUopYt+5qQZs11/NTkMAbIELAMzPz9tqNhN5Z5GLPafIfJ3fFV2UxsEMJhAokN1PJycnlYH08SIAtFZ0+uf5fN5W85gWtIG8I1MVvQrNcpmyoMknxy0eZHsu/l9ZWTnd8yimAAAgAElEQVR58uTJL/RyvuHh4Ss/9rGPfRSAVfKNjQ39nve8Z2ltba3n9ryZTOZyjkfGD7opq/uDUhH4Wj7gwqcN+NEUV8nF59Ia6BiDXCmFsrGhZOg+lJ2dnVCePI6Rqy8fevf3kq8lso3XKSaBjms72yRmtgEA1Ov1J7pt48rQ0NDLzT46mUyqarXqtqOykfdcLmepoKnkDFBvbGwoCSyTHA7FYlHNz8+r+fl5JStHe1Fy4Byi7qSNmpyc1EytzczMqFwup4sG8hqNRjVx7fPz87ZCzVSnKaBluu/s7KhSqYRsNmvz5oL3TW1ubp7odXxDQ0PDQKeC+L5PSyTg27kgFb5+4oknHlpeXu4pqDYyMvIzS0tL7+N75tqXl5d7LnSJxWI/tXfv3o6cOh9g+aC7P2iIud4VTNNFYUKpl6isIWmzDp/f8zwdiUR2VR6KtFgGBwd1JBLpuu3Ozo6cnGwQjrl1XqszLiq7vVb3euXrMJeF+1Wr1UWtdc/dXB588MGfMM0dLO87AEsvJd0FWcsBtBByZJ4BWik2tm2iTtFXp79O8tVei1v6gdF1+AYS3/7973/fi8fjmuQSMKa7U6VmTXgThJOEEpYxxvja3pNPPvlfY7HY/9HL4Or1+v/3yCOPdNAwOwi0DjSaG4ihHD169JW5XO6VvZx7aWnpA4VC4c83NjZ0NBrFL/3SLyXuu+++nvOxi4uLf1mpVBaB4KTj+sZnCcIFotSuXy+DfbsF47hvWNBMmMhdOeoHBwf11tZW6HNlro3fac/zwG0HBwe1yYoEXlO6Fa04k7d1HdzfWmzXEceRxyYE2fd9XHrppb8+PDx8NOxaXDl9+vTvZ7PZ24FWNxdDNaVhSlfN9ctyXEvp7VbgLSwsyAFqRuAhyCGNvd5zcUs/ig5zAiWmEfro1nSnucFqNbSCDNje3raKns/nrQKaFVfxvzSlH3jggVdMTk7+TY/jWj9x4sQH19fXN/gZH0h5LvdHlooOBCO9L3nJS17Rr7Lzpp8+ffqTvVa0bWxsLD788MN/CXRG3KUyykmAD4hUbplychWbx5DvpUg/GU5gK8yvprhK6aL75P5c0d34CI8jJ4huE0ZY5P1sr+V+7mu5vYswy+VyP5tOp68LvXBHNjY2/kc0Gn09RKVZOp3eLfKOfD5vv+Pvtri4qCcnJ7Ubeed5WNwiffRexneuWHfbpKFYLLppNSLHNACC9m2nlbGxsYDPRMgr0GqlRNI9APjsZz97Qmtd62V8SqnowYMHOxTLfehc31x+Lmd9ADhx4sT9pVLpn3o5/9jY2Fv/+Z//+VdISvHVr371g73sBwDDw8MTQ0NDUbe6SZrRBMjIz81Y7X/XxHZfh70HOokmXNO/m5LL8xpTXHueZ83ySCSCwcFBzdVLjMH+DpFIRJvJwr6WSu6a93JsIaZ7R0TebBe6oAmrwH5GxfR9H2fOnHm864U7MjQ09PJEIoFkshU/Jt24G3kvlUpYWVlRMp++tLTEhdBSPYvIe6DdE4V4lvOOdTeibr31ViWoozTQ8h/oSwBg0t8GiEywQTH4QGA/6aEA68twRde1Wg233HJLbWNj44FeB5dKpV4WhiEHdl/NKSFRWX3ixIn7T58+/bVezn/VVVe974tf/OI10WhU33XXXd/x++i8euDAgZ+SY3W/383fdEWk7Had7bsVt7hC5ZN/VEDHl3fHtyvdlLwmV4F5DmEpBK5bToJ878YUxHbWSpLnCasdYHDL8zw0Go0f9OOn33HHHYeBFhmFg323sZZcLofR0VEtO66yEePExESgjNuUq2qgFfR+NsUt5wKBtRxW8/PzihU2phFDoL0SI4jmItixAvl8Hr7vq1wuh1KpBN/3Ff0Yng4AEokEHn300dt7HaPnedEjR478MtCd/VOaaHKVdIUR5YGBAf3www//fbVa7akzy3XXXfeRj3/841d+5jOfqfUDiY3FYpdzLBJcIsfHhzgsAu0EoTqCdm5ue7dJgErFFZbnBoCtrS1bFy6Da2FytmCY+9pVen4uFb5blZqY3PjexhqA9iQuJyRpDUmRVuDm5mZo2jZMrr766pcQCgvDDlupVKCU0uVymSg5+zvJXgVuDGJ+fh6zs7NqampKGR45+925FLf0ZbobU0FbTikhc3Nzml0igWD9ucsmY6Lt2kTcwwI7GgDq9Tpe8YpXPNDPqj4yMnL5xMTEz4ginNaFioATJy03d2q2057XpjHmuL/xjW984ZlnnjlrysXzvMSNN9740c9+9rPXRKPRsbNtTxkeHp6Ix+MpIIjPluN1/XYXtLJb6WnINXZ8TsV1/OmAcpjPOyaSMIWWq6kb4At77SguAOvz22O7q3LYuaj08vuQbe1n8r651FNbW1tPddyoLpLL5aT5rgBbyaYAWM53IVR4PTDQIoxk5F3qD61lWdziMjtx7N3G1jfWXa7sLgkkRRI0DA8Pa+GfW2QcUwxmVbWR2Gq1ilQqhUQioVgCWCqVeqZUBoBcLvfqXC43zvduainsITfb2dc0Ban0nufpb3/725/e2NhYCd1ZyMDAwNh11113dzKZ/Lf9jHvfvn2saAv4s0T8uTEECS3drbBDiquUQHsFp8kst0UX/vfdju9EuN3gmVwgZP47QKRIZaPP75xDZgsCgbWwCU/cEwnFdScnAG0WGsYU+lnRBwcHD9frdabY7GICEXmHIBylDjiNGBXNd6e5g9U3J4/eU3FL34oO46cfP35cu8QTpMBhIE72UltaWtK8qJWVFW1IJriqElyg0ul0B9LniiuuuHd9ff3BfgZ56aWXHhsZGUnR8KDiAp0BOkqYEshJYmNjY/3rX//63b0WwfQryWTyGp6Lwgor6XN3czekSLM1bFUT5jlBLO6qze0BAad1A2CuCPeiY9Xnfu51dDumvA8cE8ctEHkdJBju/vI+SPcoLBXHFZ1ptmaz2TNwZnBw8CU8DAPKhI6Xy2Xl+z6BM8jlcrZGfXl52VpxhUJBLywsED6ugVZAjsUtElLeT3FL3+m16elp7/jx4/rXfu3XvJmZGW2aNgCmhlYSQfIcsjkDbyrhr2STITccI5W63T9NxeNx9dWvfvXlV1111ef6GevOzk71W9/61h1bW1vrIsUGrbWSTC7St+HKyYeHqzk/830f8Xg8+RM/8RP/cXBwsGeIbq+yvLz8iXK5vEi/WpJLSLipa3J2Ky+Vr8PeA+2U2Nl8bnmMEOsnwOfmbN/VXBevAwrfLcbCaLyMX3SzduT+Ap4biHvIdB3PIZ8VADh69OitvdwXAFBK7YOZGJlP9zzPF0E+m3IrlUpasM7YtBxaxS120ZQcciSLdLnezycEVmmt1fT0tFZKKYOKs8wyTOrPzc3ZmUgG42i+U0qlkgZaZXyuklerVdRqNZVIJBCPx9FoNNQrX/nK/1mr1T7W63gBIBKJpK688spjWuvAwy1vSlgenb65IBC01VO+76tarVb/9re//cnnYmVPJBJHu/nVNEtdH9tVZHe/bueSwbZu5nGYuCtwmFku/eEu4wy87maliEmkI5UoJjqp1N391JBJLsSC61CafhiJ7rvvvsOGhAJAi1pKa61YkUlhWnl5eVmJ+nQArZT0/Py82tjYIOMMg97EraiQTqsKuyzc52K626if4Z3WbqMG86fNqq7N4LG0tITl5WWXJM/O3iaHjlQqZb9sNBo2zfDe9773tp2dnVP9jDUajY4fPXr01WH+nxulDHvYZPRWVmY1Go3qiRMnPrm1tdVTnr9XGRkZuWpgYMCWy7oVed0ixWHXIHHwQNtsNjluC2wRJm7H8XabROQxnT/7XdgKHyZyf9fvltaJ/C+DljJ/7vrpvbo60k/nsTzPw/b2dl+Rd2ONAoBlnSG9FCPvTCtzRTfXqMkjB0CbHuoA2sUtQLt3OtA23yGIW0Ovr9cLMPW10vkH0FZ62eucMjk5GYgeMo+ez+e1ZJWJRCK+8NOlCWOl2WziQx/6UP3v//7vb+p1zJRUKvWyQqHw02E/pgvkAILgE5G26ah8qtVqtfn5+Z7KW3sVpVQ0mUxOcJWTAA45RinStDfvtXlAO9oxAa2oepipLo8tVlF5jJ5Me7ndbpZBN3EnDvldmHsRYsWE/YYdxzLf8b/9bd121js7Oz3/vsPDw0kyw9ZqtUBXWsBG3gMZKPImiiYmKBQKCmgFtqnsQLu4BegIyu1a3NLXii4q2CzO3UTf9bFjx/Tc3Jw9ESPvHNTi4iJMWZ6ldfY8T9OEWV1dtTNftVq1po8r119//YmnnnqqJw51Kfv37391Mpk8IBVIKdWxqlH4cIj8q3JXDQBoNBq1hx9++JPnU9nT6fQ1nucF4LDu+MJWLDdHHDYpSMRaD0PpYI7ppoDnWxiFd1b3btt25Nc5SQGBqj77Xmxr9+l2z3Z2diodH3aRkZGRQ4lEArVajS2VyZwUcG9KpRJGR0exsrKiyZfAgLVMsdENZoqNnA8AXB9913H1HIwTM4ZND/A7Kv3MzAympqZkcQsjibaR4tjYGCvY5HEsT1ylUlGs/uGfMd/ZFgnNZlOVy+U/SqfTb+p1/EDL13r44Yf/qmbsqjATvtuP7Qq34//R0dHDvdSy9yrf//73/6/t7e11WcgS9l+aqbvxvcmH20SuQ4kaxAourasLLm6wTnweyJq4wTQRL4D8XLwOsNXI2nW5LZ93rbXKZrNXZTKZG3oZ99ra2l/HYrHfBYBkMmmZZiqVigZaFNAyIGdcqVDm3YWFBXn/ZQrNzni9Frf0TDwh4YFaa3XrrbdalBwT9sZX94nNJb2zJIbc3t5m5Zo2BfgwrWvg+z7S6XSAy6vRaOh4PK4ajYaKxWJ2oslkMn/4zDPPTEaj0Z/r9RoikUjqxS9+8bH5+fm7zpw5syGirAHyAanEUuR3rr+4srJycmRk5L8fPHjwl3odz26SSqWOrq6uftOlgAICk1EgIi/3P8uEFZpLPkcz/YILU4Ju/KFb5D/MJZMiJwiKVJrt7e1zstbMeqJSqRQymYzrmgJok0X6LXScrGCzbq8beUerMlQL4IydOLqZ8H0XtRAU51LPsoJtZmYmUODCWcn0g7YBOfolzKXLhnRMSQAtGCyl2WwCAEZGRjAyMqLf+c53/ma/wbnh4eHRyy677NVAW3EdkoCAEss/+Z0UztqPP/74Q08++eR/72c83WRoaCglZv0OP9wZ365+qzsJuN1gxD4XjXK7q7mceEMmvEBKVMZiwuRs2QGKyMj0rOgDAwOHDTrOpth4LBl5D4OrLi0tkUAVhUIhgHunyAIXouNEcUtXP70vH10ehD3XgM7iFvoTss3M4uIii1tsBRv99NXVVZ3NZuF5nq5UKrbTRb1e1/V6HY1GAwD8eDyum80m1tbWAAB33HFH9a677vrf/D6KRwAgHo//5JVXXvnKs0Vjfaeyyb0XchYFWg/j448//lCvFW+7iecQVfJBlAE2t2RTbife22s5m/QaIb+QwniAUGq1tbVF/vsAw4w0x3ezaBwzORQuK1fGjY2NvtKo9XrrcQwpbrHbKKW0rNwEOhlnJNfe7Owscrmclj56WN90aQ1L6YczLtBokUpu7Hl7R00+XQGWjF6L5orarOxqbGxMj46OktRer6ysqEwmQ9PGxgOSyWSgHC8Wi+lms2lB/DfddNOpo0eP3nTNNdf0XEACAJlM5lWXXnpp7fHHH3+I5rsUpZQeHBwM+PDuyk+R4JuBgQH92GOPfVUppbPZ7Kv6GZMU5uiN8oWa6LvBXuWqJ1c7loBKRaBPLpXmXMf9XEhIihCyVl2symEBSXLOBcx6mZrrxiNHy6cf8QzPoQF7aYjilkwmo0XJqsrlcrpUKlkL1/d9Vnja+0/g2dTUFNFxemZmBpOTk+RqZFQf/B+WZusnvQbAYmsVAJ+BANGpRc3OzupisWjzfzI1wJpbKaVSSfsGGuh5npa8cTDlqpwhzTh0LBaz8YKRkRH9C7/wC/9zaWnpeK/XQrnkkkv+7b59+0blakdif6212tnZUTyPtGb4Pb8TfrtVvEcfffSfVldXv9rvmCishXbN0C65/kCr4t0eTrMakhlXKsK5DvWCCS2sbqlG17Q3nyn3M74PW8nlccPiNGeTSCSSoOkuM0chxS0d41leXtZAK0MlaKXsdrILEtDKp4cVt4RJv1F3O1uIoJySfdGBth8hWzIBrVSbC4c18D9P+Oo2Gs/OlITDiqCcQrsG1x7/1KlT/2e/kfjt7e3ad77znbtkJB5oPzSEywLtlknyeylh1WNXXHHFq5PJ5Mv6GdPGxsZ3T548ebecPNzIehgDTbeH1/XjnbZPENtdVCs5JSzFJslAPS/IQCu3F+7Nbt91wGKl5TY8PJwaHx//zz2O9WQ6nX6pWZws/TMAVKtVP5vNagBkhtUANJlmAGB5edk3Vm9oO2WyzRAie/z4cRl15zE7gn59AWZIRmdmEVvcYjpJKFkcD4Bw2NDjMSgHAKOjo7pUKll6XKA1A8pV1ATlVDweh1JKN5tNvba2hrW1NesnZzKZ41tbWz0TSgLAwMBA8ujRo8f27NkzLNIsoTXrDssLPK+zba+USCSiv/vd7/5dpVL5x17H4/t+dXV19X+4Si79SjlOZ9/Ays593TGFnfeHQckpZsIFEJzwzlbB1y0GIe8jt+FvfS6WjrRA3eIWLmTZbBa5XA65XE4RKbq8vGz980KhABa3SKF+cVFVSoF6qQWluSt9reg8MGcPLVozsVn79PS0IjMs+eNIFkm0j+CPw+joqAe0bjDr012iSHHDvHg8DgCKRBcAMDIyotbW1tTIyAg+8IEPHH7jG9/4qUgkcqjXawOAcrn8L48++ujfuXlYtwCm10i12cf6xocPH/6ZTCbzskgkkgrbHgA2NzcXn3rqqc9ubm5WwnxxBzgTSgbJ7aSvzf27reRnu5aLQAIFLABk4Yn9zuWCc/Pq8jWtAO4nJs+O4pZ+VvSNjY0HotHoL0PkvXfr3AIApVLJHxsb08bC1WJfDbTNd9m5RcbIzLF2zaX3E2VV5riBmUSA620u3eWQm5qaUnNzc4r9pdCqaAvQP8PU5+7s7Hi+71skEUweUprvMGZ7s9lELBaD1tozkXi1d+9edd99901ef/31n/Z6bI1EWV1d/erCwsJXAXQ8FPJ1LwqhlHLNZx2LxVKjo6M/tWfPnvHBwcEDnudFd3Z2qhsbG4v1ev0b9Xp9EbAKGWqq81hd0m27bvvDZrK7sr297THS7rL7hpnoUrldIhF+xm3lvvycz/rIyMiBgwcP3tzLGKnoiUTCpoiBVnFLOp3WlUpFS9AMi7sAaGajiJAzJataIOQ0g3EwFWxum6ZuCt+vj84gmDUPZJqNxywWi2p2dlZPTU15QJCIQgBoFFFypH4GoMyKDrTQciiXy565QQot091Da0VHPB63+UOttVpbW8PIyIgCgIceeuh1R44c+bNer4/yve99766VlZWTMkIrzbfdFF3WvrvfOci00NVa5s0l9ZO3CzjG9ctdH90N5rkc7LzOi1HZd0v3iXLVgDKHrcxy5RbHDuznnle6b4lEYuLAgQM39TLmjY2NB/bv3//vDd5d12o1zSItKn65XLbKTf44U9yiJyYmGJCzparz8/O6WCxqUj4fO3Ys4KPz3G4MTY6rX6x7IFkvIvHWzABsPl0dOXLEj8fjmnjd+fl5DA8Pa3ZuAdo59Xw+r/P5vC8GyP8+8+rJZBKNRiNwrmazqZvNpjYReHvcF73oRfc+/fTT/62f6wNahBXscsocLv1xMp2G4Yq5CrsKI/13mm98AKVPKR8svg+baCjyXHKcPCf/SyUnI6s8zsWq5EDnNQItBXdSawCCNe27BePOJq6Sm9/qrM03xflO1ut1BbSQcWfp3GLTp0Arj06XdmJiQm1sbFi2mUajoQxGRc3MzEAWtrhjCDPf+wJIcKDklHZ9dadNkyWi4P4kpKAJXygUsL6+7gEAV3YSUjByb3Lr8H2fvrxngh3K4N+VQcypWCyGZrOpRkZGQJ99eXn5A4lE4tf6uc6dnZ3qt7/97TvW19fXzTkDyuCa5VKkXw4HT07cOoWTABW/G64dwh8HglZFWBAwzL+nhNWdX8zKDoRj3SUM1jW5Zc5cmPCA4+uLidTFw9tza61VP/zujUbj9oMHD75bKaXr9br10YHW728w7zqbzWJ1dZWLnM9cuud5emlpiXgTn91VRcEYuyOFkU/IoZyb6S4v3A3ISX+dZrwpclFAC0TjKjwArK2teSKvrgBYZWfNrhbNHSqViq0IAoBareYZnx1MuwkXw1tbW8Pv/M7vJN7//vd/WtD89CTr6+tPfOtb37rLXHNrgCGmuaskUpFd5aGP7PudjRbkJOAG2ELeW7aZEEhsxzko5E8PCyhe7MoOtO41UXECB2BTtW4KzU2ZuYE5sW/gHDIQ6/s+xsbGirFY7NpexlipVN43Pj7+PlfRucqyuCWbzYYWtiwtLYHm+4DpQUeLGJ0l3Na6dfSx43c8J+IJeXD5H4AtXQU6E/wAwIo2KWNjY2whK820jn3ZZRWwBQO60WhoU/iiYcD9BiarR0ZG8OEPf7j2yU9+sm9MfDQaHb/88stfLa/NIPRsFRTHKs1wrh5SaSKRiJb5dzcNJH8Y11Q1ooSyQ2xrH1i5jxuhpridT8T2F7WSy5V5cHAwUFrs/g7ufvI/xQmuBiZtqeTcdnBw8JJex3r69OkTRsntZ9VqFSbGhEwmA0ltzvMz1UwYLJ+R+fl5S+ZioOVMZ8vIuz3eecG6U2TkXf4HbCI/cGMNxZQ2aTZtiO8ICtADAwN6aWmJ6QUALZZYRiZ5AZVKxRbzJ5NJ5tal6WIniFgsptfW1nwA+N3f/d1Tf/u3f/ubfp+Y+FQq9bIjR468TClllTXMF+cKsVtOnRLCUGppp53gW2ivcfN954zduUoHJiTZcEGM+6JXcCB4vd36upntA9fkBCftdt3aM+0iPfvoZ86csYxDyWTSmu2SNUkE40IDjgYZp2QFG4VsToIkUsbKunK7963oYTOGNNvNn92GRS5TU1PK5XxnUG5xcRETExNYXl7W+XwekUhEs7VsqVRCuVzmwx5Y6TkWk1vXjUYDJuWmm80mRkZGFAN0r3vd60489dRTf9rv9e7fv//V+/fvH+d7ZzXfFW+uDIMr30vmUsfn71mRmSOXxwkLNLkmumhe6G7Xt/t2oUT62eZ9IGPhMuhwH/k+LOIuRTbL4Dmk+L6PoaGhA72O+a//+q9PUNlIJ5VKpbiqA2jHnThePuscjwHNBILWFINztxF5I6EBYinnarp3rOZaay2VnQMhZC8ej+u5uTldLBYtpG9hYYEVOtbnIN43n8/rlZUVjI6OBr4nYk4ppU1UUyultKlwA4IresCnufzyyz++urrat7KPj48HIvFi1ba+lKtAYQg0kYeX9zHUv+f2PKdzjI5uLSEPPGAYYsgRt7W1tWtjg4tJqOAhY7NPtMyL77Yyu7+NPKaMyougnZV4PH5AKdXTiq61rr33ve+tAe3y6mq1qkz1miZvnOe1KjZNHzbbbJE92La3txXhrzz23NycZjaLmHaRQ1cyjhS2qp+LotuD8ISCt0pzAFT2mZkZq+ymso1IOQ1Ab2xsqEKhYGeysbExUNkhVm9GKKUpn06n/VqtZk32RCLBUlZtIvHW9F9bW9Nra2t6YmLiv/XLEe95XvSyyy77DfZ1k8EcsY19LZolBr6XviG34+fuyhxGH9WrckoXgGwyAJScfJxI9kW3qougohvsDL1uh1orsDp3893FMTsmYMrg4GBXJKMrm5ubJwxrMeheplIpnUqlkE6nQbAMcSIkiJTgH+PG+oLbnfoCwQJrdezWW29VOgTy6sq5KDqruyBTbKJ81Sq7FNbSMqAAtKB9CwsLenh4WC8sLOjFxUUMDAxoo+wAgJWVFT06OqpHR0d1LpfT5XI5QM2TSqW01lolEgk5k+l4PK5Nug1ra2s6Fotpk3bD29/+9pv6Dc5FIpHUZZdd9u/DiknOJtJUd4NqbkDInQzCzrHbBMAJgis5iSDPMjGc9RoutIRNRL7v7+qjy+Cc7/uhq7x7v8OsMbnt3r17L+11zJubmye4sJgyVVSr1UCzRW4rWyFTxsbGsL29bQu/KAzEmYVSz8zMWPo2biNN9/MWdRcpLFvsAtjkPfs2Y35+nrh3PTMzg2KxaEcjyldJC41CoWCVnQw0/E/hDcpkMrbZvCGo0I1Gg6w0utFoaJa0GgoqKrz/iU98onYuhBXRaPTo+Ph40e15BiAQrOP2VPBuJrkUaVLLiSCMUUa+do8t00iyxl767M4k0vVBf74kLD22tbWlHNhrwKpyySF3sVIUuqSVeY+YVgOAwcHBnv3zlZWVB8yio2FKrLudizgR0ZYJhIOTYQaAkmWqs7OzllqdFrPMo4eBZ+RFP2uRuXVWtAm8rCd7s0kqHEMgCQAoFAoe0K5ZFwQV8H3f/sgrKysKBlnktzHxhCp69XodXN1FSStpqBQAAmrwL//yLy//6Z/+6b4IK8wY/mZ5efmb8jMJX5UiFZdK5TngGLmf2L5jkgijShJ+v5bbuOLi3KUyXEw+ujS7XUWXXVUpYeSQYfn0XfLsAcCN57WLWTzPixYKhXf1Ovb777//2te85jXfbjQa2sBfAUM8Qax7JBLxBZRcs1sL0Gq2ODExwWYnenJyUpv0muWMA9qL3czMjHVxuejKqks5tmdls7n14MpwyRmlt8R1jBTKfVn0whzhwsKCbxoy6kKhoIF2U8bl5WW9srLC4F5gDIaeR/rvNodJf10pZU35WCxm4bIve9nLHnjyySf/sN/rzuVyr04mk6NAeyXv5uPJ2xUS8barkqtsbq7edRl4LBcT75qrRMLtNraL0UeHg6MwlpI2mQPlmuac8Nxsg/lOTgYdr4FQvDsSicREr4P1ff/ka17zGttamwqXSieAWGEAACAASURBVKUYT9JAi9Z8Z2fHI0fi6Ogom5rYY01MTKBQKISWeNN0n5yc1AyAA8EgXFgE/lkpusxbE0wSllt3m8MBrcCc7KUOoOPCWMVDEEEkEmG1j30ITIBDp9Npm1+HiSNQwRuNhhJReSsjIyMYGxv7eKVS+Xg/1+15XnR8fPx1e/futYGaLuZ4WEAtsPpL09ldzeU+7mrEc4adVz603XxaeZyLaUUHOk1v81rt7OwokznQMFxvfkjlGldmfiatnd3cKLIKibTt0V7HvLW1dYLoz0QiAaWUTqVSmi2ZAPusIhKJ+ABk5ZodwuLiol5cXNSATUPb1Vz2SWcg7vjx41ronpY6GbinvV7IbtIth2c6ruK+++7zTQReMyiXy+X01NQU5ubmbDcK09lFLywsSNCJTWVx1svlclhdXbXKUC6XUalUNIsHkskk6vU6SCwZj8c1c+1or/6+qXbTmUzmln4j8ZFIJPWiF73o1wYHB6NA9wivlG5Remefjo6fzmoT6rOb9wFzX3Qg3TXXfDGs6LtlATwHKSnM9NC0oucFeeB4PMJdzXvp/gTORwDT0NBQz4G4Uqn0Jb5m62StteICxENLsAzQIkgdGxuzJaoTExNK5s+npqZgFiqF1uSgGHWnf94NDRe4L71eyFnEJuwlLJafseCFAQQToEM8HtfFYlHncjkfaLHGzs/PS0CNBlrBCUJk8/m8Hhwc9KnsQKv3tIloWmVHK90GGJgsAKbd+Jq5doyMjKh3v/vdfUfiBwYGDhw+fPjfyc8ckxph37mvnW06UHKOQgdWdIo7WQDt1Zy4cHmO3q7wwog0p10riArdrdW1PIb00/l52MQrOrd0OxYSicTEbiQhrtx///0PGOvR5tBrtVrA8oSoWgNaZns+n9cMwpFCit8T4z43N0ddUcZ0Dyg2/f3dxnc+8yod6BwqPds2mcGzE2sgxeBCZAVYwMJkuS2b0rkpt0wmY2d+FhJIXvh4PI54PG754Q16DgD07bffXrv77rt/pd9I/MjIyFXj4+P/y27bhKXizGvrb7u5Xyd4FPhPCQu8hcUKwgJxPV3cBRI5Hq625nXPqb+w7IF0beR329vbHUE8CTLxPA/JZPKqXse/tbV14rd+67dONRoNlUgkpAsZEFnIAiCAiDPjCqTWJLEqYONazGxBKaVEj/RdJ8LznUBlDt0GBST4nsL2TUAwn1g07LFTU1M6Go1qBzXXGrDnWTMHsO1ndblc1uVyWWcyGXsza7WartfrmjcfZnWPxWIwwTmJnsNv/MZvnHr00Uff0u9FJ5PJ4oEDB66SKTH3oQt7YOX2XMmkvy6v2Y2uy5wx0Fu9dZif757rQkuYdeF+5rLJSF/cpWp2j+MG3fi5m+UQ32F4eDi1Z8+el/Z6DeVy+R6gFfyt1+tKBuIqlYpt3LC6uqrctBrQTiHL9uLDw8OaVZ5TU1OYnZ1Vx44d08eOHdNMX2utNX30s63o592E61bGKs8l+6pTmGMnJzwATE5O2tcbGxtK1K4DpqSVDerc+nWWtYrrJIsszGs5C9rzaK3V4uLi27PZ7Nv7vO71xx9//KPNZrMmHx43qAagI7UGBFJnHZ+HFMLosElFtEmW9FEdE4WM5j8fKTaa6F3GYVdiz/M6gomSRcaNlEsMgfxM0ki5aTa+lkQT+/fv77nXGgDce++9U29605ueaDQa1oJkYIzwV8Pprmm6m4BcgDbMPNd6cnLSB2xwWgOtRRBoLYySXYa5c6P83UFRvV5ML+IAaQL+uqxV5+air7oyQTp7QVNTU9ZnJ/3U0tJSIEhnL8IEa8gNb4JztqxVVLpZ850wRUJleby1tTXkcrk/bTab9/Zz7Uqp6Pj4+BtHRkYCfp2TzrFKLlfuMN435xhdce+OSRow/wGQnEEqUNeg13MtbnorbBy7+eRUWLkPLZuwVJmsNQ9jmhFZjkATjlQqdW2v17S1tXXixhtvPGne2hw2C1ognq1sNgullCacm6a7byofTR263tjYUDJWVWzRSOlcLqdnZmYY5Kb1bFf13aSvTi1nE4lDN//V9PS0On78uETwKGHOawDKsGVowAJqNOvWp6am9NzcHFvI8sfUppc0gQYql8tBtLjRhBum0+mOm6C1hlndNZUehqEGgI7FYnjnO9/5h+9///sn+yGsiEQiqbGxsV9+7LHH7vR9X8sV1GtBUl3f00aP+QBvb2+roaEhW+VmHj4lVm7lhfijQHhxC4VjCNnnovLXKSzCcT+XCuukHTvMerNL1/RimHuVzWav8jyv5yDcysrK7Ux/JRIJzd7oLE81RVh2exKqCJ44wDzHpHomISTQ6aejFQujj85JxFqx57Ue/WyiBU0zzQvV5oOX5ax2n+npaWt+y5JW+ils6UQfRgJI8vm8Nv2mfZiVXeLhGYk3hABa8M7ZX4DgGvM5DEy270j88PDwxPj4+L8LSXuF9cUK9bc3NzdlFBpAsIVQt3PTnHUfYGLdwyaHsBX2fEuYe9DtOgh15YoeiUQCuXIez/M6mWXMcd1DWgugW4Wb/F2SyWTPqzkAPPDAAw8CQKPRQL1eV2yuqLVW1WrVxotkWq1UKkE2bSBOxJX5+fkAIk7SPJtzBNqk7eanPyeKTqXiSsrVnCu7DNDJ1Zw59rm5OR2PxzXNdwB6YWHBLxQKKBQKWmLijV+D0dFR7fu+cnPsnPVkjl1E4q1ia62VuKlaKaXf+ta3nvzyl7/8xn4j8fF4/JpLLrnkGr6XD2PYj8HVO+xY7kMchuCS37tpPVOi2hGsk6v/c6Xsrnm+m9vgKuzg4KAeHBzUGxsb3SCtgUg795fHkK6K83loC6psNntVPym1ZrN5z5ve9KYngJZLmEgkdK1WU7VazabWZBum1dVVsEBLFBppAsOAFkcDV3PGqIgidUFnophM76bkwHMQjAOCATmKJJQMA98bxZefKwBqcnJSzc/PaxmYW1tb8wYGBjSDcwBYEGDNtWw2q4BWpFM2g9Atfngkk0n7mQHVBMwfNogYGRlRJ06ceN3ExMQH+r0Py8vLn6hWq4tueo0/ShhtM81Rl1mmG+GjG4mXx5PmunEbAoE6KXL7bma+K2fbvteJg/ufxVTvUE73OzkRygCcDODJcclA3PDwcGpsbOymfhT905/+9L+56aabThJ1yeyOxLh7XSieAWBlZcUnzNvliQOA+fl5v1gsQjRtUADsIkm4ubmGXVf05zQYI8wKCbYPFL+4vPDFYtE+hSJviKmpKbh93AAo+jWGJlcBQC6Xs+SSpVLJA9olguSHBxAobRUQWXsc47MrAHjiiSfenslk3tHn9a8//vjjH11fX6/KSDkDP1RS4csHUm48jqv0Yakhqey7KalbKx8W8XZFbiPPBXQoe4eFIVbesBSX9lsFSxxbR8Ud2nGMgHLyfZeGDB1Kz32kb++JApZDhw69tp+UWrPZvCefz/+eeRugPON/AUmFZ8gmgJb16Tbp2N7eVtFo1AdaPnqxWPRN0Vcg+Cw53Rlpv9CAmQ6h+e4qOYVKLv9mZ2f9YrHos3a9WCzqYrGoTR83G4V3aXaEn6M8z9MMzmWzWZ3NZnWlUtGMxKdSKU1mGrN6EyILAZVFs9mE8dsxPj5+25kzZ76EPoSR+IGBgagbOHL/m4cxEH2WQtPXVewwxQS6M65wf1dh3GN1CdxZpXVNcSOBfcLOwc9J1SwVm59x/NKlkGZ52PHccXZjngn7HfrNmwPA5z73udsajQb7DNh+a9Jsr1QqFpYMwJrtkUhELy8vY2lpiSk1O7FzNZ+dnaUraa1UlnwDHY0bzmp9PeeMA3IQYW1dZUicPsj09DRkaSuFAToSVUA8WEtLS5oQWaDVjhlo5SuVUppdLA0mvsOn4Q+GVhEBZBCElzI9Pf1W3/dPog+JRCKpiYmJG+VqLQNyzkMrzylzzPbDbl1HZGDKoUcKrIQy2GX6pHeNSof48PZ7x10I9fFdheJrrqI7OzsBHH63VbrbpCTTibu1WnLHJN24wcHB4UOHDt0Udg+6SbPZvOfNb37zSfrl/Fwi4qrVauDe8TVTavl8nrBuLC4uYnFxkc+09dGZbi4KshagTe4i5KyW+QWhFqFSTU9P+7LDi8wFEgcvo/HMHZrD2P/EABcKBSwuLto8tCxpzefzbHejSqUSVldXkclkiItHtVolco5kFfYcUumZcms2m/ojH/lI7Z577vmVfiPxQ0NDE2NjY9d3W30p0nfu5k8Cu67Wronc4deSDZays7PjtjeSYwhTFOX872pVALBdVdhhxc2Ph5BJBM4lJ8hun8nJzzHftdinA+rq+z5yudzP95NOA9qrub3IloJroIXGTKfTOp1OI5PJaGOyg7XnLEuVZrsJMAMA6aM00KZeA1omO5s2wDC/Tk9PM1vw/K/oFOJxmdyXNFRmwDbXbrDxdlWXMFlDq6MnJyeRTCZ9U+0GtHLryOfzCmjh4VnDTIJJssmyWwYpeJPJpK1h56REc16WuzabTf3bv/3bp775zW/2DZONxWLXHDx48FqegxVSctV1kV2uUrnifu6yolJp5GrvEjdIxTeR4I62R/JYIWMIHZdRagC91cI7paUd5+bKzmuR19RtDG76zfPaJcK+QcDFYrFrOnbeRbiaA+2UGtAO4vKZErBX+/yOjo4yfw7fgGQMtXPgHMZy1WzDNDs7G1BkWsHSfD+bXEiyMO0GKIBWtDBswKxwm5yc1KVSSRWLRbCXW6PRUKZNDQBY+tulpSXfa2Ph7c0FgoQVJNBn6q1Wq3FG1kArekqfHWgH6ri6F4vFB1ZWVv6g3xsQj8eLBw4cuIYPhQwMhYm7uoWZsWGTg+s/d1MgoE03JVdefmdM+8B4XPOZ4+fkIBVcHifsuqTyusd3Amiq22TB77pxtctYxs7Ojs2X79mzJ5VKpa4PPWgX2dnZOfW5z33uNr5n+XO9XreTt6B1Di1J5ZjEhKyBFiOyKdPG3NwcpqamVDwe16xBlzl0UraZ9FpPyv6cRt3DhDeaUfeOATl914F2EQxbMgMtGqp4PK4ZVTe4YBvQGhsbk9xpamVlBblczs6+q6uripF46bMB7cAKU248JokFSDpZrVbfk0wmf6vfe1CpVD5XKpW+ISKyAVNObit7s5ltA33X3X08A6mljy197TA5W5SeMjg4qNkOiftReWgVuAruipvmovB38rrUkbuxBio3X+/m5oSZ7MPDw6lDhw7d1K/JvrS09HuHDh26FyaOA7F4MWXL97L1EnHtZEmCcENZis0gXDQatSCZXC6nS6WSkvh20Z3FRvd7ibpfcEWX5zWNH1yzpANB5wIFqOxMvzH15rZkBlo/tIEZWqU1EXkFoCPHLsah6vW6Mj8o/aCAmdZoNNQzzzzzuWg0+nP93oBqtfrZp59++pvEvlO64d5lKo7+Zy/7cd+w4/kCeiuV7WyTgytO4C5wfCPKVWIpYW2LxeuAAsvV27UwuK+7Hbdl8O3w4cO/GYlEeiZ9BFqY9kwm8/NAq4NvPB63lmm9XtduI0XZA13ey8HBQX9paQljY2OsVmMAzvY7oNV65MgRH4B1Y2dmZrSL5+51Rb/gPL9GoQC0fAzS4ADtqLxb1kp+eKB10bOzs+wVDYhABMtaJyYmLGpueXnZRuNHR0e7mvCMxIsfD0C7t5t7LkM8iVtvvfUN/QbnACCVSt2wf/9+W/NMc2634Jb8Lsw/d77rSJu5Dz4/475URte0dlfTswQVA742tw9TcrfM1L3WMLekW1mq+x3vFf84iV9yySW/0q+Sa61r99577xtEutU2DGGk3dA6a621ymQyKJfLAFpwV5rsMsNANJxBeyIajer19XVrrjN/Tu6GENO9ZyUHngdFF4OjYtl8u6yzlfuYlV3LAJ1JOVhfRrLTGN4twAToKBKkIAN85XIZmUxGV6tVlhUimUzaSKpMoZhx20YRH/7wh6uf+tSnXqu1rqFPSaVSN+RyuZcKBepQxG7mKxBQRITsF9if4prGYiXv5ucGgmDCLw8Eu+SEIdFo7nl4bDcFFhZbcK9Vbi+PISaqQLCOx6CSj42N3RCNRnvmgaM8/fTTt918882n0DbZWcCiarWaDcKxi5B5xvTq6ip7EkDmzoFWAYvMnbOIa3Z2VvHZnpmZUa41SxGIuJ6s8ueFuZ/KLlIDSsxS0j+XucPAMRiJpJljsPFU9o6VHWhH4j3P06VSCZFIxHdNVNkMD2i31iGwhpVuBjaLRqOBG2+88dQ//MM/3OD3iYk355PKDqC9UoXlg8PMVfGdjEjDVTzh23bUZXfLPYet3mGFM2HBMjfd5SqgM267+roruUv26E4Ocqzu70lFOHTo0Gv37t3bM2sMpdls3nPZZZfdbjIvgHkmafEBAfoyAO1Iey6Xgy9y54YbDkCLHg1ooeA41Gg0qovFIuHX9lwirWaZls33Pbvez5ePbkUEEqzSC7KKDp/diOLKPjMzwxREwFcHWpHMiYkJyxO/ubnpseG8CdCpbDarGNBYXV1VAJRpn6MAIJlMWmy87/seFZzjkNfw8MMP3zg2Nvbn53IfGo3G7A9+8IN/ALri1wNkE7I222wX6BxKMzwsmBd2fulTu+i5sOCe45cHFF/2RHNF7s9zhE1cYcU7YqKyxwoLvEkZGBiIHjx48D8MDQ1NhI1nN/F9/+Tdd999w+tf/3oLkjILi04kEjAlqQGXj4E38hmyFDWfz2NoaMjf3t5WS0tLulAo6IWFBRQKBSwsLPiArTvnqazJboLRdkKQBm+v5vt5rUc/FxGru3nbbu9kPgDQYqWBAfRz1Z6dnfWKxSIajYYtaxVN4+1BDOkeYEx53/dt9FgpRagsAMsTL1d2TWVPJBL8gZWoY+ePjyuvvPKexcXFw/1i4s0xikop/dRTT33FPKyB0tJuYBqhuAqA9fE9zwukqSDKNeWxwqC0rrKICSOgpPzOTCx2X55DTjTS7Hevwb0XIWMJYNTl5CDMdU5w1icfGRlJXnLJJb/ueV7P/c0pWuva3XfffcOb3/zmk7FYTJkAnP3NqeQEyDDKnslkVLlcJgRbGSVn81AuZgBa/rlspAi0XVIYnobJyUm7opsilnZdajtAfPEAZnoRqeAGRMMJQEvzhakGg4kHy1plmSlaqQuLnGMrWiC4qrH4BWgF5yqVil+pVAI9sxhwkc3tARAmSxcCWms1MTHxvnK5fBvOQWKx2LVjY2PXu2YwzW2+l6uhaxqH+blhx3FWRWsKh6DQFABsbm7aTjrSHRDnDozBBbiIY0p/v1vwrGM1D7M45HgozJWPjIwcuOSSS37zXJQcAB577LG3vP71rz8FtKPsAHQikdCM39RqNcsLBwFZ5jHonwPBmnOu5gTKsIkJxZj99tkC2tbs9PR0i1XULIzoQcmBi0jRRQEMZGCOZjvtFXHB7O0WuCG8YVNTU3p4eFgb08j2YKe/zoAJSwYZRMlms8hms34mk/Fh/C8DlyWCTieTSZ/7SGBNs9nUjUYDz0bZ9+zZ87MTExM3R6PRlOtLhymIFOnnhyk0kXMuqsz15+U5wszsELM9sI+wKjr87jAFN+cJjFt83+HjhwFipIyOjl6Tz+f7zpNTyuXybVNTU18yACnrqhkknNxUV6tVnUqlkMlkNFles9ksTAxIA5BdWGzenHGk+fl5rK+vK7eZieRUZJrZoEi1cG17jro/7z66FDeCKDDx7OcmU3ByNlME07i5dcCy01hZWFjgBKdGR0cDQShJMsnxCJJJJJNJZXLsdpgASE0lHwp1+vTpd5yLGW/GU33qqaf+b5a4yu9kDlyaw+a70Hpzfif3l367BKBIHzzMZQg7RphZ7kby5XF2+a5jEuDnrsviugMDAwPR/fv3X99vJZqUcrl82/j4+G3NZlMWNnWkWGXenP89U4qay+XgeZ5eWVkJMBYLllfbV21ychK5XM43z63teSAr1SD8cgLK+kmtAReZolOkwsvSVqfI3kKCjP8uFR0Qdey1Ws0DYE2lsbExTwaMSFoxOjoK3/dVqVRCJpOxT3i5XFapVEoBLVoq0zSP5poiJr5er3sudPb06dP/5VyVHQCazeZXVlZWvhKm0OK1+94N5EG8D/2um7iTg3OsgNK6/ru7nzuRyO26+ezdJgPX0kgkEpfmcrkbznUVB9pKDgRrHtB2z1Sj0fCTySRILmH8c2SzWZ/KzvGZ4iosLy/bG1coFPTw8LB2GV4lnl0Ue0H45gSY+WgHrHtW9uc9GLebUJf5niaLUkpJEx4tE0gxN14sFlWj0cDc3Bz7uxGcoBYWFsACfzO7KvNjaNOpVQNQxClnMhmVTqftLJpKpVS1WiVDDYBWU8d4PC6pqOzqvm/fvvedPn0a56rssVjs2kgkkl5dXf3K+vp6xY3I+wLoIlFuDJ5x5TefA+2S0kB0vNvkIBTP7YcG97VUPGm2u8cKU/IeP5PuCK8teskll1y7d+/en+3xloZKpVJ53/j4+J8y6EYxkzjq9To8wxbDvLmEuvomwGsWCkbc2SEVpnkojJIrruhC6IZaa1UoukWRTk9PeyFlqmeVi8ZHl+IWvnAll/76tGky5+47PT2tZ2dnNds9AS1/fXJyEvTZ+XCTnYYPuSDV17lcTmezWZTLZV2pVLTneT4rkthPy6zi2k2xAEAsFlO6xUP3rHx2ANizZ89VBw8evMkF10jf3VVQN0glV1W5TYiv7QbG7Lbu/vLYziSgnGN2jSu4wTr3GPK9G3Tbv3//VRMTE297tkpeLpdvy2Qyf2radMnzSvOcwTcNtAlHM5kMstkssRmhbZBNKaq1KEU7ZPAZBYJdh11Mu3ndV8WalItS0aUwSEegAK/bRc8BrQAGfXiaQryRBjlnGziK0kBtsMc6EonofD6vWfxC6h+SVsAEXyqVimJEHgBqtZoCgHq9zgYRVHwfaJnw+/bte1bK7nleKpVK3WDQXakQ5eqqWBIttsuKbd93CbB1QGMds7rDOjCv5fjs/t3gr+7nHLecqBKJxKUTExM3JZPJX1FKRfu7k0Epl8u37du3732MqjebTR/GJydICmj1BgACbqUul8sol8u23tztvkJSCV4PFZxm+9zcnG1YYnAhygSY7XHcdLMZQ9fGpt3kovTRXZHmCi/SAQ3QtLE3bWZmRgGBvCRmZ2flU67MLKsmJiYCKDSSIfi+rwyQhvlRwABqWARD96JWqymTclEyMGdQe/akjz322G+Pjo6+59ncD9/3q/V6/SulUukb3QJx0mTvJu72boAtTFwwTJi/7YwVCCHAMN91gHBkIE9OZlTwdDp97bmAX8JkZWXlDwqFwseAgE8eoBPzPM+XlWniui2qUgbgRHWfXlpaYloXIyMjPtDuvmI6CZM9JgDJBhAgYZmenva14F88l2u96BWdF+gqtlR43gEG5YB2xY8M0E1NTSnTDMJG4yV6jhVvW1tbXiQS0UTP8bTmD7LizfjrBNSoer1uYbMMzrm92b/yla+85FWvetWdnucdfjb3hgp/+vTpb8jP3RVVROi7NnFwA1zdAn99jq/DYjCfh/r63b4/3wquta5961vfesMrX/nKB4G2ae5u12g0rFtWrVbBwBsAW53mKjkbMpDdtVAokPARwi/XwmTH7OxsINpO8x2ATadR+o222/3OZacLKQ5EVn4eUHRZzirSE9ycMFkQSTc3N6cmJydDlZ1tbEdHR9XKyooiJRUppLnSK6V0uVz2gBaSjmZdrVYLMMwCtn4ejUYDsVhM3XHHHYeOHTv22Wer7ACwtbX1eLVa/Yqhlg6NlIdFzftR4N1grWHHlxKWDuum4Px+YGAgmkqlju7Zs+ffnC8FB1rlpvfee+8bXv/615+Kx+O2ltus5LYqjV1XAGjhl7OHGrLZrGV1RQuPESiaAoBoNOovLCwoRtrNZ4zga6Ct5BQ3pSYXNZFm7lvZL3pFp1BpwtJtaKUbtAzOTU9PK4kVdlNvzLPPz88zGq8AhCk6RNpN5XI5vbOz45XLZaTTaVWpVCBSb4q+HP12wFJHe3yggFY09y/+4i8O/+qv/uofRaPR15yPe7S5ubl45syZb4SZ9GHbi6aMXU39MKXc7bOw73pRcE4EIyMjB2Kx2BUjIyM/+2z9b1cajcbtf/RHf3TbbbfdVo/FYnB+Dy3cLY0W9BlAexWtVqu+rDOXLcAYgPO8di+9xcVFTE5O+hsbG4optampKc1S1KKgiZru7DqsJV8Dsz69kEyEyQ+NogOdyk6fhea9uTE2YilX+KLp1gp0ElYIdhqu7MqYXkoUwCCXyynz46psNmtXdo6NP0K1WlU0441IUI0WXV0Rj8exuLj4rHLtrtCkX1tbe3x9fb1KJeuWE+/2mUzL7QLCCcuTd/j8YWk27jM0NBRNp9MvjUajV5zP1Zuita6dOnXqlvHxcdveWCiMrX7k9jKDIv+Ta5CHBVowV1OdZnPmsgSVfIaA7SOoHZooe17CvEUe3bIwPRslB37IFB0I99kp5InnHTE3zaLmTDdKdezYMV0qlRTLAaUZL2ucgXZwjqWGDh0V0um0Z/ji2W8rUPEmUHSBe01lZ8HEv/7rv77ipS996QfOhykvZWNj47vPPPPMd2q12ne2t7fXezXXnRw7sAvQRvriu7kLZlsFANFoNBWPx6/Ys2fP0cHBwUvP+QLPIuvr6w9+6lOf+r2bb775lKMsWgTeVKPR8DkRC79cA61CJ7LGmIIVbQAxPI0eGxuTK7m9x8ai1IRmS5Od24hKTOmb22sQHVnOScmBH4L0mitMt8n3NOHN7KcdKqqOGzszM6M4ixNjPD8/j+Hh4QB1NNDKhTLtls/ntYlUB2b8TCajK5UKlFKaOXYAVHKdSCQs4aRo22xZZgHg6quvvv++++577dra2j3n834NDw8fTaVSN4yPj//+4cOHb9q3b9/P7dmz5xJg9zr0ELaWAPuqkyIL1IuHHXtgYCCaTqdfms/nr5+YJSPtrwAAHq5JREFUmHjbwYMH35ZIJK5/rpRca11bWVn5g1wu91oWpzQaDduQAy1Eo02HAq3fMpFIoFarWXBUJpMhcAqyvznQwl2Y56KjEQMJS6PRaEDJRXRdBo715OSkJj7ETR27z/y5yA/dii4k4I9LX8atX2egzgTnbGCOJlSj0VAuLn57e1sROSfPRWw8AOu3ZzIZu8obXLym3y4CdABsGyjP+IFuNw4ArRRcLpf7L57nJfAcidZ6fWtr6webm5uPb2xsPLW1tVVdW1v7QRcYq4zGu+g7ux232bt3byoajR6IRCLp4eHhAwMDA5f209Ps2Uqz2bznT/7kT/7gz/7sz1qmlFjJqdgMjIqgG8tOkUwm4Xmeb4KtygTgZODNat3g4KDPGAPrzIEgoQTQrjWXpjoQMNfttkwTy95qeBarOfDDr+gaBvdLcdllhdJLYIJNu01NTdl7QGUX9D02x25mbAWDiQesogPGZyezrDTlXUWHwcZTZINHmpJaa/WRj3zk0A033PCOkZGRG8/XDetFdnZ2qjs7O1UAz5jX6wCwvb1dkdsNDAykzf9hpdQez/NSnuelL6RCu7K+vv7g/Pz8bddee+39MuPBVZz5cbmKAy0WIVpWpp2SJi2UoRkLED0aNlcFY7KzSaLTIDEQeKMUTdNEvpfl18If59cWAn6uvvkLTZT8MzeH/z0AntZamVreyLFjxyIABqampgaLxeLA1NTUIIBBAEPm9RCA4UKhMDwxMREFEDX/9wDYm8/n9wIY4V8ul4sBiGWz2Xgmk0mk0+kkgCSAVKrFYJFOJpNpAJlEIpEBkAGQicfj+wDsi8fjWfcPQC4ej2efeOKJ39vZ2XlC/1i6yvb29slTp079biwWy/EPQI730NzPbDwe38c/AJlkMsnfJS1+qxSAZCaTSWQymQSAOIB4LpeLjY6OjgAYyefze8fGxvaMjY3tMc/EHgBRAMOTk5NDU1NTg/wrFosD8g9ABEDEPIue/K/NM6rbC0TAmnw28kPno4eJFgQV2oEHCq4tC13k/7m5OR8AZMdKA6gB0GZWMUUJTL9pALaRPYNzJK8wwAk/k8nodDptj8tqJ6BlIiYSiQ4UFsxqI3K6anJy8p677777hmcDn32hiu/79aeeeuqWgYGBq6+44op7gfbqzVpy3k/AttsKtFACgiWnmUzGZ66cPjlXYNNlxSV51Gx5DFjkGwDIMteAuNVpYYE3Y4met1X8BaHoFB2sZ5e9o21aZNr0eDt27JhMuWnJ8kGqqpGREZ+Y+ImJCYt28jyPPGB6cHDQZzGDa17xvaGl0oRRcpySXZbEk3w45Oubb7751L59+267++67rz7fwbofRvF9/+TJkyffkkwmCy9+8YtvByDvvWo2m3wv/2C43nS9XrddT2u1mmY1GoXmejabtb+hiU1oz+kEJEQXCgXbaQVopXH5l8vl9OzsrJaVZ2EmO59ZGXM6H/LD7KOHitaduXbdBtgEylsJmSUunv66DMwNDw/rtbU1zxTCBHDxso5ddoIheQUApNNpD2iRV6TTaU2zzKzwSCQSNmgnc+wSL89rajabAIC77rrrefHfn2+hD14sFh/gZ6biDEAQr07hZMnv6vU6J1+CYADjkzOFBsCm0diV1/zGMsBmX7NB4vDwsG3CMDc3h6JhdD1y5IhPlKaj6AEt1kFQDPDjFb1TpIITPGM+dymk7Uw6MzOjTcVbwISPRqM6Go3aNrYsSABg028DAwPa0Pf6TL+VSiXttXqz2zRKpVLxmXYz4+MKQh46Xa/XNVM7FGnWcx8+0DfffPOpWCz2lnvvvXfqhb7C+75fbzQat3/5y1/++T179rz26quvppJb/5WNFYSCBzgEef+MyY5UKmX5++XvwqAbf0PP8yzijQ076bpNTExgYmKCLK46TMmB1kRjnrEA1BVo8yICgZXbKrljoT4recGt6Gizb3SrdFPSNxIkAEr2dWPxCztoSPQcTDQeaJMmmh5kenl5WRFBl8vlLLAmrPotrCAGrRScNkyzgWg8OeWp8EDrIb/nnnsOXXfddb8dj8evO9+Am+dL1tfXH1xcXPzYnXfe+cCHPvQhQgwDKxxXc0EWEUCRMX0mP/M8z+cqLo8pilQAk0ITDDHI5/M2tSgpoXiMyclJyMaf5jtdLBYJ1ArQQ+mgZgNop4m5sp+fO2nOcT4PdpFIBy+8DM5pkWc/fvy4vvXWW203DGlyU9l5TAbozLaabDUhxTDWlAdafd7MsT0DuiBvPGDuvyyIkf9l6o3DRzubAPKaaa0VzfpHHnnk+rGxsRv37t3bV6fQi0HW19cfrFQqX/rgBz94z4c+9KE6rykWi2kY31tuz4Al2nlxC0ISdMwQ1E9IpVLWn5eNEHlMo+g+0A64AmBrL8tOBHRWpPFzruZsklgsFn036BZmtks534r+gjHdhdhZ1jWL+J83WfrsMzMz1twWva8YpJM3XVPpAQTYZdnjDWj5dBJYARPIyWQyoYEiibSr1+uaDy23IcCG26gWA63s6gEAuPzyy780MjLyhltuuaVw8uTJt5w5c+ZL53wnn2Pxfb9er9fvXVxcfOu73vWuy3K53Gvz+fzH3vve99abzaaOxWJWyYFWJJ1/DrV3h5ILNyhwv6UZbxTc0kOZFkoBJV9eXtZkillaWrKwYCq5HAPPweAbB8AaDC4oBv1GtmPpcj5nufIX4oou/XWttVYCNCMtJouNFwE6VSwW1ezsrDb/bWMI0Ytd0Rer1Woeu204fcAC93Vra8sjsMZ8pACEVb8hmUzafd0KOAASmy07xtimj1wFgXaKCQBmZ2df/uIXv/i6aDT68sHBwZf0cz/Pl/i+X3/mmWcerNfrDywvL5+4+uqrH2TP+WazqWKxGP8DYgJkTYBUBDc1yRSaabBhA26yjtzBrAOANkAnjZa5blNoPA/NdZJILC4uasn3ZgpVLPKNgBi3tpzPWCDSpm3XEl5H36SPvcoLcUW3K565p9qUAGqgpdwM2BlqqsCqK1Z1DcBnUIfpN/rsc3Nzanh4WE9OTuqFhQXrty0tLWmm38jn7XkeYZOWmD+bzbK9rszn2pQP0Mq3A2CHGEtayDJKQUEMtJQFMIEolmECLRP/6quvfiCfz9+SyWR+/l3vetdlc3NzNzz55JN/uLa29rdbW1snzvdvsLOzc+rMmTNfajQat588efKtd95559WRSOSyAwcOvCGfz3+sWCw+CCd6jXb8wV6XnLSZExc4Ay2sG4twM+WlNrVJrj8ZcMvlcrZ1kmyEyP2Wl5c1S04JbXWKVQCDu4BZxWXZqeRDkIuJiRlprVtl1cLFfM6UHHiBrughogDo6elpz4UZTgdbNVuYrOjBTtORKTh7UFa9zc/PK6ZYFhYW1NjYmBoYGNCm15seHR31WNcOADs7Ox7QxobTbzeQS485XRl11aYKjj2/EFzlO35H6ce7K728JyRDbDab+OQnP3no8ssvPxSPx5PxePzQ4OBgMhqNjsmdpLXieZ7e3Nw8tbGxUd/a2qqXSqWTJ06cOPXGN77xJFpKK1dojiU0oGZeB8YDM2kJOi5bcSZNdLOCs8ZAm/RlINNh7rNdwWX7bEkBtby8DMJagXajTtFVxTfBWVuscuTIEd9AqrVDeOLWmAOwoBi7uDtxpB8r+rkIV3U3VeHc4FCOeAZT+J917DCrz+TkpCKmmdzxQLvyi3Xtvu8rs7pb7niODQBMc0cAbZoqButoyjMyL6+Lr0VaqQNHT5GNJQDY8ljux2tCS/mpaFZJeb61tTVt9geMFWFeU0Hl/u557HvhVigY31mW7Uq2F45fWmlAoKNpwEw3GY2AtQS0GiCaCdxG1cW167GxMWuZFQoFbQqbuMor2SuNEXYZeKOCu3RQQNBtFM8eI/DPOZ79BWm6S+l284TFrqdb7W4CE4E04fkDGiI/u6Np6KjX19fV8PCwXlhYsGY8jz0wMMB8LPL5vF5ZWYFE0q2uriKbzepsNmt9x0qlok2zRy1M+UAgidVVJv9O09U3CDu78omyWADtgBaMQjumslVAN4XHc8l71Gw2FVrRcPuZ3N+4D75obaTlOcwxfXlcZZhzzfb2TwYrxViskgOwvrjhX7clxZ7n6XK57Js4iR4dHbUrOISSE9YKwP6OptwUAGyu3Ci5Pb8010M431oHFHgOERy2ZCXPpZIDPwKKTjE3E0opLf10kc7ShMcaII0mVJaSy+Usa2exWCTBn56fn3fJ+K2wD7aEzQKtqDyJ/ldXV/Xq6ipMVB6ZTMbWuafTafsn/XfWTLPEkg+K8OXpx9uINHHe4n50+PUhJr41/bmtnCjgRJxh0mCEocqsAM/PP+lzcwxAm9bJbBPg0JcKkUqlNFdy1WKAgawfX11dBe9tLpeDNNeBFiWzGD8A6MXFRT0xMaFM7MV+NzU1RQXH3NycPnbsmKZPTnOdvOyyzFTGgBw8hyxBfc7lBW+6d5HAdUuILBAIntjt+GNKSioKy11FmStgTD0AgYg8+ehIUQUAZJolwAYI+sLEXpfLZQVAMe/OHLG5BgW0zFm2dk4kEgHgiHltSSpl80BJXBl2w5izl9F9d9Xn59LsFq6ETZOZc8qOKIoBRsYgJEqQyi1plyWyTUTUARPoNPlw5rJh2hjrsNy45MpjVJ3v6Yuvr68rSezI2nKi3gi8khBrNx7kALme0xXclR+ZFV0Kc5j8E/BY9+bb/CtX99nZWT07O6tNkQKAlkkfj8e1aRKBqakpi38GEHiQWBAhA0D5fN4fHR21TfpWV1dpbmqp5DTnlVId5jyhtEALz51IJKyJL4tnaD7zv4xgx+NxNJtNn6sx/zNnz3tCs1l878fjcZrgvjmPvH+B+2nMc2ttoKXgGoBlXpXXBbTqxA3wxcUhALCTgS+UXAMg9zox64GIOn+bxcVFLC4uWlOdTRZkwI2rOVliXCUPo4ESVqN9L/HsuIDyI6nowny1aTbAruySOB/Hjh1TovjF+mIUKrvgjtdzc3MWVMFo7eLiIqLRqL+0tKSBVncY0lQBsAUTNC+VUjqXy9l0EJv4iQCTBlqdY0zjR+K4LQCEY6SyuL6g00AQwq8PnEP4/VpMCvY1TF4faCPU+FqcB0J5uWIHPmdaTCLZYOIUxnXx5QpuKLz8TCZjFdedBARxowZaLhRXcZaXGsx6YJInSGpubk4byjENk0aTIkEwbrkpxEREXDvdxQut7D+Sig4EFcH1lehXHT9+PGDGGaUP9K6m0Hc3OXe9sLDAfck6YpXHFETosbExLC8vc1VHJBLRpVLJl4g6QWEUGLuMKJOnrlar0aS1Ck2fHgALaFgS65PLjr5wIpGwAT53EpBBPaHMxJJ3KLX0sfl5vV4HoansWcexuopNqGoqlbKFJ0QV8j+Vu1wu+wS9lEolMC+OVpDNJ07dpM00V3HzXwOtyjP65EQ+mtVcNRoNVSwWUSwWrblunoeOwJuJ9dD/toE3l+BRZg8uhPzIKroRu5JL8ALQiUUGYAN1gG1Ur4E2yMahDbLVTNFoVE9OTmo2eeTDZVb3Dt71lZUVWwk3Ojrqr66ukr9Ml8tl+4BLU57nZOCOASrWwpvovCIIh76ujGBTEQEL0gHQmaYzx5JloVa5OXkkk0nfrNI6mUz65r8kfLBVfM5/mPHrarWqnTECaMUseA947wlI4iRpKgrB+yuBL0BrFScV8+Lios9e5fy9aLEUi0V95MgRn/XkfDb4HEizncos3UJajVIuRJTdlR/VYJwUm0OeNjzaEjJLnLJ5b3eS9exSTG27Yi0y0ILPMqADhBNQ0oxkNRxFtoUSBTLkqAOJKSkyJ0u/npVyxuxVkmSBQb1EIqG4sppKOs3PRKCPATUtqKw7PuP53Xsju5FSRL951oTD+e/6+BCwVQBwawqsGyT53PidAL/oQqGgRK/yQE2DYB0CAO0g3br65dMOJzvvw4VewV35saIbEQ+oXeFFySCAdnEC0DLjnWBMR2Rekk9S2em/FwoF68fDwcATZCPZV0WE3hJcALbiTjkVWEoQKNjjGsXha6v01WqVqDIA4HtIlBnLadF2Qew+EqPvthbm8blihyiyVGgljm9LR3kvDObATiKlUsl2MF1ZWcHY2Ji/tLSkWDNOJWeKEy3lhnGr7G8vg26EtJKtlQjJXC7HQJ2S+PWw6Lp4pgKBN75+PhT+R910t7Kbzw6AlUbMi2rD3qmnp6fhKjnNSUbjiZWXfHQLCwtEWbHjpgbgmyqpwAO+vLwMAfBg/t0OTaaT+JlRcBiF18K/9QHYZoE0m9EK7Nn9mZ8WeXsN4xpwG8AytIAxgnQ67dPs5iTAzwAglUoppZSW6TCO0w000jyPRCI+AIyOjvpKKV0qlfTg4KBPABL38X1f0Q83RSh6cXGR5npAydlGm0rOoiXZ/BBoKTiVHLANGewDQn9cGbITt9yU90biFzo2uADyY0U3IoAzANo8XjTjiWgy7yU+vsOfn5mZkcg6ANYUpN+u0QLaAAAWFxd9GdShsg8NDfksf11eXiYRgh4dHYXneTZlpJSy5ZVC4a3/n81mJUIMmUyGYBxUKhVrNjOol0qlrH9Pn9koOFcnKi0DZYwZBO4DJxZZvGNQa1RenclkUKlUbPwhm83qXC6nuXJTMajsVH4WDAHQg4ODFgln7h+ANhsQxW10SNAToaxzc3OB1Jn5La0vzhXc5Mttzpz+uJQwhf+xXHyiYAgedJsmOvB/WtDzok3bG5GUvseOHbPU0oJWegCApQOenJwcmpycHAIwVCgUhguFwjBa1MGWZlpSC+fz+b2jo6MjpB7mfwja6VwuF8tms/FsNhsHEOdr+Vkmk0mY1wkApDZOwFAdp9PppKGtTgDga/vH7+UfPyfttaBMDryW44KhUuZrcz2xXC4XkxTLaNNs7zWf7QWwx7k/UQBR3kfeVwBDkoaZ99/8Vva34W9nfrPI9PS0Z157ZoKTv7l9RqYdiuYLnSPvRS66AT3f4lQUWf+KjSGEWR+4dyQWkHXIBgqpYII5ksFG+u+SqkoCbUg3zYo4ACS4CCDnJI2VS1QJAKLrp+JKybEYiitWdVngkBvkc0V0MKF7wM9hjms/c7MKvK/0ud1qMu4jK/5I6xR2vLCeZ6KaUDvEIZCNDmUxChAIwAb2kRae8xw85+ww50N+bLr//+1dvW4bTQyctQ0oQIpUggAhhRC4c6kX0Es4ryO/j17CL6BSXQoXgYEA6dzEQHD8CnF4s9Qqn5PY8Q92AEHy3VnSnY5LLjmcTRDCRdUhxrmYjaogcVxqRbTNZmPr9Zo8+QGow3nFdru13W5nFxcXyPxq3riuYFOFogzFGdIDAIUqgf08XoQOAeznm8xW+xpi5qE9hE2mZawIh7VBxHcPrl8fx3nNP+bX6fjgnet1Zv1bjxfWIMNyACOj7evXr3E9WKIERuNml5leS4JkIIbpVADmb0epMKAO11l+5X3gg0GQYOTx4owc6B79oVCKbMzlOar76wLn2mTlGl2+mf/vDRGFyiTAfhln9rgrWI4DqpIcAHB5Z8zn8+q3pKChZus1Qw0gloH2ls3Qt2NmWMt4urggsM8FTKfT8MyEemj3yqqbF5xzANX3EekmqOdmQpLvf8x7s0zm+gBYLpdGfrrwGwqTbceWLAbqNftkHh6ZdTat+DHat/JiDb179AdAfsiiRAhNwvDXTiu5AkCwp3zRCFxeXvLGM7KuJPMbRBtg3yBDOWFpgbXFYgE3clssFnZ7ezvQ4znbzoB9yMskHj0/jYrJvGEYymw2M4b4379/NzOLMJ+RAB/cxu9I1ZzpdBrkGzHOIP/o9vl8bqenp3Z6emofP34Mr83EIz03yS5A3TNwfn4OXzChMixvHQYwEl+AscXYF1SI6+NdZ1WXGcHuM6+JHSgKx03xgj05cfbcX+A1IJfebJT9iWNkAKDXNx35AahiKKmUhd6Gnobzdt6wFLfg6jH39/fFy0RY7JcDCoFK93LxmW5ULDkVbcucz+fGuT0Au729LXAKKRASS9VlcM+Pk5OTULmdzWYDX9OIVXuNq8/65xQy1lTJZT6fF3aS8XLyGnotHO/evRvYBeh5C5NSpV1cXBzw0+/u7igWEivzZKknzsnTbxmtzPydSYABqpVVYor30o29h+6/iV9lVEmyIbHmGKPOnwvJNqJeE5x5yk1L/b0oTfP+/r6wYUaxWCyKt8PaYjGuBMsQX4wJNH4Nl4Fg44WRMtTnaiWz2azoNj8mbnJ9r6yJrhChhyC2UC+fKi/5f5SPTpllsg4pBMJEG1ArvwAoDNcz6YVgEk6jNv6ukAFIiC8Vyeelohv6H4KjOPae+4Q3gg4E4hGahq/EC2BcyplQVh2AakEJHrPb7UCNeWBMSNH7EdSeB6I1M/Zzfu/hMtl5pgMBsF8b/tu3b4N74MgBaEZcPLXmNZAVXOC0X4lGdDuc6ILJZGLMUVDhRQdAv05xnrpgJisdFIcgNNxXVpvQVg9CdDf2Aa8U3dD/HJljXu1kGUbLMa1EHV+zFEe5YNWo84TdgfQ0v4MsLgF4iY4y1EBdpkuhPuAJvWT8OghUSTHXv7MWTVfDcY0cMnElee6qdz9DQ3Qm2Y4du91uK9UXABGe+7Vuls00RCc0VH/OrrPHQp+j/zn0x66MXjw9jyvYM9hw5a2M9PIEmVbX19fwkB6r1Yp93uHBKDv948ePMp1Oh7u7uyJ1eAhVMwwfiIUA7ezsLAYAD/MrjTuyym5ubsp8Pi9aXuMzjZgLG/z8+RM6PdAmElYIaNgAcH5+bhyIpN4d65jxODfqoksdqSBj7g1PjDZcXl6qkcPMBk2W8rdhIk7Ddf6+rc4zvEJ0j/4I0IYYYJSQpkdQiIcvZmafP38+UQkiR9FQU8QpVZE2PLyu2OJNM/zc+H0pSw3v2tIPU08PQL1t9TcwRgetfYwaqKCqMsnZoFkOYweZfh/NnOsAx3PVY6mnDhzMx7ORh+Hm0iiRyqUcBHT/qzRyoJfXHgXCyTYAtl6vrWXkQGX8VkrBZrMZeCOKsZv3vsf/UcZqs9nw5jZml4FxbrpcLilaCSfhxHtQ0XQymUS5zrcP79+/H9j8cXNzQ0GGWLiAD4o1iOeP8pcbcZy3eu0vX77Yhw8fBiCEOMDvstvtosnEzwEA4hzzuTJzTl567hWXxFlcz2ONStyu+/01o7Aqw/5a0UP3J4DM6SqijXqHlNUFsB8E1ut11OK1BATUXhkYPTyJONnbsTNLk1VAeP0qKcXynWb1gf0cWZN9HAA4BeB2X1q6SOhtADCZTMDvrs8ejhcpicX2dB42nU4PRDn9vA0S/bgKK4BanBFARVsV0ouJ9wZEmyANAq/ayIHu0Z8KerNXfHkSL4AxRGTSrpQSyTogOqfUGMNAlTfPz3LhSgB7r6ie0HXPGAbbcrmMNk121GnITJIOvS48yuDgIGUuk8x4/D/r2toOyn1CCAoVF+kkC4KLJtVIdEmLF8a1Vi/OfEf20uQ6OI15yF7e91We/K2gz9H/AXLtXeqvrYaIimLJQaBFz6TCTe6RzlRbIDxgke3GWr2+5tcAYjUaXfc7PLBIWxvLfk7+KancVbH+WONW3oDOsxWqmf6QpY7k+liKmKo6+LGe8eYbvhH00P0foBEaAiPpIo5r9cK3SDiZWquvd7sdQ1kDoMZR6CVVyBKo1oK35XJZtttt1Iu9pMXBAEBkvgeuTe5ThKLcfVnoIs7PS4eDDzh5cYwwaJ7P9fV18VwFVV3KRaK8NtRddCUUGrs5J/1gwH2t5bLfRQ/d/y2qGyoTM3QOWcooQ82aribsGoyugw9TwwFgq9VqYPIKCI8ZGu+r1Spq0f4wABFOcxrAZJ/qqn369GmQBp0K5JbLcsIxCFEvnwbMFU/8nDQsZ+tv88JeeScZeel6PYGx/q0PP+bNGznQQ/dnR2LSVYkgDgKZa63hfVbCIZRiq6G96tzxbw+LC71v7uwieYd1avXEeT8XpdxsNkX/5mdh78mrZGBr0PJHdAO2+sHzIMm/yWJrXNuOjpcDE2WbK1EvuRJVmytXOeE+vsY+SgvVGzk2nv24UFDx7ad8rFars6y2os9HVHTi2T8/VFr0s/P3OfbI53VVK/oUffDYdB26ExP0i/EyEY0T1cbktbRkpNuBMYmn/9/aRsjaYUUUcrKnraIEHpvn1qqU2gJ5Ay2acI5c9NwaVNUqz6GRUPfgHa8ONHj1WNnLH/NqDS+nx4V3RfK24j2bXlgigZP8ProtRyD5+7fOJZ+znhe6x+546zhizP9rFA1Dqt4jTxNolDmUlv8/2A4ZHFrvdcyYW4NUPt/WNXj6q93R8UxoGUI6pOTXrSjgoQ8c8cDwQaA1gOTjfzW45GP5vY8Ycjfwv0C/cG8UnLtagxySoXPffLzUmo/Oj63OfkduQV833q8iDfU5dUfHXyDP733zwQCv+7OX/dVzMuQD76z7Hu+sOjo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Op4M/wF16x90OB1iWAAAAABJRU5ErkJggg==","e":1},{"id":"comp_0","nm":"Pre-comp 1","fr":30,"layers":[{"ddd":0,"ind":1,"ty":2,"nm":"Cursor","refId":"image_0","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":24,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":31,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":69,"s":[100]},{"t":76,"s":[0],"h":1}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":39,"s":[766,1552,0],"to":[-2.124,-10.195,0],"ti":[7.19,16.039,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":40,"s":[763.675,1543.691,0],"to":[-10.384,-23.165,0],"ti":[19.558,31.51,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":42,"s":[760.984,1496.902,0],"to":[-30.655,-49.386,0],"ti":[30.773,9.616,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":45,"s":[618,1350,0],"to":[-75.01,-23.441,0],"ti":[38,-30,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":48,"s":[428,1368,0],"to":[-48.764,38.498,0],"ti":[-13.825,-82.951,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":50,"s":[366,1532,0],"to":[14,84,0],"ti":[-58.729,-9.322,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":53,"s":[528,1710,0],"to":[126,20,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":56,"s":[738,1684,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":58,"s":[766,1640,0],"to":[0,0,0],"ti":[0,0,0]},{"t":76,"s":[766,1640,0],"h":1}],"ix":2,"l":2},"a":{"a":0,"k":[125,135.5,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":89,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":69,"s":[100]},{"t":76,"s":[0],"h":1}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[562.5,1213,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[12.265,58.869],[64,20],[38,-30],[-13.825,-82.951],[-58.729,-9.322],[0,0]],"o":[[-10,-48],[-75.01,-23.441],[-48.764,38.498],[14,84],[126,20],[0,0]],"v":[[159.5,255],[55.5,133],[-134.5,151],[-196.5,315],[-34.5,441],[155.5,375]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.543],"y":[0]},"t":39,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":58,"s":[100]},{"t":76,"s":[100],"h":1}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":12,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":89,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Pre-comp 1","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[562.5,417,0],"ix":2,"l":2},"a":{"a":0,"k":[562.5,1217,0],"ix":1,"l":2},"s":{"a":0,"k":[140,140,100],"ix":6,"l":2}},"ao":0,"w":1125,"h":2434,"ip":0,"op":86,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"Pre-comp 1","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[562.5,497,0],"ix":2,"l":2},"a":{"a":0,"k":[562.5,1217,0],"ix":1,"l":2},"s":{"a":0,"k":[140,140,100],"ix":6,"l":2}},"ao":0,"w":1125,"h":2434,"ip":85,"op":171,"st":85,"bm":0},{"ddd":0,"ind":3,"ty":0,"nm":"Pre-comp 1","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[562.5,497,0],"ix":2,"l":2},"a":{"a":0,"k":[562.5,1217,0],"ix":1,"l":2},"s":{"a":0,"k":[140,140,100],"ix":6,"l":2}},"ao":0,"w":1125,"h":2434,"ip":170,"op":257,"st":170,"bm":0}],"markers":[]} \ No newline at end of file
diff --git a/ios/chrome/browser/first_run/public/features.mm b/ios/chrome/browser/first_run/public/features.mm index 05c34f63..4323756a 100644 --- a/ios/chrome/browser/first_run/public/features.mm +++ b/ios/chrome/browser/first_run/public/features.mm
@@ -18,7 +18,7 @@ "BestFeaturesScreenInFirstRunExperience", base::FEATURE_DISABLED_BY_DEFAULT); -BASE_FEATURE(kManualLogUploadsInTheFRE, base::FEATURE_DISABLED_BY_DEFAULT); +BASE_FEATURE(kManualLogUploadsInTheFRE, base::FEATURE_ENABLED_BY_DEFAULT); BASE_FEATURE(kSkipDefaultBrowserPromoInFirstRun, base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/ios/chrome/browser/intelligence/proto_wrappers/page_context_extractor_java_script_feature_unittest.mm b/ios/chrome/browser/intelligence/proto_wrappers/page_context_extractor_java_script_feature_unittest.mm index c8505abe67..940c3eb 100644 --- a/ios/chrome/browser/intelligence/proto_wrappers/page_context_extractor_java_script_feature_unittest.mm +++ b/ios/chrome/browser/intelligence/proto_wrappers/page_context_extractor_java_script_feature_unittest.mm
@@ -597,3 +597,125 @@ // and that the uppercase transformation still applies to the nested text. EXPECT_EQ(*table_name, "MY NESTED TABLE NAME"); } + +// Verifies that internal SVG structural and metadata elements (like <title>, +// <defs>, and <script>) are strictly excluded from extraction to prevent +// non-visible technical strings from polluting the output. +TEST_F(PageContextExtractorJavaScriptFeatureTest, + ExtractPageContext_RichExtraction_Svg) { + const std::string html = "<html><body><svg width=\"100\" height=\"100\">" + "<title>SVG Title</title>" + "<desc>SVG Desc</desc>" + "<text>SVG Text</text>" + "<g><text><tspan>Nested Text</tspan></text></g>" + "</svg></body></html>"; + web::test::LoadHtml(base::SysUTF8ToNSString(html), + test_server_.GetURL(kMainPagePath), web_state()); + + base::test::TestFuture<base::Value> future; + feature()->ExtractPageContext( + web_state()->GetPageWorldWebFramesManager()->GetMainWebFrame(), + /*include_cross_origin_frame_content=*/false, + /*use_rich_extraction=*/true, + /*use_rich_extraction_with_actionable=*/false, + /*extract_paid_content=*/false, + /*attempt_paid_content_json_fixing=*/false, "nonce", base::Seconds(1), + base::BindOnce( + [](base::OnceCallback<void(base::Value)> callback, + const base::Value* value) { + std::move(callback).Run(value ? value->Clone() : base::Value()); + }, + future.GetCallback())); + + base::Value result_value = future.Take(); + ASSERT_TRUE(result_value.is_dict()); + + const base::DictValue& dict = result_value.GetDict(); + const base::DictValue* root_node = dict.FindDict("rootNode"); + ASSERT_TRUE(root_node); + + const base::ListValue* children = root_node->FindList("childrenNodes"); + ASSERT_TRUE(children); + ASSERT_EQ(children->size(), 1u); + + // Check SVG + const base::DictValue& svg_node = (*children)[0].GetDict(); + std::optional<double> attribute_type = + svg_node.FindDoubleByDottedPath("contentAttributes.attributeType"); + ASSERT_TRUE(attribute_type.has_value()); + EXPECT_EQ( + static_cast<int>(attribute_type.value()), + static_cast<int>(optimization_guide::proto::CONTENT_ATTRIBUTE_SVG_ROOT)); + + // Verify that the SVG is NOT treated as a leaf component. + const base::ListValue* svg_children = svg_node.FindList("childrenNodes"); + ASSERT_TRUE(svg_children); + + // We expect "SVG Text" and the group containing "Nested Text". + // <title> and <desc> are excluded. + ASSERT_EQ(svg_children->size(), 2u); + + // Check for the "SVG Text" node. + const base::DictValue& text_node = (*svg_children)[0].GetDict(); + EXPECT_EQ(*(text_node.FindStringByDottedPath( + "contentAttributes.textInfo.textContent")), + "SVG Text"); + + // Check for nested text node. + const base::DictValue& nested_text_node = (*svg_children)[1].GetDict(); + EXPECT_EQ(*(nested_text_node.FindStringByDottedPath( + "contentAttributes.textInfo.textContent")), + "Nested Text"); +} + +// Verifies that SVG elements rendered invisible via CSS (display/visibility) +// are excluded. +TEST_F(PageContextExtractorJavaScriptFeatureTest, + ExtractPageContext_RichExtraction_Svg_Visibility) { + const std::string html = + "<html><body><svg width=\"200\" height=\"200\">" + "<text>Visible Text</text>" + "<text style=\"display: none\">Hidden Display Text</text>" + "<text style=\"visibility: hidden\">Hidden Visibility Text</text>" + "<g style=\"display: none\"><text>Hidden Group Text</text></g>" + "</svg></body></html>"; + web::test::LoadHtml(base::SysUTF8ToNSString(html), + test_server_.GetURL(kMainPagePath), web_state()); + + base::test::TestFuture<base::Value> future; + feature()->ExtractPageContext( + web_state()->GetPageWorldWebFramesManager()->GetMainWebFrame(), + /*include_cross_origin_frame_content=*/false, + /*use_rich_extraction=*/true, + /*use_rich_extraction_with_actionable=*/false, + /*extract_paid_content=*/false, + /*attempt_paid_content_json_fixing=*/false, "nonce", base::Seconds(1), + base::BindOnce( + [](base::OnceCallback<void(base::Value)> callback, + const base::Value* value) { + std::move(callback).Run(value ? value->Clone() : base::Value()); + }, + future.GetCallback())); + + base::Value result_value = future.Take(); + ASSERT_TRUE(result_value.is_dict()); + + const base::DictValue& dict = result_value.GetDict(); + const base::DictValue* root_node = dict.FindDict("rootNode"); + ASSERT_TRUE(root_node); + + const base::ListValue* children = root_node->FindList("childrenNodes"); + ASSERT_TRUE(children); + ASSERT_EQ(children->size(), 1u); + + // Check SVG + const base::DictValue& svg_node = (*children)[0].GetDict(); + const base::ListValue* svg_children = svg_node.FindList("childrenNodes"); + ASSERT_TRUE(svg_children); + + ASSERT_EQ(svg_children->size(), 1u); + const base::DictValue& text_node = (*svg_children)[0].GetDict(); + EXPECT_EQ(*((text_node.FindStringByDottedPath( + "contentAttributes.textInfo.textContent"))), + "Visible Text"); +}
diff --git a/ios/chrome/browser/intelligence/proto_wrappers/page_context_wrapper_unittest.mm b/ios/chrome/browser/intelligence/proto_wrappers/page_context_wrapper_unittest.mm index c423ec6..5a6b4cd 100644 --- a/ios/chrome/browser/intelligence/proto_wrappers/page_context_wrapper_unittest.mm +++ b/ios/chrome/browser/intelligence/proto_wrappers/page_context_wrapper_unittest.mm
@@ -4075,6 +4075,48 @@ 100); } +// Tests that SVG inner text is extracted correctly. +TEST_P(PageContextWrapperTest, PopulatePageContext_RichExtraction_Svg) { + if (!IsRefactored()) { + return; + } + auto page_structure = HtmlPage( + "RichExtraction_Svg", + RawHtml("<svg width=\"100\" height=\"100\"><title>Title</title><text>SVG " + "Text</text></svg>")); + + std::string main_html = page_helper_->Build(page_structure); + web::test::LoadHtml(base::SysUTF8ToNSString(main_html), + test_server_.GetURL(kMainPagePath), web_state()); + + PageContextWrapperConfig config = + PageContextWrapperConfigBuilder().SetUseRichExtraction(true).Build(); + + PageContextWrapperCallbackResponse response = RunPageContextWrapperWithConfig( + web_state(), config, ^(PageContextWrapper* wrapper) { + wrapper.shouldGetAnnotatedPageContent = YES; + }); + + ASSERT_TRUE(response.has_value()); + const auto& page_context = *response.value(); + const auto& root_node = page_context.annotated_page_content().root_node(); + + // Root -> SVG + ASSERT_EQ(root_node.children_nodes_size(), 1); + const auto& svg_node = root_node.children_nodes(0); + EXPECT_EQ(svg_node.content_attributes().attribute_type(), + optimization_guide::proto::CONTENT_ATTRIBUTE_SVG_ROOT); + EXPECT_FALSE(svg_node.content_attributes().has_svg_root_data()); + + // Verify that the child text was extracted. + ASSERT_EQ(svg_node.children_nodes_size(), 1); + const auto& text_node = svg_node.children_nodes(0); + EXPECT_EQ(text_node.content_attributes().attribute_type(), + optimization_guide::proto::CONTENT_ATTRIBUTE_TEXT); + EXPECT_EQ(text_node.content_attributes().text_data().text_content(), + "SVG Text"); +} + // Tests that Video Metadata is extracted correctly. TEST_P(PageContextWrapperTest, PopulatePageContext_RichExtraction_Video) { if (!IsRefactored()) {
diff --git a/ios/chrome/browser/intelligence/proto_wrappers/resources/annotated_page_content_extraction.ts b/ios/chrome/browser/intelligence/proto_wrappers/resources/annotated_page_content_extraction.ts index 1cf4134..c06fed0 100644 --- a/ios/chrome/browser/intelligence/proto_wrappers/resources/annotated_page_content_extraction.ts +++ b/ios/chrome/browser/intelligence/proto_wrappers/resources/annotated_page_content_extraction.ts
@@ -40,6 +40,8 @@ // Media tags. const TAG_SVG = 'SVG'; +const TAG_DESC = 'DESC'; +const TAG_TITLE = 'TITLE'; const TAG_CANVAS = 'CANVAS'; const TAG_VIDEO = 'VIDEO'; @@ -100,13 +102,10 @@ TAG_DATALIST, TAG_HEAD, TAG_CAPTION, + TAG_DESC, + TAG_TITLE, ]; -// Tags that contain valid content but are not yet extracted. -// TODO(crbug.com/468852704): Remove tags from this list as they are -// implemented. -const TAGS_TO_SUPPORT_EVENTUALLY = [TAG_SVG]; - // Tags that should be strictly rejected if they are invisible, // because they are considered "leaf" nodes. const TAGS_TO_STRICTLY_REJECT_IF_HIDDEN = [ @@ -334,7 +333,7 @@ * @return The corresponding FormControlType. */ function getFormControlType(element: HTMLElement): FormControlType|undefined { - const tagName = element.tagName; + const tagName = getStandardTagName(element); if (tagName === TAG_BUTTON) { const type = (element as HTMLButtonElement).type; @@ -476,7 +475,7 @@ // Fallback: check if it's an open dialog. Note: Without `:modal` support, // we cannot distinguish between `dialog.show()` (normal document flow) and // `dialog.showModal()` (top layer). This is a best-effort approximation. - if (element.tagName === TAG_DIALOG && + if (getStandardTagName(element) === TAG_DIALOG && element.hasAttribute(ATTRIBUTE_OPEN_DIALOG)) { return true; } @@ -523,18 +522,19 @@ interactionInfo: PageContentNodeInteractionInfo|undefined): boolean { // Check if the element is an interactive node. const nodeId = getNodeId(element); + const tagName = getStandardTagName(element); if (nodeId !== null && interactiveNodeIds.has(nodeId)) { return true; } // Elements with annotated roles are considered generic containers. - if (getAnnotatedRoleForTag(element.tagName) !== null) { + if (getAnnotatedRoleForTag(tagName) !== null) { return true; } // A <figure> element is a semantic container for self-contained content, like // images or diagrams, making it a generic container. - if (element.tagName === TAG_FIGURE) { + if (tagName === TAG_FIGURE) { return true; } @@ -691,9 +691,9 @@ const clickabilityReasons = interactionInfo.clickabilityReasons; + const tagName = getStandardTagName(element); // Form Controls. - if ([TAG_BUTTON, TAG_INPUT, TAG_SELECT, TAG_TEXTAREA].includes( - element.tagName)) { + if ([TAG_BUTTON, TAG_INPUT, TAG_SELECT, TAG_TEXTAREA].includes(tagName)) { clickabilityReasons.push(PageContentClickabilityReason.CLICKABLE_CONTROL); } @@ -723,8 +723,9 @@ } // Editable. - if (element.isContentEditable || element.tagName === TAG_TEXTAREA || - (element.tagName === TAG_INPUT && + if (element.isContentEditable || + tagName === TAG_TEXTAREA || + (tagName === TAG_INPUT && ![CHECKBOX_TYPE, RADIO_TYPE, RANGE_TYPE, COLOR_TYPE, FILE_TYPE, IMAGE_TYPE, SUBMIT_TYPE, RESET_TYPE, BUTTON_TYPE] .includes((element as HTMLInputElement).type))) { @@ -822,10 +823,11 @@ return undefined; } + const tagName = getStandardTagName(selectedMedia); let mediaDataType = PageContentMediaType.MEDIA_DATA_TYPE_UNKNOWN; - if (selectedMedia.tagName === TAG_VIDEO) { + if (tagName === TAG_VIDEO) { mediaDataType = PageContentMediaType.MEDIA_DATA_TYPE_VIDEO; - } else if (selectedMedia.tagName === TAG_AUDIO) { + } else if (tagName === TAG_AUDIO) { mediaDataType = PageContentMediaType.MEDIA_DATA_TYPE_AUDIO; } @@ -1452,7 +1454,7 @@ domNode: HTMLElement, nonce: string, depth: number, maxDepth: number, actionableMode: boolean, paidContentContext: PaidContentExtractionContext): PageContentNode|null { - const tagName = domNode.tagName; + const tagName = getStandardTagName(domNode); switch (tagName) { // 1. Complex Elements. @@ -1518,6 +1520,15 @@ }, }; } + case TAG_SVG: { + return { + childrenNodes: [], + contentAttributes: { + ...BASIC_CONTENT_ATTRIBUTES, + attributeType: PageContentAttributeType.SVG_ROOT, + }, + }; + } // 2. Structural & Layout Elements. case TAG_TABLE: { @@ -1538,9 +1549,9 @@ // table boundary and don't match a section from an outer table if this // row is inside a nested table. const section = domNode.closest('thead, tfoot, table'); - if (section && section.tagName === 'THEAD') { + if (section && getStandardTagName(section) === 'THEAD') { rowType = PageContentTableRowType.HEADER; - } else if (section && section.tagName === 'TFOOT') { + } else if (section && getStandardTagName(section) === 'TFOOT') { rowType = PageContentTableRowType.FOOTER; } return { @@ -1707,7 +1718,7 @@ function addAnnotatedRoles( domNode: HTMLElement, attributesToPopulate: PageContentAttributes, paidContentContext: PaidContentExtractionContext) { - const role = getAnnotatedRoleForTag(domNode.tagName); + const role = getAnnotatedRoleForTag(getStandardTagName(domNode)); const roles: PageContentAnnotatedRole[] = []; if (role !== null) { roles.push(role); @@ -1757,7 +1768,7 @@ } } else if (domNode.nodeType === Node.ELEMENT_NODE) { const element = domNode as HTMLElement; - const role = getAnnotatedRoleForTag(element.tagName); + const role = getAnnotatedRoleForTag(getStandardTagName(element)); const annotatedRoles = (role == null) ? [] : [role]; const interactionInfo = getNodeInteractionInfo(element, actionableMode); @@ -1784,8 +1795,8 @@ function shouldAcceptNode(node: Node): number { if (node.nodeType === Node.ELEMENT_NODE) { const element = node as Element; - if (TAGS_TO_REJECT.includes(element.tagName) || - TAGS_TO_SUPPORT_EVENTUALLY.includes(element.tagName)) { + const tagName = getStandardTagName(element); + if (TAGS_TO_REJECT.includes(tagName)) { return NodeFilter.FILTER_REJECT; } const windowObj = element.ownerDocument?.defaultView; @@ -1801,7 +1812,7 @@ } if (style.visibility === ATTR_VISIBILITY_HIDDEN) { // Strictly skip invisible leaf nodes. - if (TAGS_TO_STRICTLY_REJECT_IF_HIDDEN.includes(element.tagName)) { + if (TAGS_TO_STRICTLY_REJECT_IF_HIDDEN.includes(tagName)) { return NodeFilter.FILTER_REJECT; } // For containers, we OPTIMISTICALLY ACCEPT (FILTER_ACCEPT). @@ -1952,6 +1963,16 @@ return interactiveNodeIds; } +/** + * Returns the standardized, uppercase tag name for an element. + * + * @param element The DOM element to evaluate. + * @return The uppercase tag name. + */ +function getStandardTagName(element: Element): string { + return element.tagName.toUpperCase(); +} + // TODO(crbug.com/485796293): Wrap this in a class. /** * Extracts the annotated page content of the document starting from the body
diff --git a/ios/chrome/browser/picture_in_picture/test/BUILD.gn b/ios/chrome/browser/picture_in_picture/test/BUILD.gn new file mode 100644 index 0000000..5b6733b --- /dev/null +++ b/ios/chrome/browser/picture_in_picture/test/BUILD.gn
@@ -0,0 +1,24 @@ +# Copyright 2026 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//build/config/chrome_build.gni") + +source_set("eg2_tests") { + configs += [ "//build/config/ios:xctest_config" ] + testonly = true + sources = [ "picture_in_picture_egtest.mm" ] + deps = [ + "//base/test:test_support", + "//ios/chrome/app/strings", + "//ios/chrome/browser/default_browser/promo/public:features", + "//ios/chrome/browser/shared/public/features", + "//ios/chrome/test/earl_grey:eg_test_support+eg2", + "//ios/chrome/test/earl_grey:switches", + "//ios/testing/earl_grey:eg_test_support+eg2", + "//net:test_support", + "//ui/base", + "//ui/base:test_support", + ] + frameworks = [ "UIKit.framework" ] +}
diff --git a/ios/chrome/browser/picture_in_picture/test/picture_in_picture_egtest.mm b/ios/chrome/browser/picture_in_picture/test/picture_in_picture_egtest.mm new file mode 100644 index 0000000..55fd3e0e --- /dev/null +++ b/ios/chrome/browser/picture_in_picture/test/picture_in_picture_egtest.mm
@@ -0,0 +1,194 @@ +// Copyright 2026 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import <XCTest/XCTest.h> + +#import "ios/chrome/browser/default_browser/promo/public/features.h" +#import "ios/chrome/grit/ios_branded_strings.h" +#import "ios/chrome/grit/ios_strings.h" +#import "ios/chrome/test/earl_grey/chrome_earl_grey.h" +#import "ios/chrome/test/earl_grey/chrome_earl_grey_ui.h" +#import "ios/chrome/test/earl_grey/chrome_matchers.h" +#import "ios/chrome/test/earl_grey/chrome_test_case.h" +#import "ios/testing/earl_grey/earl_grey_test.h" +#import "ui/base/l10n/l10n_util.h" + +namespace { + +// Timeout for PiP window to appear. +const NSTimeInterval kPipAppearanceTimeout = 5.0; + +// Timeout for PiP controls to appear. +const NSTimeInterval kPipControlsTimeout = 3.0; + +// Accessibility label for the PiP close button. +NSString* const kPipCloseButtonLabel = @"Close Picture in Picture"; + +// Accessibility label for the PiP restore fullscreen button. +NSString* const kPipRestoreFullscreenButtonLabel = @"Restore fullscreen"; + +// Accessibility label for the SpringBoard breadcrumb button. +NSString* const kSpringBoardBreadcrumbLabel = @"breadcrumb"; + +// Identifier for the iOS SpringBoard process. +NSString* const kSpringBoardBundleIdentifier = @"com.apple.springboard"; + +// Accessibility identifier for the PiP window in SpringBoard. +NSString* const kPipWindowIdentifier = @"Picture in Picture"; + +// Navigates to the Default Browser Settings and triggers the PiP promo. +void OpenDefaultBrowserPictureInPicturePromo() { + [ChromeEarlGreyUI openSettingsMenu]; + + id<GREYMatcher> defaultBrowserRow = chrome_test_util::ContainsPartialText( + l10n_util::GetNSString(IDS_IOS_SETTINGS_SET_DEFAULT_BROWSER)); + + [[[EarlGrey selectElementWithMatcher:defaultBrowserRow] + usingSearchAction:grey_scrollInDirection(kGREYDirectionDown, 200) + onElementWithMatcher:chrome_test_util::SettingsCollectionView()] + performAction:grey_tap()]; + + id<GREYMatcher> primaryButton = chrome_test_util::ButtonStackPrimaryButton(); + [ChromeEarlGrey waitForUIElementToAppearWithMatcher:primaryButton]; + [[EarlGrey selectElementWithMatcher:primaryButton] performAction:grey_tap()]; +} + +// Returns a proxy to the iOS SpringBoard application. Picture in Picture is a +// system-level feature, so we need to interact with SpringBoard to control it. +XCUIApplication* SpringBoardApplication() { + return [[XCUIApplication alloc] + initWithBundleIdentifier:kSpringBoardBundleIdentifier]; +} + +// Returns the PiP window element within the given application. +XCUIElement* PipWindowInApplication(XCUIApplication* application) { + return application.windows[kPipWindowIdentifier].firstMatch; +} + +// Ensures that PiP controls are visible by tapping the PiP window if necessary. +void EnsurePipControlsAreVisibleForWindow(XCUIElement* pipWindow, + XCUIElement* controlElement) { + if (!controlElement.exists || !controlElement.isHittable) { + [pipWindow tap]; + } +} + +} // namespace + +@interface PictureInPictureTestCase : ChromeTestCase +@end + +@implementation PictureInPictureTestCase + +- (AppLaunchConfiguration)appConfigurationForTestCase { + AppLaunchConfiguration config = [super appConfigurationForTestCase]; + config.features_enabled.push_back(kDefaultBrowserPictureInPicture); + return config; +} + +#pragma mark - Tests + +// Tests that the PiP window for the Default Browser promo can be +// started and then dismissed using the close button. +- (void)testDefaultBrowserStartPipAndDismiss { +#if TARGET_OS_SIMULATOR + EARL_GREY_TEST_DISABLED(@"This test is not supported on simulator."); +#endif + OpenDefaultBrowserPictureInPicturePromo(); + + XCUIApplication* springboard = SpringBoardApplication(); + XCUIElement* pipWindow = PipWindowInApplication(springboard); + + GREYAssertTrue([pipWindow waitForExistenceWithTimeout:kPipAppearanceTimeout], + @"PiP window did not appear."); + + XCUIElement* closeButton = pipWindow.buttons[kPipCloseButtonLabel].firstMatch; + + // Ensure the close button is visible before tapping it. + EnsurePipControlsAreVisibleForWindow(pipWindow, closeButton); + + BOOL successfullyClosed = NO; + if ([closeButton waitForExistenceWithTimeout:kPipControlsTimeout]) { + [closeButton tap]; + successfullyClosed = YES; + } + + GREYAssertTrue(successfullyClosed, + @"Could not find or tap the close button."); + + // Verify that the Default Browser fullscreen video instructions title is not + // visible. + id<GREYMatcher> titleLabel = + chrome_test_util::ContainsPartialText(l10n_util::GetNSString( + IDS_IOS_DEFAULT_BROWSER_PICTURE_IN_PICTURE_TITLE_TEXT)); + [[EarlGrey selectElementWithMatcher:titleLabel] + assertWithMatcher:grey_notVisible()]; +} + +// Tests that the PiP window for the Default Browser promo can be +// started and then used to restore the app and display the video in fullscreen. +- (void)testDefaultBrowserStartPipAndRestoreFullscreen { +#if TARGET_OS_SIMULATOR + EARL_GREY_TEST_DISABLED(@"This test is not supported on simulator."); +#endif + OpenDefaultBrowserPictureInPicturePromo(); + + XCUIApplication* springboard = SpringBoardApplication(); + XCUIElement* pipWindow = PipWindowInApplication(springboard); + + GREYAssertTrue([pipWindow waitForExistenceWithTimeout:kPipAppearanceTimeout], + @"PiP window did not appear."); + + XCUIElement* restoreButton = + pipWindow.buttons[kPipRestoreFullscreenButtonLabel].firstMatch; + + // Ensure the restore button is visible before tapping it. + EnsurePipControlsAreVisibleForWindow(pipWindow, restoreButton); + + GREYAssertTrue( + [restoreButton waitForExistenceWithTimeout:kPipControlsTimeout], + @"Restore fullscreen button did not appear."); + [restoreButton tap]; + + // Verify that the Default Browser fullscreen video instructions title is + // visible after restoration. + id<GREYMatcher> titleLabel = + chrome_test_util::ContainsPartialText(l10n_util::GetNSString( + IDS_IOS_DEFAULT_BROWSER_PICTURE_IN_PICTURE_TITLE_TEXT)); + [ChromeEarlGrey waitForUIElementToAppearWithMatcher:titleLabel]; +} + +// Tests that the PiP window for the Default Browser promo can be +// started and then the app can be restored via the status bar return to app +// button. +- (void)testDefaultBrowserStartPipAndRestoreViaReturnToApp { +#if TARGET_OS_SIMULATOR + EARL_GREY_TEST_DISABLED(@"This test is not supported on simulator."); +#endif + OpenDefaultBrowserPictureInPicturePromo(); + + XCUIApplication* springboard = SpringBoardApplication(); + XCUIElement* pipWindow = PipWindowInApplication(springboard); + + GREYAssertTrue([pipWindow waitForExistenceWithTimeout:kPipAppearanceTimeout], + @"PiP window did not appear."); + + XCUIElement* breadcrumbButton = + springboard.statusBars.buttons[kSpringBoardBreadcrumbLabel].firstMatch; + + GREYAssertTrue( + [breadcrumbButton waitForExistenceWithTimeout:kPipControlsTimeout], + @"Status bar breadcrumb button did not appear."); + [breadcrumbButton tap]; + + // Verify that the Default Browser fullscreen video instructions title is not + // visible after restoration. + id<GREYMatcher> titleLabel = + chrome_test_util::ContainsPartialText(l10n_util::GetNSString( + IDS_IOS_DEFAULT_BROWSER_PICTURE_IN_PICTURE_TITLE_TEXT)); + [[EarlGrey selectElementWithMatcher:titleLabel] + assertWithMatcher:grey_notVisible()]; +} + +@end
diff --git a/ios/chrome/browser/popup_menu/coordinator/BUILD.gn b/ios/chrome/browser/popup_menu/coordinator/BUILD.gn index f5ea1d0..c29ef9c 100644 --- a/ios/chrome/browser/popup_menu/coordinator/BUILD.gn +++ b/ios/chrome/browser/popup_menu/coordinator/BUILD.gn
@@ -26,6 +26,7 @@ "//ios/chrome/browser/intelligence/features", "//ios/chrome/browser/lens_overlay/coordinator:lens_overlay_availability", "//ios/chrome/browser/overlays/model", + "//ios/chrome/browser/policy/model", "//ios/chrome/browser/popup_menu/overflow_menu/coordinator", "//ios/chrome/browser/popup_menu/overflow_menu/public", "//ios/chrome/browser/popup_menu/overflow_menu/public:overflow_menu_constants",
diff --git a/ios/chrome/browser/popup_menu/coordinator/popup_menu_coordinator.mm b/ios/chrome/browser/popup_menu/coordinator/popup_menu_coordinator.mm index 16ebfab..37ef4039 100644 --- a/ios/chrome/browser/popup_menu/coordinator/popup_menu_coordinator.mm +++ b/ios/chrome/browser/popup_menu/coordinator/popup_menu_coordinator.mm
@@ -5,6 +5,7 @@ #import "ios/chrome/browser/popup_menu/coordinator/popup_menu_coordinator.h" #import "base/check.h" +#import "base/ios/ios_util.mm" #import "base/metrics/histogram_functions.h" #import "base/metrics/histogram_macros.h" #import "base/metrics/user_metrics.h" @@ -20,6 +21,7 @@ #import "ios/chrome/browser/intelligence/features/features.h" #import "ios/chrome/browser/lens_overlay/coordinator/lens_overlay_availability.h" #import "ios/chrome/browser/overlays/model/public/overlay_presenter.h" +#import "ios/chrome/browser/policy/model/browser_management_service_factory.h" #import "ios/chrome/browser/popup_menu/coordinator/popup_menu_help_coordinator.h" #import "ios/chrome/browser/popup_menu/overflow_menu/coordinator/overflow_menu_mediator.h" #import "ios/chrome/browser/popup_menu/overflow_menu/coordinator/overflow_menu_orderer.h" @@ -295,6 +297,8 @@ mediator.syncService = SyncServiceFactory::GetForProfile(profile); mediator.templateURLService = ios::TemplateURLServiceFactory::GetForProfile(profile); + mediator.browserManagementService = + policy::BrowserManagementServiceFactory::GetForProfile(profile); mediator.promosManager = PromosManagerFactory::GetForProfile(profile); mediator.readingListBrowserAgent = ReadingListBrowserAgent::FromBrowser(browser); @@ -344,21 +348,17 @@ UILayoutGuide* layoutGuide = [layoutGuideCenter makeLayoutGuideNamed:kToolsMenuGuide]; [self.baseViewController.view addLayoutGuide:layoutGuide]; - CGRect frame = layoutGuide.layoutFrame; menu.modalPresentationStyle = UIModalPresentationPopover; UIPopoverPresentationController* popoverPresentationController = menu.popoverPresentationController; - // Hides the arrow on the popover. - popoverPresentationController.permittedArrowDirections = 0; popoverPresentationController.sourceView = self.baseViewController.view; - // With permittedArrowDirections = 0 (no arrow), apply an offset to position - // the popover approximately where it would be with an arrow-up. - popoverPresentationController.sourceRect = - CGRectMake(frame.origin.x, frame.origin.y + 360, frame.size.width, - frame.size.height); - + popoverPresentationController.sourceRect = layoutGuide.layoutFrame; + // Hides the arrow on the popover on iOS 26+ because of a UI glitch on the + // arrow. + popoverPresentationController.permittedArrowDirections = + base::ios::IsRunningOnIOS26OrLater() ? 0 : UIPopoverArrowDirectionUp; popoverPresentationController.delegate = self; popoverPresentationController.backgroundColor = [UIColor colorNamed:kBackgroundColor];
diff --git a/ios/chrome/browser/popup_menu/overflow_menu/coordinator/BUILD.gn b/ios/chrome/browser/popup_menu/overflow_menu/coordinator/BUILD.gn index e91b74f..42feed9 100644 --- a/ios/chrome/browser/popup_menu/overflow_menu/coordinator/BUILD.gn +++ b/ios/chrome/browser/popup_menu/overflow_menu/coordinator/BUILD.gn
@@ -87,7 +87,9 @@ "//ios/chrome/browser/web/model/font_size", "//ios/chrome/browser/whats_new/coordinator:util", "//ios/chrome/browser/window_activities/model", + "//ios/public/provider/chrome/browser/cobalt:cobalt_api", "//ios/public/provider/chrome/browser/user_feedback:user_feedback_api", + "//ios/web/common:features", "//ios/web/common:user_agent", "//ios/web/public", "//ios/web/public/js_messaging",
diff --git a/ios/chrome/browser/popup_menu/overflow_menu/coordinator/overflow_menu_mediator.h b/ios/chrome/browser/popup_menu/overflow_menu/coordinator/overflow_menu_mediator.h index 1de3111..de26bad 100644 --- a/ios/chrome/browser/popup_menu/overflow_menu/coordinator/overflow_menu_mediator.h +++ b/ios/chrome/browser/popup_menu/overflow_menu/coordinator/overflow_menu_mediator.h
@@ -8,6 +8,7 @@ #import <UIKit/UIKit.h> #import "ios/chrome/browser/browser_content/ui_bundled/browser_content_consumer.h" +#import "ios/chrome/browser/policy/model/browser_management_service.h" #import "ios/chrome/browser/popup_menu/overflow_menu/public/overflow_menu_action_provider.h" #import "ios/chrome/browser/popup_menu/overflow_menu/ui/ui_swift.h" @@ -152,6 +153,10 @@ // TemplateURLService to observe default search engine change. @property(nonatomic, assign) TemplateURLService* templateURLService; +// Browser management service to determine if the browser is managed. +@property(nonatomic, assign) + policy::BrowserManagementService* browserManagementService; + // If settings destination has a blue dot. @property(nonatomic, assign) bool hasSettingsBlueDot;
diff --git a/ios/chrome/browser/popup_menu/overflow_menu/coordinator/overflow_menu_mediator.mm b/ios/chrome/browser/popup_menu/overflow_menu/coordinator/overflow_menu_mediator.mm index 6a3e119..2406954 100644 --- a/ios/chrome/browser/popup_menu/overflow_menu/coordinator/overflow_menu_mediator.mm +++ b/ios/chrome/browser/popup_menu/overflow_menu/coordinator/overflow_menu_mediator.mm
@@ -113,7 +113,9 @@ #import "ios/chrome/browser/window_activities/model/window_activity_helpers.h" #import "ios/chrome/grit/ios_branded_strings.h" #import "ios/chrome/grit/ios_strings.h" +#import "ios/public/provider/chrome/browser/cobalt/cobalt_api.h" #import "ios/public/provider/chrome/browser/user_feedback/user_feedback_api.h" +#import "ios/web/common/features.h" #import "ios/web/common/user_agent.h" #import "ios/web/public/js_messaging/web_frame.h" #import "ios/web/public/navigation/navigation_item.h" @@ -227,6 +229,7 @@ @property(nonatomic, strong) OverflowMenuDestination* whatsNewDestination; @property(nonatomic, strong) OverflowMenuDestination* spotlightDebuggerDestination; +@property(nonatomic, strong) OverflowMenuDestination* cobaltDestination; @property(nonatomic, strong) OverflowMenuActionGroup* appActionsGroup; @property(nonatomic, strong) OverflowMenuActionGroup* pageActionsGroup; @@ -327,6 +330,7 @@ self.localStatePrefs = nullptr; self.syncService = nullptr; + self.browserManagementService = nullptr; _searchEngineObserver.reset(); } @@ -497,6 +501,12 @@ } } +- (void)setBrowserManagementService: + (policy::BrowserManagementService*)browserManagementService { + _browserManagementService = browserManagementService; + [self updateModel]; +} + #pragma mark - Model Creation - (void)initializeModel { @@ -530,6 +540,9 @@ self.spotlightDebuggerDestination = [self newSpotlightDebuggerDestination]; + // Cobalt destination. + self.cobaltDestination = [self newCobaltDestination]; + // WhatsNew destination. self.whatsNewDestination = [self newWhatsNewDestination]; @@ -1233,6 +1246,24 @@ }]; } +- (OverflowMenuDestination*)newCobaltDestination { + auto destinationParameters = + ios::provider::GetCobaltOverflowMenuDestinationParameters(); + if (destinationParameters.destination_name_id == 0) { + return nil; + } + __weak __typeof(self) weakSelf = self; + return [self + createOverflowMenuDestination:destinationParameters.destination_name_id + destination:destinationParameters.destination + symbolName:destinationParameters.symbol_name + systemSymbol:destinationParameters.system_symbol + accessibilityID:destinationParameters.accessibility_id + handler:^{ + [weakSelf openCobalt]; + }]; +} + - (OverflowMenuDestination*)newPriceNotificationsDestination { __weak __typeof(self) weakSelf = self; return [self createOverflowMenuDestination:IDS_IOS_TOOLS_MENU_PRICE_TRACKING @@ -1252,6 +1283,7 @@ case overflow_menu::Destination::SiteInfo: case overflow_menu::Destination::Settings: case overflow_menu::Destination::SpotlightDebugger: + case overflow_menu::Destination::Cobalt: // These items are unhideable. return nil; case overflow_menu::Destination::Bookmarks: @@ -1491,6 +1523,7 @@ overflow_menu::Destination::Settings, overflow_menu::Destination::PriceNotifications, overflow_menu::Destination::WhatsNew, + overflow_menu::Destination::Cobalt, }; return destinations; @@ -2106,6 +2139,17 @@ return self.whatsNewDestination; case overflow_menu::Destination::SpotlightDebugger: return self.spotlightDebuggerDestination; + case overflow_menu::Destination::Cobalt: + if (!web::features::IsCobaltEnabled()) { + return nil; + } + if (!self.browserManagementService) { + return nil; + } + if (self.browserManagementService->IsManaged()) { + return nil; + } + return self.cobaltDestination; case overflow_menu::Destination::PriceNotifications: BOOL priceNotificationsActive = self.webState && IsPriceTrackingEnabled(ProfileIOS::FromBrowserState( @@ -2138,6 +2182,8 @@ return [self newWhatsNewDestination]; case overflow_menu::Destination::SpotlightDebugger: return [self newSpotlightDebuggerDestination]; + case overflow_menu::Destination::Cobalt: + return [self newCobaltDestination]; case overflow_menu::Destination::PriceNotifications: return [self newPriceNotificationsDestination]; } @@ -2653,6 +2699,12 @@ showSavedPasswordsSettingsFromViewController:self.baseViewController]; } +// Dismisses the menu and opens Cobalt. +- (void)openCobalt { + [self dismissMenu]; + // TODO(crbug.com/475807780): Open Cobalt UI. +} + // Dismisses the menu and opens price notifications list. - (void)openPriceNotifications { RecordAction(UserMetricsAction("MobileMenuPriceNotifications")); @@ -2752,6 +2804,7 @@ case overflow_menu::Destination::Settings: case overflow_menu::Destination::WhatsNew: case overflow_menu::Destination::SpotlightDebugger: + case overflow_menu::Destination::Cobalt: case overflow_menu::Destination::PriceNotifications: // Most destinations have no corresponding destination and nothing special // to be done when their shown state is toggled.
diff --git a/ios/chrome/browser/popup_menu/overflow_menu/public/overflow_menu_constants.cc b/ios/chrome/browser/popup_menu/overflow_menu/public/overflow_menu_constants.cc index 55b1ba0..20971792 100644 --- a/ios/chrome/browser/popup_menu/overflow_menu/public/overflow_menu_constants.cc +++ b/ios/chrome/browser/popup_menu/overflow_menu/public/overflow_menu_constants.cc
@@ -35,6 +35,8 @@ return overflow_menu::Destination::WhatsNew; } else if (destination == "overflow_menu::Destination::SpotlightDebugger") { return overflow_menu::Destination::SpotlightDebugger; + } else if (destination == "overflow_menu::Destination::Cobalt") { + return overflow_menu::Destination::Cobalt; } else { return std::nullopt; } @@ -68,6 +70,8 @@ return "overflow_menu::Destination::WhatsNew"; case overflow_menu::Destination::SpotlightDebugger: return "overflow_menu::Destination::SpotlightDebugger"; + case overflow_menu::Destination::Cobalt: + return "overflow_menu::Destination::Cobalt"; } } // LINT.ThenChange(:stringToDestination) @@ -220,6 +224,9 @@ case overflow_menu::Destination::SpotlightDebugger: // No need to log metrics for a debug-only feature. break; + case overflow_menu::Destination::Cobalt: + // No need to log metrics yet. + break; } } } // namespace overflow_menu
diff --git a/ios/chrome/browser/popup_menu/overflow_menu/public/overflow_menu_constants.h b/ios/chrome/browser/popup_menu/overflow_menu/public/overflow_menu_constants.h index 4ebb1591..a0b69002 100644 --- a/ios/chrome/browser/popup_menu/overflow_menu/public/overflow_menu_constants.h +++ b/ios/chrome/browser/popup_menu/overflow_menu/public/overflow_menu_constants.h
@@ -23,8 +23,12 @@ WhatsNew = 8, SpotlightDebugger = 9, PriceNotifications = 10, + Cobalt = 11, }; -// LINT.ThenChange(overflow_menu_metrics.h:destination) +// LINT.ThenChange( +// /ios/chrome/browser/popup_menu/overflow_menu/ui/overflow_menu_metrics.h:destination, +// /tools/metrics/histograms/metadata/ios/enums.xml:IOSOverflowMenuDestination +// ) // Represents a type of action (i.e. a row). For example, both the Stop and // Reload actions have an `actionType` of `Reload` as they would both take
diff --git a/ios/chrome/browser/popup_menu/overflow_menu/public/overflow_menu_constants_unittest.mm b/ios/chrome/browser/popup_menu/overflow_menu/public/overflow_menu_constants_unittest.mm index a6a3e12..e633435 100644 --- a/ios/chrome/browser/popup_menu/overflow_menu/public/overflow_menu_constants_unittest.mm +++ b/ios/chrome/browser/popup_menu/overflow_menu/public/overflow_menu_constants_unittest.mm
@@ -53,6 +53,9 @@ finalExpectedDestination = overflow_menu::Destination::SpotlightDebugger; break; + case overflow_menu::Destination::Cobalt: + finalExpectedDestination = overflow_menu::Destination::Cobalt; + break; } // If there's no finalExpectedDestination, then the loop has looped through
diff --git a/ios/chrome/browser/popup_menu/overflow_menu/ui/overflow_menu_metrics.h b/ios/chrome/browser/popup_menu/overflow_menu/ui/overflow_menu_metrics.h index 13ce733..af9f7df 100644 --- a/ios/chrome/browser/popup_menu/overflow_menu/ui/overflow_menu_metrics.h +++ b/ios/chrome/browser/popup_menu/overflow_menu/ui/overflow_menu_metrics.h
@@ -59,9 +59,13 @@ kWhatsNew = 8, kSpotlightDebugger = 9, kPriceNotifications = 10, - kMaxValue = kPriceNotifications, + kCobalt = 11, + kMaxValue = kCobalt, }; -// LINT.ThenChange(overflow_menu_constants.h:destination) +// LINT.ThenChange( +// /ios/chrome/browser/popup_menu/overflow_menu/public/overflow_menu_constants.h:destination, +// /tools/metrics/histograms/metadata/ios/enums.xml:IOSOverflowMenuDestination +// ) // Returns the correct destination histogram enum value for the given // `destination`.
diff --git a/ios/chrome/browser/popup_menu/overflow_menu/ui/overflow_menu_metrics.mm b/ios/chrome/browser/popup_menu/overflow_menu/ui/overflow_menu_metrics.mm index 92a42796..ca67b78 100644 --- a/ios/chrome/browser/popup_menu/overflow_menu/ui/overflow_menu_metrics.mm +++ b/ios/chrome/browser/popup_menu/overflow_menu/ui/overflow_menu_metrics.mm
@@ -33,6 +33,8 @@ return IOSOverflowMenuDestination::kSpotlightDebugger; case overflow_menu::Destination::PriceNotifications: return IOSOverflowMenuDestination::kPriceNotifications; + case overflow_menu::Destination::Cobalt: + return IOSOverflowMenuDestination::kCobalt; } }
diff --git a/ios/chrome/browser/providers/BUILD.gn b/ios/chrome/browser/providers/BUILD.gn index f21d98e..dce0f84 100644 --- a/ios/chrome/browser/providers/BUILD.gn +++ b/ios/chrome/browser/providers/BUILD.gn
@@ -40,6 +40,7 @@ "//ios/chrome/browser/providers/raccoon:chromium_raccoon", "//ios/chrome/browser/providers/risk_data:chromium_risk_data", "//ios/chrome/browser/providers/safari_data_import:chromium_safari_data_import", + "//ios/chrome/browser/providers/screenshot_protection:chromium_screenshot_protection", "//ios/chrome/browser/providers/share_kit:chromium_share_kit", "//ios/chrome/browser/providers/signin:chromium_choice", "//ios/chrome/browser/providers/signin:chromium_signin_error",
diff --git a/ios/chrome/browser/providers/screenshot_protection/BUILD.gn b/ios/chrome/browser/providers/screenshot_protection/BUILD.gn new file mode 100644 index 0000000..80d315b --- /dev/null +++ b/ios/chrome/browser/providers/screenshot_protection/BUILD.gn
@@ -0,0 +1,8 @@ +# Copyright 2026 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +source_set("chromium_screenshot_protection") { + sources = [ "chromium_screenshot_protection.mm" ] + deps = [ "//ios/public/provider/chrome/browser/screenshot_protection:screenshot_protection_api" ] +}
diff --git a/ios/chrome/browser/providers/screenshot_protection/chromium_screenshot_protection.mm b/ios/chrome/browser/providers/screenshot_protection/chromium_screenshot_protection.mm new file mode 100644 index 0000000..e257a7bd --- /dev/null +++ b/ios/chrome/browser/providers/screenshot_protection/chromium_screenshot_protection.mm
@@ -0,0 +1,17 @@ +// Copyright 2026 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/public/provider/chrome/browser/screenshot_protection/screenshot_protection_api.h" + +namespace ios { +namespace provider { + +void SetScreenshotProtection(UIView* view, + ScreenshotProtectionOptions options) { + // Screenshot protection is not supported in the public Chromium + // implementation. This is a no-op stub. +} + +} // namespace provider +} // namespace ios
diff --git a/ios/chrome/browser/settings/autofill/autofill_ai/OWNERS b/ios/chrome/browser/settings/autofill/autofill_ai/OWNERS new file mode 100644 index 0000000..3c939ab9 --- /dev/null +++ b/ios/chrome/browser/settings/autofill/autofill_ai/OWNERS
@@ -0,0 +1 @@ +leozhao@google.com
diff --git a/ios/chrome/browser/shared/model/url/chrome_url_constants.h b/ios/chrome/browser/shared/model/url/chrome_url_constants.h index 1d0f89cd..41c8278 100644 --- a/ios/chrome/browser/shared/model/url/chrome_url_constants.h +++ b/ios/chrome/browser/shared/model/url/chrome_url_constants.h
@@ -36,6 +36,7 @@ inline constexpr char kChromeUIPolicyURL[] = "chrome://policy/"; inline constexpr char kChromeUIPolicyLogsURL[] = "chrome://policy/logs"; inline constexpr char kChromeUIPolicyTestURL[] = "chrome://policy/test"; +inline constexpr char kChromeUISafeBrowsingURL[] = "chrome://safe-browsing"; inline constexpr char kChromeUISettingsURL[] = "chrome://settings/"; inline constexpr char kChromeUITermsURL[] = "chrome://terms/"; inline constexpr char kChromeUIVersionURL[] = "chrome://version/"; @@ -75,6 +76,7 @@ inline constexpr char kChromeUIPolicyHost[] = "policy"; inline constexpr char kChromeUIPrefsInternalsHost[] = "prefs-internals"; inline constexpr char kChromeUIProfileInternalsHost[] = "profile-internals"; +inline constexpr char kChromeUISafeBrowsingHost[] = "safe-browsing"; inline constexpr char kChromeUISignInInternalsHost[] = "signin-internals"; inline constexpr char kChromeUITermsHost[] = "terms"; inline constexpr char kChromeUITranslateInternalsHost[] = "translate-internals";
diff --git a/ios/chrome/browser/webui/ui_bundled/chrome_web_ui_ios_controller_factory.mm b/ios/chrome/browser/webui/ui_bundled/chrome_web_ui_ios_controller_factory.mm index de476d8f..95681c6a 100644 --- a/ios/chrome/browser/webui/ui_bundled/chrome_web_ui_ios_controller_factory.mm +++ b/ios/chrome/browser/webui/ui_bundled/chrome_web_ui_ios_controller_factory.mm
@@ -16,6 +16,7 @@ #import "components/optimization_guide/optimization_guide_buildflags.h" #import "components/optimization_guide/optimization_guide_internals/webui/url_constants.h" #import "components/prefs/pref_service.h" +#import "components/safe_browsing/ios/browser/web_ui/safe_browsing_ui.h" #import "components/version_info/channel.h" #import "components/webui/chrome_urls/pref_names.h" #import "components/webui/regional_capabilities_internals/constants.h" @@ -181,6 +182,9 @@ ? &NewWebUIIOS<ProfileInternalsUI> : &NewWebUIIOS<InternalDebugPagesDisabledUI>; } + if (url_host == kChromeUISafeBrowsingHost) { + return &NewWebUIIOS<safe_browsing::SafeBrowsingUI>; + } if (url_host == kChromeUISignInInternalsHost) { return &NewWebUIIOS<SignInInternalsUIIOS>; }
diff --git a/ios/chrome/test/earl_grey2/BUILD.gn b/ios/chrome/test/earl_grey2/BUILD.gn index a717850..251c1f1 100644 --- a/ios/chrome/test/earl_grey2/BUILD.gn +++ b/ios/chrome/test/earl_grey2/BUILD.gn
@@ -274,6 +274,11 @@ "//ios/chrome/browser/webui/ui_bundled/interstitials:eg2_tests", "//ios/chrome/browser/webui/ui_bundled/optimization_guide_internals:eg2_tests", ] + + if (target_environment == "device") { + deps += [ "//ios/chrome/browser/picture_in_picture/test:eg2_tests" ] + } + data_deps = [ ":ios_chrome_eg2tests" ] }
diff --git a/ios/chrome/test/providers/BUILD.gn b/ios/chrome/test/providers/BUILD.gn index 138cf719..15c45009 100644 --- a/ios/chrome/test/providers/BUILD.gn +++ b/ios/chrome/test/providers/BUILD.gn
@@ -41,6 +41,7 @@ "//ios/chrome/test/providers/raccoon", "//ios/chrome/test/providers/risk_data", "//ios/chrome/test/providers/safari_data_import", + "//ios/chrome/test/providers/screenshot_protection", "//ios/chrome/test/providers/share_kit", "//ios/chrome/test/providers/signin", "//ios/chrome/test/providers/text_zoom",
diff --git a/ios/chrome/test/providers/screenshot_protection/BUILD.gn b/ios/chrome/test/providers/screenshot_protection/BUILD.gn new file mode 100644 index 0000000..84b8d5c --- /dev/null +++ b/ios/chrome/test/providers/screenshot_protection/BUILD.gn
@@ -0,0 +1,9 @@ +# Copyright 2026 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +source_set("screenshot_protection") { + testonly = true + sources = [ "test_screenshot_protection.mm" ] + deps = [ "//ios/public/provider/chrome/browser/screenshot_protection:screenshot_protection_api" ] +}
diff --git a/ios/chrome/test/providers/screenshot_protection/test_screenshot_protection.mm b/ios/chrome/test/providers/screenshot_protection/test_screenshot_protection.mm new file mode 100644 index 0000000..3aa1ec0 --- /dev/null +++ b/ios/chrome/test/providers/screenshot_protection/test_screenshot_protection.mm
@@ -0,0 +1,17 @@ +// Copyright 2026 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/public/provider/chrome/browser/screenshot_protection/screenshot_protection_api.h" + +namespace ios { +namespace provider { + +void SetScreenshotProtection(UIView* view, + ScreenshotProtectionOptions options) { + // The test provider does nothing by default to avoid side effects on the test + // runner. +} + +} // namespace provider +} // namespace ios
diff --git a/ios/public/provider/chrome/browser/BUILD.gn b/ios/public/provider/chrome/browser/BUILD.gn index ec066d9..61e9241 100644 --- a/ios/public/provider/chrome/browser/BUILD.gn +++ b/ios/public/provider/chrome/browser/BUILD.gn
@@ -34,6 +34,7 @@ "//ios/public/provider/chrome/browser/raccoon:raccoon_api", "//ios/public/provider/chrome/browser/risk_data:risk_data_api", "//ios/public/provider/chrome/browser/safari_data_import:safari_data_import_api", + "//ios/public/provider/chrome/browser/screenshot_protection:screenshot_protection_api", "//ios/public/provider/chrome/browser/signin:signin_error_api", "//ios/public/provider/chrome/browser/signin:signin_identity_api", "//ios/public/provider/chrome/browser/signin:signin_resources_api",
diff --git a/ios/public/provider/chrome/browser/screenshot_protection/BUILD.gn b/ios/public/provider/chrome/browser/screenshot_protection/BUILD.gn new file mode 100644 index 0000000..fb413ffe --- /dev/null +++ b/ios/public/provider/chrome/browser/screenshot_protection/BUILD.gn
@@ -0,0 +1,7 @@ +# Copyright 2026 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +source_set("screenshot_protection_api") { + sources = [ "screenshot_protection_api.h" ] +}
diff --git a/ios/public/provider/chrome/browser/screenshot_protection/screenshot_protection_api.h b/ios/public/provider/chrome/browser/screenshot_protection/screenshot_protection_api.h new file mode 100644 index 0000000..3c65db77 --- /dev/null +++ b/ios/public/provider/chrome/browser/screenshot_protection/screenshot_protection_api.h
@@ -0,0 +1,29 @@ +// Copyright 2026 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_PUBLIC_PROVIDER_CHROME_BROWSER_SCREENSHOT_PROTECTION_SCREENSHOT_PROTECTION_API_H_ +#define IOS_PUBLIC_PROVIDER_CHROME_BROWSER_SCREENSHOT_PROTECTION_SCREENSHOT_PROTECTION_API_H_ + +#import <UIKit/UIKit.h> + +namespace ios { +namespace provider { + +// Options for content obfuscation. +struct ScreenshotProtectionOptions { + // If true, the view's content will be hidden in system screenshots. + bool obfuscate_screenshots = false; + + // If true, the view's content will be hidden during system + // screen capturing + bool obfuscate_screen_recordings = false; +}; + +// Applies protection to `view` based on the provided `options`. +void SetScreenshotProtection(UIView* view, ScreenshotProtectionOptions options); + +} // namespace provider +} // namespace ios + +#endif // IOS_PUBLIC_PROVIDER_CHROME_BROWSER_SCREENSHOT_PROTECTION_SCREENSHOT_PROTECTION_API_H_
diff --git a/media/base/BUILD.gn b/media/base/BUILD.gn index 2c82170..59e41f5 100644 --- a/media/base/BUILD.gn +++ b/media/base/BUILD.gn
@@ -523,7 +523,6 @@ source_set("video_facing") { sources = [ "video_facing.h" ] - deps = [ "//base" ] } if (is_android) {
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc index f84d6f7c..f5fd813 100644 --- a/media/base/media_switches.cc +++ b/media/base/media_switches.cc
@@ -879,9 +879,6 @@ // Enable or disable Live Caption support for WebAudio. BASE_FEATURE(kLiveCaptionWebAudio, base::FEATURE_ENABLED_BY_DEFAULT); -// Live Translate translates captions generated by Live Caption. -BASE_FEATURE(kLiveTranslate, base::FEATURE_ENABLED_BY_DEFAULT); - // Prevents UrlProvisionFetcher from making a provisioning request. If // specified, any provisioning request made will not be sent to the provisioning // server, and the response will indicate a failure to communicate with the @@ -1604,7 +1601,12 @@ // playback when the media goes to background to avoid wasting CPU power on // decoding audio that cannot be heard. This flag will be switched on gradually // via Finch. +#if BUILDFLAG(IS_ANDROID) BASE_FEATURE(kPauseMutedBackgroundAudio, base::FEATURE_ENABLED_BY_DEFAULT); +#else +BASE_FEATURE(kPauseMutedBackgroundAudio, base::FEATURE_DISABLED_BY_DEFAULT); +#endif + // Controls headless Live Caption experiment, which is likely unstable. BASE_FEATURE(kHeadlessLiveCaption, base::FEATURE_DISABLED_BY_DEFAULT); @@ -1789,10 +1791,9 @@ bool IsLiveTranslateEnabled() { #if BUILDFLAG(IS_CHROMEOS) - return base::FeatureList::IsEnabled(kLiveTranslate) && - base::FeatureList::IsEnabled(kFeatureManagementLiveTranslateCrOS); + return base::FeatureList::IsEnabled(kFeatureManagementLiveTranslateCrOS); #else - return base::FeatureList::IsEnabled(kLiveTranslate); + return true; #endif }
diff --git a/media/base/media_switches.h b/media/base/media_switches.h index 6cd5a91e..cdf3d9f 100644 --- a/media/base/media_switches.h +++ b/media/base/media_switches.h
@@ -260,7 +260,6 @@ MEDIA_EXPORT BASE_DECLARE_FEATURE(kLiveCaptionUseGreedyTextStabilizer); MEDIA_EXPORT BASE_DECLARE_FEATURE(kLiveCaptionUseWaitK); MEDIA_EXPORT BASE_DECLARE_FEATURE(kLiveCaptionWebAudio); -MEDIA_EXPORT BASE_DECLARE_FEATURE(kLiveTranslate); MEDIA_EXPORT BASE_DECLARE_FEATURE(kLogSodaLoadFailures); #if BUILDFLAG(IS_WIN) MEDIA_EXPORT BASE_DECLARE_FEATURE(kApplicationAudioCaptureWin);
diff --git a/media/base/video_facing.h b/media/base/video_facing.h index 97c9eee..202a307 100644 --- a/media/base/video_facing.h +++ b/media/base/video_facing.h
@@ -5,8 +5,6 @@ #ifndef MEDIA_BASE_VIDEO_FACING_H_ #define MEDIA_BASE_VIDEO_FACING_H_ -#include "base/observer_list_types.h" - namespace media { // Facing mode for video capture. @@ -22,13 +20,11 @@ // Clients interested in video capture events can implement this interface // and register the observers to MediaStreamManager or VideoCaptureManager. -class VideoCaptureObserver : public base::CheckedObserver { +class VideoCaptureObserver { public: + virtual ~VideoCaptureObserver() {} virtual void OnVideoCaptureStarted(VideoFacingMode facing) = 0; virtual void OnVideoCaptureStopped(VideoFacingMode facing) = 0; - - protected: - ~VideoCaptureObserver() override = default; }; } // namespace media
diff --git a/media/capture/BUILD.gn b/media/capture/BUILD.gn index 84e6e4e..2f6eb8e 100644 --- a/media/capture/BUILD.gn +++ b/media/capture/BUILD.gn
@@ -2,7 +2,6 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -import("//build/config/apple/mobile_config.gni") import("//build/config/ui.gni") import("//media/media_options.gni") import("//testing/test.gni") @@ -57,9 +56,12 @@ visibility = [ ":capture_lib", "//media/capture/video/android", + "//media/capture/video/apple", "//media/capture/video/chromeos", "//media/capture/video/fuchsia", + "//media/capture/video/ios", "//media/capture/video/linux", + "//media/capture/video/mac", "//media/capture/video/win", ] defines = [ "CAPTURE_IMPLEMENTATION" ] @@ -169,6 +171,8 @@ "//third_party/libyuv", "//ui/display", "//ui/gfx", + "//ui/gfx:color_space", + "//ui/gfx/geometry", ] if (is_android) { @@ -177,64 +181,7 @@ } if (is_apple) { - sources += [ - "video/apple/gpu_memory_buffer_tracker_apple.cc", - "video/apple/gpu_memory_buffer_tracker_apple.h", - "video/apple/pixel_buffer_pool.h", - "video/apple/pixel_buffer_pool.mm", - "video/apple/pixel_buffer_transferer.cc", - "video/apple/pixel_buffer_transferer.h", - "video/apple/sample_buffer_transformer.cc", - "video/apple/sample_buffer_transformer.h", - ] - if (target_platform != "tvos") { - sources += [ - "video/apple/video_capture_device_apple.h", - "video/apple/video_capture_device_apple.mm", - "video/apple/video_capture_device_avfoundation.h", - "video/apple/video_capture_device_avfoundation.mm", - "video/apple/video_capture_device_avfoundation_utils.h", - "video/apple/video_capture_device_avfoundation_utils.mm", - "video/apple/video_capture_device_factory_apple.h", - "video/apple/video_capture_device_factory_apple.mm", - "video/apple/video_capture_device_frame_receiver.h", - ] - } - deps += [ "//components/crash/core/common:crash_key" ] - frameworks = [ - "AVFoundation.framework", - "CoreFoundation.framework", - "CoreGraphics.framework", - "CoreMedia.framework", - "CoreVideo.framework", - "Foundation.framework", - "IOSurface.framework", - "VideoToolbox.framework", - ] - } - - if (is_mac) { - sources += [ - "video/mac/uvc_control_mac.h", - "video/mac/uvc_control_mac.mm", - "video/mac/video_capture_device_decklink_mac.h", - "video/mac/video_capture_device_decklink_mac.mm", - "video/mac/video_capture_metrics_mac.h", - "video/mac/video_capture_metrics_mac.mm", - ] - deps += [ "//third_party/decklink" ] - frameworks += [ - # Needed for the logging of camera information for - # https://crbug.com/461717105; remove when that logging is removed. - "CoreMediaIO.framework", - ] - } - - if (is_ios) { - sources += [ - "video/ios/pixel_buffer_rotator.cc", - "video/ios/pixel_buffer_rotator.h", - ] + public_deps += [ "video/apple" ] } if (is_win) { @@ -253,10 +200,6 @@ if (is_fuchsia) { deps += [ "video/fuchsia" ] } - - # TODO(crbug.com/40031409): Fix code that adds exit-time destructors and - # enable the diagnostic by removing this line. - configs += [ "//build/config/compiler:no_exit_time_destructors" ] } source_set("capture_gpu_channel") { @@ -305,20 +248,12 @@ "//ui/gfx:test_support", ] - if (is_linux) { - public_deps = [ "video/linux:test_support" ] - } - - if (is_mac) { - sources += [ - "video/mac/test/screen_capture_kit_test_helper.h", - "video/mac/test/screen_capture_kit_test_helper.mm", - ] - weak_frameworks = [ "ScreenCaptureKit.framework" ] - } - if (is_chromeos) { public_deps = [ "video/chromeos:test_support" ] + } else if (is_linux) { + public_deps = [ "video/linux:test_support" ] + } else if (is_mac) { + public_deps = [ "video/mac/test:test_support" ] } testonly = true @@ -358,6 +293,7 @@ "//testing/gmock", "//testing/gtest", "//third_party/libyuv", + "//ui/gfx:color_space", "//ui/gfx:test_support", ] @@ -380,33 +316,11 @@ } if (is_apple) { - sources += [ - "video/apple/pixel_buffer_pool_unittest.mm", - "video/apple/pixel_buffer_transferer_unittest.mm", - "video/apple/sample_buffer_transformer_unittest.mm", - "video/apple/test/fake_av_capture_device_format.h", - "video/apple/test/fake_av_capture_device_format.mm", - "video/apple/test/mock_video_capture_device_avfoundation_frame_receiver.h", - "video/apple/test/mock_video_capture_device_avfoundation_frame_receiver.mm", - "video/apple/test/pixel_buffer_test_utils.cc", - "video/apple/test/pixel_buffer_test_utils.h", - "video/apple/test/video_capture_test_utils.h", - "video/apple/test/video_capture_test_utils.mm", - "video/apple/video_capture_device_apple_unittest.mm", - "video/apple/video_capture_device_avfoundation_unittest.mm", - "video/apple/video_capture_device_factory_unittest.mm", - ] - frameworks = [ - "IOSurface.framework", - "AVFoundation.framework", - "CoreMedia.framework", - "CoreVideo.framework", - ] + deps += [ "video/apple:unit_tests" ] } if (is_mac) { - sources += [ "video/mac/video_capture_metrics_mac_unittest.mm" ] - deps += [ "//third_party/ocmock" ] + deps += [ "video/mac:unit_tests" ] } if (is_ios) {
diff --git a/media/capture/video/apple/BUILD.gn b/media/capture/video/apple/BUILD.gn new file mode 100644 index 0000000..8103fcd --- /dev/null +++ b/media/capture/video/apple/BUILD.gn
@@ -0,0 +1,122 @@ +# Copyright 2026 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//build/config/apple/mobile_config.gni") + +assert(is_apple) + +source_set("apple") { + visibility = [ + ":unit_tests", + "//media/capture:capture_lib", + "//media/capture/video/apple/test:test_support", + ] + defines = [ "CAPTURE_IMPLEMENTATION" ] + + sources = [ + "gpu_memory_buffer_tracker_apple.cc", + "gpu_memory_buffer_tracker_apple.h", + "pixel_buffer_pool.h", + "pixel_buffer_pool.mm", + "pixel_buffer_transferer.cc", + "pixel_buffer_transferer.h", + "sample_buffer_transformer.cc", + "sample_buffer_transformer.h", + ] + + if (target_platform != "tvos") { + sources += [ + "video_capture_device_apple.h", + "video_capture_device_apple.mm", + "video_capture_device_avfoundation.h", + "video_capture_device_avfoundation.mm", + "video_capture_device_avfoundation_utils.h", + "video_capture_device_avfoundation_utils.mm", + "video_capture_device_factory_apple.h", + "video_capture_device_factory_apple.mm", + "video_capture_device_frame_receiver.h", + ] + } + + deps = [ + "//base", + "//media", + "//media/capture:capture_base", + "//media/capture:capture_device_specific", + "//media/capture:capture_switches", + "//media/capture/mojom:image_capture", + "//media/capture/mojom:image_capture_types", + "//media/capture/mojom:video_capture", + "//third_party/libyuv", + "//ui/gfx", + "//ui/gfx:color_space", + "//ui/gfx/geometry", + ] + + if (target_platform != "tvos") { + deps += [ "//components/crash/core/common:crash_key" ] + } + + if (is_mac) { + deps += [ "//media/capture/video/mac" ] + } + + if (is_ios) { + deps += [ "//media/capture/video/ios" ] + } + + frameworks = [ + "AVFoundation.framework", + "CoreFoundation.framework", + "CoreGraphics.framework", + "CoreMedia.framework", + "CoreVideo.framework", + "Foundation.framework", + "IOSurface.framework", + "VideoToolbox.framework", + ] + + if (is_ios) { + frameworks += [ "UIKit.framework" ] + } +} + +source_set("unit_tests") { + visibility = [ "//media/capture:capture_unittests" ] + testonly = true + + sources = [ + "pixel_buffer_pool_unittest.mm", + "pixel_buffer_transferer_unittest.mm", + "sample_buffer_transformer_unittest.mm", + "video_capture_device_apple_unittest.mm", + "video_capture_device_avfoundation_unittest.mm", + "video_capture_device_factory_unittest.mm", + ] + + deps = [ + ":apple", + "test:test_support", + "//base/test:test_support", + "//media", + "//media/capture:test_support", + "//testing/gmock", + "//testing/gtest", + "//third_party/libyuv", + "//ui/gfx:color_space", + ] + + frameworks = [ + "AVFoundation.framework", + "CoreMedia.framework", + "CoreVideo.framework", + "Foundation.framework", + "IOSurface.framework", + "VideoToolbox.framework", + ] + + if (is_ios) { + frameworks += [ "UIKit.framework" ] + } +}
diff --git a/media/capture/video/apple/sample_buffer_transformer.cc b/media/capture/video/apple/sample_buffer_transformer.cc index f3def38..afa905f 100644 --- a/media/capture/video/apple/sample_buffer_transformer.cc +++ b/media/capture/video/apple/sample_buffer_transformer.cc
@@ -12,9 +12,15 @@ #include "base/notreached.h" #include "media/base/video_frame.h" #include "media/base/video_types.h" +#include "media/capture/video/apple/pixel_buffer_pool.h" +#include "media/capture/video/apple/pixel_buffer_transferer.h" #include "third_party/libyuv/include/libyuv.h" #include "third_party/libyuv/include/libyuv/scale.h" +#if BUILDFLAG(IS_IOS) +#include "media/capture/video/ios/pixel_buffer_rotator.h" +#endif + namespace media { namespace {
diff --git a/media/capture/video/apple/sample_buffer_transformer.h b/media/capture/video/apple/sample_buffer_transformer.h index 1b144c8..0bc094e 100644 --- a/media/capture/video/apple/sample_buffer_transformer.h +++ b/media/capture/video/apple/sample_buffer_transformer.h
@@ -12,16 +12,17 @@ #include "base/apple/scoped_cftyperef.h" #include "media/capture/capture_export.h" -#include "media/capture/video/apple/pixel_buffer_pool.h" -#include "media/capture/video/apple/pixel_buffer_transferer.h" #include "ui/gfx/geometry/size.h" #if BUILDFLAG(IS_IOS) -#include "media/capture/video/ios/pixel_buffer_rotator.h" +class PixelBufferRotator; #endif namespace media { +class PixelBufferPool; +class PixelBufferTransferer; + // Capable of converting from any supported capture format (NV12, YUY2, UYVY and // MJPEG) to NV12 or I420 and doing rescaling. This class can be configured to // use VTPixelTransferSession (sometimes HW-accelerated) or third_party/libyuv
diff --git a/media/capture/video/apple/sample_buffer_transformer_unittest.mm b/media/capture/video/apple/sample_buffer_transformer_unittest.mm index 46401c0..a689432 100644 --- a/media/capture/video/apple/sample_buffer_transformer_unittest.mm +++ b/media/capture/video/apple/sample_buffer_transformer_unittest.mm
@@ -15,6 +15,8 @@ #include "base/logging.h" #include "base/mac/mac_util.h" #include "build/build_config.h" +#include "media/capture/video/apple/pixel_buffer_pool.h" +#include "media/capture/video/apple/pixel_buffer_transferer.h" #include "media/capture/video/apple/test/pixel_buffer_test_utils.h" #include "media/capture/video/apple/video_capture_device_avfoundation_utils.h" #include "testing/gmock/include/gmock/gmock.h"
diff --git a/media/capture/video/apple/test/BUILD.gn b/media/capture/video/apple/test/BUILD.gn new file mode 100644 index 0000000..d0376d5 --- /dev/null +++ b/media/capture/video/apple/test/BUILD.gn
@@ -0,0 +1,43 @@ +# Copyright 2026 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +assert(is_apple) + +source_set("test_support") { + visibility = [ "//media/capture/video/apple:unit_tests" ] + testonly = true + + sources = [ + "fake_av_capture_device_format.h", + "fake_av_capture_device_format.mm", + "mock_video_capture_device_avfoundation_frame_receiver.h", + "mock_video_capture_device_avfoundation_frame_receiver.mm", + "pixel_buffer_test_utils.cc", + "pixel_buffer_test_utils.h", + "video_capture_test_utils.h", + "video_capture_test_utils.mm", + ] + + deps = [ + "//base", + "//base/test:test_support", + "//media", + "//media/capture/video/apple", + "//testing/gmock", + "//third_party/libyuv", + ] + + frameworks = [ + "AVFoundation.framework", + "CoreMedia.framework", + "CoreVideo.framework", + "Foundation.framework", + "IOSurface.framework", + "VideoToolbox.framework", + ] + + if (is_ios) { + frameworks += [ "UIKit.framework" ] + } +}
diff --git a/media/capture/video/apple/test/video_capture_test_utils.mm b/media/capture/video/apple/test/video_capture_test_utils.mm index c8d90fb5..947b02a 100644 --- a/media/capture/video/apple/test/video_capture_test_utils.mm +++ b/media/capture/video/apple/test/video_capture_test_utils.mm
@@ -10,7 +10,6 @@ #include "base/run_loop.h" #include "base/strings/sys_string_conversions.h" -#import "base/task/single_thread_task_runner.h" #include "base/task/single_thread_task_runner.h" #include "base/test/bind.h" #include "base/test/gmock_callback_support.h"
diff --git a/media/capture/video/apple/video_capture_device_apple.h b/media/capture/video/apple/video_capture_device_apple.h index 657443a..8b23902f4 100644 --- a/media/capture/video/apple/video_capture_device_apple.h +++ b/media/capture/video/apple/video_capture_device_apple.h
@@ -10,14 +10,13 @@ #import <Foundation/Foundation.h> #include <stdint.h> -#include "base/time/time.h" #include <string> -#include "base/compiler_specific.h" #include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" -#import "media/capture/video/apple/video_capture_device_avfoundation.h" +#include "base/time/time.h" +#include "media/capture/video/apple/video_capture_device_frame_receiver.h" #include "media/capture/video/video_capture_device.h" #include "media/capture/video_capture_types.h" @@ -29,6 +28,8 @@ class Location; } // namespace base +@class VideoCaptureDeviceAVFoundation; + // Small class to bundle device name and connection type into a dictionary. CAPTURE_EXPORT @interface DeviceNameAndTransportType : NSObject
diff --git a/media/capture/video/apple/video_capture_device_apple.mm b/media/capture/video/apple/video_capture_device_apple.mm index 9710c20..93c76b0 100644 --- a/media/capture/video/apple/video_capture_device_apple.mm +++ b/media/capture/video/apple/video_capture_device_apple.mm
@@ -19,7 +19,6 @@ #include "base/location.h" #include "base/logging.h" #include "base/strings/sys_string_conversions.h" -#import "base/task/single_thread_task_runner.h" #include "base/task/single_thread_task_runner.h" #include "base/time/time.h" #include "base/trace_event/trace_event.h"
diff --git a/media/capture/video/apple/video_capture_device_apple_unittest.mm b/media/capture/video/apple/video_capture_device_apple_unittest.mm index 35a03dc9..f54b0ee 100644 --- a/media/capture/video/apple/video_capture_device_apple_unittest.mm +++ b/media/capture/video/apple/video_capture_device_apple_unittest.mm
@@ -12,6 +12,7 @@ #include "base/test/gmock_callback_support.h" #include "media/capture/video/apple/test/fake_av_capture_device_format.h" #import "media/capture/video/apple/test/video_capture_test_utils.h" +#include "media/capture/video/apple/video_capture_device_avfoundation.h" #include "media/capture/video/apple/video_capture_device_avfoundation_utils.h" #include "media/capture/video/apple/video_capture_device_factory_apple.h" #include "media/capture/video/apple/video_capture_device_frame_receiver.h"
diff --git a/media/capture/video/apple/video_capture_device_avfoundation.h b/media/capture/video/apple/video_capture_device_avfoundation.h index 22530e0..3883b339 100644 --- a/media/capture/video/apple/video_capture_device_avfoundation.h +++ b/media/capture/video/apple/video_capture_device_avfoundation.h
@@ -9,17 +9,16 @@ #import <Foundation/Foundation.h> #include "base/functional/callback_forward.h" -#include "base/synchronization/lock.h" -#include "base/task/single_thread_task_runner.h" -#include "base/threading/thread_checker.h" #include "base/time/time.h" -#include "media/capture/video/apple/sample_buffer_transformer.h" -#include "media/capture/video/apple/video_capture_device_frame_receiver.h" -#include "media/capture/video/video_capture_device.h" +#include "media/base/video_types.h" +#include "media/capture/capture_export.h" #include "media/capture/video_capture_types.h" +#include "ui/gfx/color_space.h" namespace media { +class VideoCaptureDeviceAVFoundationFrameReceiver; + // Find the best capture format from |formats| for the specified dimensions and // frame rate. Returns an element of |formats|, or nil. AVCaptureDeviceFormat* CAPTURE_EXPORT
diff --git a/media/capture/video/apple/video_capture_device_avfoundation.mm b/media/capture/video/apple/video_capture_device_avfoundation.mm index 186580b..719d212 100644 --- a/media/capture/video/apple/video_capture_device_avfoundation.mm +++ b/media/capture/video/apple/video_capture_device_avfoundation.mm
@@ -34,6 +34,7 @@ #include "media/base/mac/color_space_util_mac.h" #include "media/base/timestamp_constants.h" #include "media/base/video_types.h" +#include "media/capture/video/apple/sample_buffer_transformer.h" #include "media/capture/video/apple/video_capture_device_apple.h" #import "media/capture/video/apple/video_capture_device_avfoundation_utils.h" #include "media/capture/video/apple/video_capture_device_factory_apple.h"
diff --git a/media/capture/video/apple/video_capture_device_avfoundation_utils.h b/media/capture/video/apple/video_capture_device_avfoundation_utils.h index 151a9e9f5..4adbc82 100644 --- a/media/capture/video/apple/video_capture_device_avfoundation_utils.h +++ b/media/capture/video/apple/video_capture_device_avfoundation_utils.h
@@ -5,20 +5,20 @@ #ifndef MEDIA_CAPTURE_VIDEO_APPLE_VIDEO_CAPTURE_DEVICE_AVFOUNDATION_UTILS_H_ #define MEDIA_CAPTURE_VIDEO_APPLE_VIDEO_CAPTURE_DEVICE_AVFOUNDATION_UTILS_H_ -#import <AVFoundation/AVFoundation.h> #import <CoreMedia/CoreMedia.h> #import <CoreVideo/CoreVideo.h> -#include "media/capture/video/apple/video_capture_device_apple.h" -#include "media/capture/video/video_capture_device_descriptor.h" -#include "media/capture/video_capture_types.h" +#include <optional> +#include <string> + +#include "media/capture/capture_export.h" +#include "ui/gfx/geometry/size.h" #if BUILDFLAG(IS_IOS) +#import <AVFoundation/AVFoundation.h> #import <UIKit/UIKit.h> #endif -@class DeviceNameAndTransportType; - namespace media { std::string CAPTURE_EXPORT MacFourCCToString(OSType fourcc);
diff --git a/media/capture/video/apple/video_capture_device_avfoundation_utils.mm b/media/capture/video/apple/video_capture_device_avfoundation_utils.mm index f9e7afb..ddfd08caa 100644 --- a/media/capture/video/apple/video_capture_device_avfoundation_utils.mm +++ b/media/capture/video/apple/video_capture_device_avfoundation_utils.mm
@@ -4,21 +4,12 @@ #include "media/capture/video/apple/video_capture_device_avfoundation_utils.h" -#include "base/mac/mac_util.h" -#include "base/metrics/histogram_macros.h" -#include "base/strings/string_util.h" -#include "base/strings/sys_string_conversions.h" -#include "media/base/mac/video_capture_device_avfoundation_helpers.h" -#include "media/base/media_switches.h" -#include "media/capture/video/apple/video_capture_device_apple.h" -#include "media/capture/video/apple/video_capture_device_avfoundation.h" -#include "media/capture/video/apple/video_capture_device_factory_apple.h" -#include "media/capture/video_capture_types.h" - #if BUILDFLAG(IS_MAC) #import <IOKit/audio/IOAudioTypes.h> #endif +#include "base/check_op.h" + namespace media { std::string MacFourCCToString(OSType fourcc) {
diff --git a/media/capture/video/ios/BUILD.gn b/media/capture/video/ios/BUILD.gn new file mode 100644 index 0000000..aabbc9c --- /dev/null +++ b/media/capture/video/ios/BUILD.gn
@@ -0,0 +1,19 @@ +# Copyright 2026 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +assert(is_ios) + +source_set("ios") { + visibility = [ "//media/capture/video/apple:*" ] + defines = [ "CAPTURE_IMPLEMENTATION" ] + + sources = [ + "pixel_buffer_rotator.cc", + "pixel_buffer_rotator.h", + ] + + deps = [ "//base" ] + + frameworks = [ "VideoToolbox.framework" ] +}
diff --git a/media/capture/video/ios/pixel_buffer_rotator.h b/media/capture/video/ios/pixel_buffer_rotator.h index f698a66f..2301f90 100644 --- a/media/capture/video/ios/pixel_buffer_rotator.h +++ b/media/capture/video/ios/pixel_buffer_rotator.h
@@ -9,7 +9,6 @@ #include "base/apple/scoped_cftyperef.h" #include "media/capture/capture_export.h" -#include "media/capture/video/apple/pixel_buffer_pool.h" namespace media {
diff --git a/media/capture/video/mac/BUILD.gn b/media/capture/video/mac/BUILD.gn new file mode 100644 index 0000000..9875954 --- /dev/null +++ b/media/capture/video/mac/BUILD.gn
@@ -0,0 +1,59 @@ +# Copyright 2026 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +assert(is_mac) + +source_set("mac") { + visibility = [ + ":unit_tests", + "//media/capture:test_support", + "//media/capture/video/apple:*", + ] + defines = [ "CAPTURE_IMPLEMENTATION" ] + + sources = [ + "uvc_control_mac.h", + "uvc_control_mac.mm", + "video_capture_device_decklink_mac.h", + "video_capture_device_decklink_mac.mm", + "video_capture_metrics_mac.h", + "video_capture_metrics_mac.mm", + ] + + deps = [ + "//base", + "//media", + "//media/capture:capture_base", + "//media/capture:capture_device_specific", + "//media/capture:capture_switches", + "//media/capture/mojom:image_capture", + "//media/capture/mojom:image_capture_types", + "//media/capture/mojom:video_capture", + "//third_party/decklink", + "//ui/gfx", + ] + + frameworks = [ + "CoreMediaIO.framework", + "IOKit.framework", + ] +} + +source_set("unit_tests") { + visibility = [ "//media/capture:capture_unittests" ] + testonly = true + + sources = [ "video_capture_metrics_mac_unittest.mm" ] + + deps = [ + ":mac", + "//base/test:test_support", + "//media", + "//testing/gmock", + "//testing/gtest", + "//third_party/ocmock", + ] + + frameworks = [ "Foundation.framework" ] +}
diff --git a/media/capture/video/mac/test/BUILD.gn b/media/capture/video/mac/test/BUILD.gn new file mode 100644 index 0000000..6209adf3 --- /dev/null +++ b/media/capture/video/mac/test/BUILD.gn
@@ -0,0 +1,17 @@ +# Copyright 2026 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +assert(is_mac) + +source_set("test_support") { + visibility = [ "//media/capture:test_support" ] + testonly = true + + sources = [ + "screen_capture_kit_test_helper.h", + "screen_capture_kit_test_helper.mm", + ] + + weak_frameworks = [ "ScreenCaptureKit.framework" ] +}
diff --git a/media/capture/video/mac/test/screen_capture_kit_test_helper.h b/media/capture/video/mac/test/screen_capture_kit_test_helper.h index 98d79e67..822603f 100644 --- a/media/capture/video/mac/test/screen_capture_kit_test_helper.h +++ b/media/capture/video/mac/test/screen_capture_kit_test_helper.h
@@ -7,8 +7,6 @@ #import <ScreenCaptureKit/ScreenCaptureKit.h> -#include "base/apple/foundation_util.h" - @interface FakeSCRunningApplication : NSObject @property(readonly) pid_t processID; @property(readonly, copy) NSString* applicationName;
diff --git a/media/capture/video/mac/uvc_control_mac.h b/media/capture/video/mac/uvc_control_mac.h index bbf9ce0..e46030a 100644 --- a/media/capture/video/mac/uvc_control_mac.h +++ b/media/capture/video/mac/uvc_control_mac.h
@@ -5,10 +5,10 @@ #ifndef MEDIA_CAPTURE_VIDEO_MAC_UVC_CONTROL_MAC_H_ #define MEDIA_CAPTURE_VIDEO_MAC_UVC_CONTROL_MAC_H_ -#import <Foundation/Foundation.h> #include <IOKit/usb/IOUSBLib.h> #include <string_view> +#include <vector> #include "base/check.h" #include "base/logging.h"
diff --git a/media/capture/video/mac/video_capture_device_decklink_mac.h b/media/capture/video/mac/video_capture_device_decklink_mac.h index eb679b3..0b25384 100644 --- a/media/capture/video/mac/video_capture_device_decklink_mac.h +++ b/media/capture/video/mac/video_capture_device_decklink_mac.h
@@ -8,14 +8,14 @@ #ifndef MEDIA_CAPTURE_VIDEO_MAC_VIDEO_CAPTURE_DEVICE_DECKLINK_MAC_H_ #define MEDIA_CAPTURE_VIDEO_MAC_VIDEO_CAPTURE_DEVICE_DECKLINK_MAC_H_ -#include "media/capture/video/video_capture_device.h" - -#import <Foundation/Foundation.h> #include <stddef.h> #include <stdint.h> +#include <vector> + #include "base/synchronization/lock.h" #include "base/threading/thread_checker.h" +#include "media/capture/video/video_capture_device.h" namespace { class DeckLinkCaptureDelegate;
diff --git a/media/capture/video/mac/video_capture_metrics_mac.h b/media/capture/video/mac/video_capture_metrics_mac.h index 8cac39b..1f19af5 100644 --- a/media/capture/video/mac/video_capture_metrics_mac.h +++ b/media/capture/video/mac/video_capture_metrics_mac.h
@@ -7,10 +7,8 @@ #import <AVFoundation/AVFoundation.h> #include <CoreMedia/CoreMedia.h> -#import <Foundation/Foundation.h> #include "media/capture/capture_export.h" -#include "ui/gfx/geometry/size.h" namespace media { @@ -25,4 +23,4 @@ } // namespace media -#endif // MEDIA_CAPTURE_VIDEO_MAC_VIDEO_CAPTURE_METRICS_MAC_H_ \ No newline at end of file +#endif // MEDIA_CAPTURE_VIDEO_MAC_VIDEO_CAPTURE_METRICS_MAC_H_
diff --git a/media/capture/video/mac/video_capture_metrics_mac.mm b/media/capture/video/mac/video_capture_metrics_mac.mm index 5412ba9..519fc7e 100644 --- a/media/capture/video/mac/video_capture_metrics_mac.mm +++ b/media/capture/video/mac/video_capture_metrics_mac.mm
@@ -12,9 +12,13 @@ #include "base/apple/bridging.h" #include "base/apple/scoped_cftyperef.h" #include "base/metrics/histogram_functions.h" -#import "media/capture/video/apple/video_capture_device_avfoundation.h" +#include "media/base/video_types.h" #include "media/capture/video/video_capture_device_info.h" +@interface VideoCaptureDeviceAVFoundation : NSObject ++ (media::VideoPixelFormat)FourCCToChromiumPixelFormat:(FourCharCode)code; +@end + @interface AVCaptureDevice (SPI) - (UInt32)connectionID; @end
diff --git a/media/capture/video/win/d3d_capture_test_utils.cc b/media/capture/video/win/d3d_capture_test_utils.cc index 9288ca1..b9a50ed 100644 --- a/media/capture/video/win/d3d_capture_test_utils.cc +++ b/media/capture/video/win/d3d_capture_test_utils.cc
@@ -876,13 +876,6 @@ return E_NOTIMPL; } -IFACEMETHODIMP MockDXGIResource::AcquireSync(UINT64 key, DWORD milliseconds) { - return S_OK; -} -IFACEMETHODIMP MockDXGIResource::ReleaseSync(UINT64 key) { - return S_OK; -} - MockDXGIResource::~MockDXGIResource() {} MockD3D11Texture2D::MockD3D11Texture2D(D3D11_TEXTURE2D_DESC desc, @@ -891,7 +884,7 @@ MockD3D11Texture2D::MockD3D11Texture2D() {} IFACEMETHODIMP MockD3D11Texture2D::QueryInterface(REFIID riid, void** object) { - if (riid == __uuidof(IDXGIResource1) || riid == __uuidof(IDXGIKeyedMutex)) { + if (riid == __uuidof(IDXGIResource1)) { if (!mock_resource_) { mock_resource_ = MakeComPtrFromRefCounted<MockDXGIResource>(); }
diff --git a/media/capture/video/win/d3d_capture_test_utils.h b/media/capture/video/win/d3d_capture_test_utils.h index 20eb501..19a0681 100644 --- a/media/capture/video/win/d3d_capture_test_utils.h +++ b/media/capture/video/win/d3d_capture_test_utils.h
@@ -734,8 +734,7 @@ scoped_refptr<MockDXGIDevice2> mock_dxgi_device2_; }; -class MockDXGIResource final - : public MockInterface<IDXGIResource1, IDXGIKeyedMutex> { +class MockDXGIResource final : public MockInterface<IDXGIResource1> { public: // IDXGIResource1 IFACEMETHODIMP CreateSubresourceSurface(UINT index, IDXGISurface2** surface); @@ -755,9 +754,6 @@ IFACEMETHODIMP SetPrivateDataInterface(REFGUID name, const IUnknown* unknown); IFACEMETHODIMP GetPrivateData(REFGUID name, UINT* data_size, void* data); IFACEMETHODIMP GetParent(REFIID riid, void** parent); - // IDXGIKeyedMutex - IFACEMETHODIMP AcquireSync(UINT64 key, DWORD milliseconds) override; - IFACEMETHODIMP ReleaseSync(UINT64 key) override; private: ~MockDXGIResource() override;
diff --git a/media/capture/video/win/gpu_memory_buffer_tracker_win.cc b/media/capture/video/win/gpu_memory_buffer_tracker_win.cc index b3066db..108bd348 100644 --- a/media/capture/video/win/gpu_memory_buffer_tracker_win.cc +++ b/media/capture/video/win/gpu_memory_buffer_tracker_win.cc
@@ -59,8 +59,8 @@ .Usage = D3D11_USAGE_DEFAULT, .BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET, .CPUAccessFlags = 0, - .MiscFlags = D3D11_RESOURCE_MISC_SHARED_NTHANDLE | - D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX}; + .MiscFlags = + D3D11_RESOURCE_MISC_SHARED_NTHANDLE | D3D11_RESOURCE_MISC_SHARED}; Microsoft::WRL::ComPtr<ID3D11Texture2D> d3d11_texture;
diff --git a/media/capture/video/win/video_capture_device_mf_win.cc b/media/capture/video/win/video_capture_device_mf_win.cc index bac6ab0..9f73dc2 100644 --- a/media/capture/video/win/video_capture_device_mf_win.cc +++ b/media/capture/video/win/video_capture_device_mf_win.cc
@@ -705,47 +705,30 @@ Microsoft::WRL::ComPtr<ID3D11DeviceContext> device_context; texture_device->GetImmediateContext(&device_context); - Microsoft::WRL::ComPtr<IDXGIKeyedMutex> keyed_mutex; - hr = target_texture.As(&keyed_mutex); - CHECK(SUCCEEDED(hr)); + device_context->CopySubresourceRegion(target_texture.Get(), 0, 0, 0, 0, + texture, 0, nullptr); - hr = keyed_mutex->AcquireSync(0, INFINITE); - // Can't check for FAILED(hr) because AcquireSync may return e.g. - // WAIT_ABANDONED. - if (hr != S_OK) { - DLOG(ERROR) << "Failed to acquire the mutex:" - << logging::SystemErrorCodeToString(hr); - return E_FAIL; - } + // Wait here for copy completion for D3D11/D3D12 interop, due to: + // 1) For D3D12 access in GPU process, D3D12 runtime is not aware of the + // simultaneous D3D11 write-access by capture module, so capture module + // must ensure copy completion before handing over to D3D12; + // 2) For D3D11 access in GPU process, if we add a D3D11Fence here and + // deliver that in GMB for access in GPU process, it will not work as GPU + // process is on a different D3D11 device/context, though they may be on + // the same adapter. + Microsoft::WRL::ComPtr<IDXGIDevice2> dxgi_device2; + hr = texture_device.As(&dxgi_device2); + CHECK_EQ(hr, S_OK); + base::WaitableEvent event; - { - gpu::DXGIScopedReleaseKeyedMutex scoped_keyed_mutex(keyed_mutex, 0); - - device_context->CopySubresourceRegion(target_texture.Get(), 0, 0, 0, 0, - texture, 0, nullptr); - - // Wait here for copy completion for D3D11/D3D12 interop, due to: - // 1) For D3D12 access in GPU process, D3D12 runtime is not aware of the - // simultaneous D3D11 write-access by capture module, so capture module - // must ensure copy completion before handing over to D3D12; - // 2) For D3D11 access in GPU process, if we add a D3D11Fence here and - // deliver that in GMB for access in GPU process, it will not work as GPU - // process is on a different D3D11 device/context, though they may be on - // the same adapter. - Microsoft::WRL::ComPtr<IDXGIDevice2> dxgi_device2; - hr = texture_device.As(&dxgi_device2); - CHECK_EQ(hr, S_OK); - base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC, - base::WaitableEvent::InitialState::NOT_SIGNALED); - - hr = dxgi_device2->EnqueueSetEvent(event.handle()); - if (SUCCEEDED(hr)) { - event.Wait(); - } else { - LOG(WARNING) << "Failed to set event: " - << logging::SystemErrorCodeToString(hr); - device_context->Flush(); - } + hr = dxgi_device2->EnqueueSetEvent(event.handle()); + if (SUCCEEDED(hr)) { + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("video_and_image_capture"), + "CopyTextureToGpuMemoryBufferSync"); + event.Wait(); + } else { + LOG(WARNING) << "Failed to set event: " + << logging::SystemErrorCodeToString(hr); } return S_OK;
diff --git a/media/gpu/fuzzers/h264_parser_structural_fuzzer.cc b/media/gpu/fuzzers/h264_parser_structural_fuzzer.cc index 6c5f808..e11e744 100644 --- a/media/gpu/fuzzers/h264_parser_structural_fuzzer.cc +++ b/media/gpu/fuzzers/h264_parser_structural_fuzzer.cc
@@ -9,6 +9,7 @@ #include <algorithm> #include <vector> +#include "base/at_exit.h" #include "base/check_op.h" #include "base/containers/span.h" #include "base/numerics/safe_conversions.h" @@ -530,6 +531,8 @@ return 0; } + base::AtExitManager at_exit_manager; + FuzzedDataProvider fdp(data, size); std::vector<uint8_t> final_bitstream;
diff --git a/media/gpu/vaapi/BUILD.gn b/media/gpu/vaapi/BUILD.gn index 950e83d..98b03e5 100644 --- a/media/gpu/vaapi/BUILD.gn +++ b/media/gpu/vaapi/BUILD.gn
@@ -150,6 +150,7 @@ ] deps = [ ":libva_stubs", + "//gpu/config", "//media/gpu/chromeos:video_frame_resource", "//third_party/libyuv", "//ui/base:features",
diff --git a/media/gpu/vaapi/vaapi_wrapper.cc b/media/gpu/vaapi/vaapi_wrapper.cc index 4c220c33..cde39f7 100644 --- a/media/gpu/vaapi/vaapi_wrapper.cc +++ b/media/gpu/vaapi/vaapi_wrapper.cc
@@ -61,6 +61,7 @@ // Auto-generated for dlopen libva libraries #include "components/viz/common/resources/shared_image_format.h" #include "components/viz/common/resources/shared_image_format_utils.h" +#include "gpu/config/gpu_driver_bug_workarounds.h" #include "media/gpu/vaapi/va_stubs.h" #include "media/media_buildflags.h" #include "third_party/abseil-cpp/absl/cleanup/cleanup.h" @@ -243,7 +244,8 @@ // This method must be called exactly once before trying to acquire a // VADisplayStateHandle. - static void PreSandboxInitialization(); + static void PreSandboxInitialization( + const gpu::GpuDriverBugWorkarounds* workarounds); // If an initialized VADisplayStateSingleton exists, this method returns a // VADisplayStateHandle to it. Otherwise, it attempts to initialize a @@ -318,6 +320,9 @@ // String representing a driver acquired by vaQueryVendorString(). std::string va_vendor_string_; + + // Was the driver disabled entirely due to a GPU driver bug. + bool disabled_ = false; }; } // namespace media @@ -1532,10 +1537,16 @@ } // static -void VADisplayStateSingleton::PreSandboxInitialization() { +void VADisplayStateSingleton::PreSandboxInitialization( + const gpu::GpuDriverBugWorkarounds* workarounds) { VADisplayStateSingleton& va_display_state = GetInstance(); base::AutoLock lock(va_display_state.lock_); + if (workarounds && workarounds->disable_vaapi) { + va_display_state.disabled_ = true; + return; + } + if (base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kHardwareVideoDevicePath)) { auto [drm_fd, should_skip] = @@ -1590,6 +1601,13 @@ return VADisplayStateHandle(&va_display_state); } + if (va_display_state.disabled_) { + // The gpu driver bug should prevent the display state from ever being + // initialized. + VLOGF(1) << "VAAPI has been disabled due to a detected driver bug."; + return VADisplayStateHandle(); + } + if (!va_display_state.drm_fd_.is_valid()) { VLOGF(1) << "Either VADisplayStateSingleton::PreSandboxInitialization() hasn't " @@ -3193,10 +3211,12 @@ bool VaapiWrapper::allow_disabling_global_lock_ = false; // static -void VaapiWrapper::PreSandboxInitialization(bool allow_disabling_global_lock) { +void VaapiWrapper::PreSandboxInitialization( + bool allow_disabling_global_lock, + const gpu::GpuDriverBugWorkarounds* workarounds) { allow_disabling_global_lock_ = allow_disabling_global_lock; - VADisplayStateSingleton::PreSandboxInitialization(); + VADisplayStateSingleton::PreSandboxInitialization(workarounds); const std::string va_suffix(base::NumberToString(VA_MAJOR_VERSION + 1)); StubPathMap paths;
diff --git a/media/gpu/vaapi/vaapi_wrapper.h b/media/gpu/vaapi/vaapi_wrapper.h index 37001b94..cd1be5d8 100644 --- a/media/gpu/vaapi/vaapi_wrapper.h +++ b/media/gpu/vaapi/vaapi_wrapper.h
@@ -60,6 +60,10 @@ CHECK(sequence_checker.CalledOnValidSequence()) #endif +namespace gpu { +class GpuDriverBugWorkarounds; +} + namespace media { constexpr unsigned int kInvalidVaRtFormat = 0u; @@ -593,7 +597,8 @@ // Initialize static data before sandbox is enabled. static void PreSandboxInitialization( - bool allow_disabling_global_lock = false); + bool allow_disabling_global_lock = false, + const gpu::GpuDriverBugWorkarounds* workarounds = nullptr); // vaDestroySurfaces() a vector or a single VASurfaceID. virtual void DestroySurfaces(std::vector<VASurfaceID> va_surfaces);
diff --git a/media/video/software_video_encoder_test.cc b/media/video/software_video_encoder_test.cc index 4ec61cd..3e879b8 100644 --- a/media/video/software_video_encoder_test.cc +++ b/media/video/software_video_encoder_test.cc
@@ -316,6 +316,7 @@ }; class H264VideoEncoderTest : public SoftwareVideoEncoderTest {}; +class Vpx10BitVideoEncoderTest : public SoftwareVideoEncoderTest {}; class SVCVideoEncoderTest : public SoftwareVideoEncoderTest {}; class ManualSVCVideoEncoderTest : public SoftwareVideoEncoderTest {}; class LargeTimestampOverflowTest : public SoftwareVideoEncoderTest {}; @@ -590,6 +591,46 @@ EXPECT_EQ(total_decoded_frames, total_frames_count); } +TEST_P(Vpx10BitVideoEncoderTest, EncodeDifferentMemoryTypes) { + VideoEncoder::Options options = CreateDefaultOptions(); + options.frame_size = gfx::Size(2000, 2000); + + encoder_->Initialize(profile_, options, /*info_cb=*/base::DoNothing(), + /*output_cb=*/base::DoNothing(), + ValidateStatusThenQuitCB()); + RunUntilQuit(); + + VideoPixelFormat format1 = (profile_ == VP9PROFILE_PROFILE2) + ? PIXEL_FORMAT_YUV420P10 + : PIXEL_FORMAT_YUV444P10; + VideoPixelFormat format2 = + (profile_ == VP9PROFILE_PROFILE2) ? PIXEL_FORMAT_I420 : PIXEL_FORMAT_I444; + + // Encode a frame that doesn't need its own memory wrapper allocation. + auto frame1 = media::VideoFrame::CreateZeroInitializedFrame( + format1, options.frame_size, gfx::Rect(options.frame_size), + options.frame_size, base::Seconds(1)); + encoder_->Encode(std::move(frame1), VideoEncoder::EncodeOptions(true), + ValidateStatusThenQuitCB()); + ASSERT_NO_FATAL_FAILURE(RunUntilQuit()); + + // Encode a frame that DOES need its own memory wrapper allocation. + auto frame2 = media::VideoFrame::CreateZeroInitializedFrame( + format2, options.frame_size, gfx::Rect(options.frame_size), + options.frame_size, base::Seconds(2)); + encoder_->Encode(std::move(frame2), VideoEncoder::EncodeOptions(false), + ValidateStatusThenQuitCB()); + ASSERT_NO_FATAL_FAILURE(RunUntilQuit()); + + // Encode the first format again. + auto frame3 = media::VideoFrame::CreateZeroInitializedFrame( + format1, options.frame_size, gfx::Rect(options.frame_size), + options.frame_size, base::Seconds(3)); + encoder_->Encode(std::move(frame3), VideoEncoder::EncodeOptions(false), + ValidateStatusThenQuitCB()); + ASSERT_NO_FATAL_FAILURE(RunUntilQuit()); +} + TEST_P(SoftwareVideoEncoderTest, EncodeAndDecodeWithEnablingDrop) { base::test::ScopedFeatureList scoped_feature_list; scoped_feature_list.InitAndEnableFeature(kWebCodecsVideoEncoderFrameDrop); @@ -1527,6 +1568,15 @@ ::testing::ValuesIn(kVpxParams), PrintTestParams); +SwVideoTestParams kVpx10BitParams[] = { + {VideoCodec::kVP9, VP9PROFILE_PROFILE2, PIXEL_FORMAT_I420}, + {VideoCodec::kVP9, VP9PROFILE_PROFILE3, PIXEL_FORMAT_I420}}; + +INSTANTIATE_TEST_SUITE_P(Vpx10BitSpecific, + Vpx10BitVideoEncoderTest, + ::testing::ValuesIn(kVpx10BitParams), + PrintTestParams); + SwVideoTestParams kVpxSVCParams[] = { {VideoCodec::kVP9, VP9PROFILE_PROFILE0, PIXEL_FORMAT_I420, std::nullopt}, {VideoCodec::kVP9, VP9PROFILE_PROFILE0, PIXEL_FORMAT_I420, @@ -1603,6 +1653,7 @@ #endif // ENABLE_LIBAOM GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(H264VideoEncoderTest); +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(Vpx10BitVideoEncoderTest); GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SVCVideoEncoderTest); GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SoftwareVideoEncoderTest); GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ManualSVCVideoEncoderTest);
diff --git a/media/video/vpx_video_encoder.cc b/media/video/vpx_video_encoder.cc index a661729e..6b0df913 100644 --- a/media/video/vpx_video_encoder.cc +++ b/media/video/vpx_video_encoder.cc
@@ -919,13 +919,15 @@ bool needs_memory) { const bool has_changed = vpx_image_.fmt != fmt || vpx_image_.d_w != codec_config_.g_w || - vpx_image_.d_h != codec_config_.g_h; + vpx_image_.d_h != codec_config_.g_h || + vpx_image_owns_memory_ != needs_memory; if (!has_changed) { return; } vpx_img_free(&vpx_image_); + vpx_image_owns_memory_ = needs_memory; if (needs_memory) { CHECK(vpx_img_alloc(&vpx_image_, fmt, codec_config_.g_w, codec_config_.g_h, /*align=*/1));
diff --git a/media/video/vpx_video_encoder.h b/media/video/vpx_video_encoder.h index 099a3a2..de7ecc4 100644 --- a/media/video/vpx_video_encoder.h +++ b/media/video/vpx_video_encoder.h
@@ -53,6 +53,8 @@ vpx_codec_unique_ptr codec_; vpx_codec_enc_cfg_t codec_config_ = {}; vpx_image_t vpx_image_ = {}; + // True if `vpx_image_` was allocated with vpx_img_alloc(). + bool vpx_image_owns_memory_ = false; gfx::Size originally_configured_size_; base::TimeDelta last_frame_timestamp_; gfx::ColorSpace last_frame_color_space_;
diff --git a/mojo/public/cpp/system/tests/data_pipe_unittest.cc b/mojo/public/cpp/system/tests/data_pipe_unittest.cc index 880e65d..fc292ea 100644 --- a/mojo/public/cpp/system/tests/data_pipe_unittest.cc +++ b/mojo/public/cpp/system/tests/data_pipe_unittest.cc
@@ -12,6 +12,7 @@ #include "base/test/task_environment.h" #include "mojo/public/c/system/types.h" #include "mojo/public/cpp/system/data_pipe.h" +#include "partition_alloc/buildflags.h" #include "testing/gtest/include/gtest/gtest.h" namespace mojo { @@ -82,15 +83,44 @@ // TODO(lukasza): Avoid UB risk by testing with a `std::vector` that contains // `std::numeric_limits<uint32_t>::max() + 123` bytes. (Once our allocator // supports such big vectors.) + // + // Note: this will be challenging given the limits of different platforms + // crossed with different build configurations. One must account for + // + // * Whether PartitionAlloc-Everywhere is in use (limiting your max + // alloc size) + // + // * If Windows (and not PA-E), the limits of the Windows CRT + // + // * If sanitizer, the limits of the underlying allocator + // + // * ...other not-immediately-obvious platform-specific pitfalls (e.g. + // Mac, Fuchsia, and linux-chromeos failures) + // + // * See https://crrev.com/c/7637373 for an example CL that almost + // satisfies these constraints (but later fails on non-CQ bots). std::vector<uint8_t> kData(1024, 0x00); base::span<const uint8_t> big_span = UNSAFE_BUFFERS(base::span<const uint8_t>( - kData.data(), + base::unchecked, kData.data(), std::numeric_limits<size_t>::max())); // subtle - see above why ok size_t bytes_written = 0; + +#if PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && PA_BUILDFLAG(CHECKED_SPAN) + // Even though we use `base::unchecked` to mint the bogus `big_span`, + // Mojo will blow this apart into a pointer+size, pass it through the + // C API layer, and reconstitute a (checked) span underneath --- where + // we would crash. + EXPECT_DEATH_IF_SUPPORTED( + producer_handle->WriteData(big_span, MOJO_BEGIN_WRITE_DATA_FLAG_NONE, + bytes_written), + ""); +#else ASSERT_EQ(producer_handle->WriteData( big_span, MOJO_BEGIN_WRITE_DATA_FLAG_NONE, bytes_written), MOJO_RESULT_OK); EXPECT_EQ(bytes_written, 16u); +#endif // PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && + // PA_BUILDFLAG(CHECKED_SPAN) } TEST(DataPipeCppTest, ReadDataGracefullyHandlesBigSize) { @@ -116,16 +146,40 @@ // TODO(lukasza): Avoid UB risk by testing with a `std::vector` that can // accommodate `std::numeric_limits<uint32_t>::max() + 123` bytes. (Once our // allocator supports such big vectors.) + // + // Note: this will be challenging given the limits of different platforms + // crossed with different build configurations. One must account for + // + // * Whether PartitionAlloc-Everywhere is in use (limiting your max + // alloc size) + // + // * If Windows (and not PA-E), the limits of the Windows CRT + // + // * If sanitizer, the limits of the underlying allocator + // + // * ...other not-immediately-obvious platform-specific pitfalls (e.g. + // Mac, Fuchsia, and linux-chromeos failures) + // + // * See https://crrev.com/c/7637373 for an example CL that almost + // satisfies these constraints (but later fails on non-CQ bots). std::vector<uint8_t> read_buffer(100); base::span<uint8_t> big_span = UNSAFE_BUFFERS(base::span<uint8_t>( - read_buffer.data(), std::numeric_limits<size_t>::max())); + base::unchecked, read_buffer.data(), std::numeric_limits<size_t>::max())); size_t actually_read_bytes; +#if PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && PA_BUILDFLAG(CHECKED_SPAN) + EXPECT_DEATH_IF_SUPPORTED( + consumer_handle->ReadData(MOJO_READ_DATA_FLAG_NONE, big_span, + actually_read_bytes), + ""); +#else ASSERT_EQ(consumer_handle->ReadData(MOJO_READ_DATA_FLAG_NONE, big_span, actually_read_bytes), MOJO_RESULT_OK); EXPECT_EQ(actually_read_bytes, 10u); EXPECT_EQ(base::as_byte_span(read_buffer).first(10u), base::as_byte_span(std::string_view(kData))); +#endif // PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && + // PA_BUILDFLAG(CHECKED_SPAN) } TEST(DataPipeCppTest, EndReadDataErrorWhenSizeTooBig) {
diff --git a/net/base/isolation_info.cc b/net/base/isolation_info.cc index bfc5e09..8e4d624 100644 --- a/net/base/isolation_info.cc +++ b/net/base/isolation_info.cc
@@ -236,7 +236,7 @@ IsolationInfo IsolationInfo::DoNotUseCreatePartialFromNak( const net::NetworkAnonymizationKey& network_anonymization_key) { - if (!network_anonymization_key.IsFullyPopulated()) { + if (network_anonymization_key.IsEmpty()) { return IsolationInfo(); } @@ -261,7 +261,7 @@ auto isolation_info = IsolationInfo::Create( IsolationInfo::RequestType::kOther, top_frame_origin, frame_origin.value(), SiteForCookies(), nonce); - // TODO(crbug.com/40852603): DCHECK isolation info is fully populated. + // TODO(crbug.com/40852603): DCHECK isolation info is not empty. return isolation_info; }
diff --git a/net/base/isolation_info.h b/net/base/isolation_info.h index b96135c0..84787824 100644 --- a/net/base/isolation_info.h +++ b/net/base/isolation_info.h
@@ -76,6 +76,20 @@ // `nonce` will therefore lead to sending network requests that should // have been blocked. See `RenderFrameHostImpl::ComputeNonce()` which // computes the correct nonce for a given frame. +// +// There are also several special cases of IsolationInfos. Specifically: +// - Transient: Created by `IsolationInfo::CreateTransient()`, used for +// requests that should not be persisted to disk or send cookies, and that +// should have corresponding network state in it's own partition (not shared +// with state from other contexts). +// - Empty: Created by the default constructor, can be used by requests for +// which cookies should not be sent, corresponding responses should not be +// persisted to disk, and for which corresponding network state should can be +// shared with that of other requests using an empty IsolationInfo (i.e. no +// partitioning between these requests is required). Note that although +// responses for requests using an empty IsolationInfo are not persisted to +// disk, other metadata that is keyed off of the NetworkAnonymizationKey +// (such as HttpServerProperties) might be. class NET_EXPORT IsolationInfo { public: // The update-on-redirect patterns.
diff --git a/net/base/isolation_info_unittest.cc b/net/base/isolation_info_unittest.cc index 8c29894d..c403ab8 100644 --- a/net/base/isolation_info_unittest.cc +++ b/net/base/isolation_info_unittest.cc
@@ -96,7 +96,7 @@ EXPECT_EQ(kOrigin1, isolation_info.frame_origin()); EXPECT_EQ("https://foo.test https://foo.test", isolation_info.network_isolation_key().ToCacheKeyString()); - EXPECT_TRUE(isolation_info.network_isolation_key().IsFullyPopulated()); + EXPECT_FALSE(isolation_info.network_isolation_key().IsEmpty()); EXPECT_FALSE(isolation_info.network_isolation_key().IsTransient()); EXPECT_TRUE( isolation_info.site_for_cookies().IsFirstParty(kOrigin1.GetURL())); @@ -112,8 +112,7 @@ redirected_isolation_info.request_type()); EXPECT_EQ(kOrigin3, redirected_isolation_info.top_frame_origin()); EXPECT_EQ(kOrigin3, redirected_isolation_info.frame_origin()); - EXPECT_TRUE( - redirected_isolation_info.network_isolation_key().IsFullyPopulated()); + EXPECT_FALSE(redirected_isolation_info.network_isolation_key().IsEmpty()); EXPECT_FALSE(redirected_isolation_info.network_isolation_key().IsTransient()); EXPECT_EQ( "https://baz.test https://baz.test", @@ -136,7 +135,7 @@ EXPECT_EQ(kOrigin2, isolation_info.frame_origin()); EXPECT_EQ("https://foo.test https://bar.test", isolation_info.network_isolation_key().ToCacheKeyString()); - EXPECT_TRUE(isolation_info.network_isolation_key().IsFullyPopulated()); + EXPECT_FALSE(isolation_info.network_isolation_key().IsEmpty()); EXPECT_FALSE(isolation_info.network_isolation_key().IsTransient()); EXPECT_TRUE( isolation_info.site_for_cookies().IsFirstParty(kOrigin1.GetURL())); @@ -157,8 +156,7 @@ "https://foo.test https://baz.test", redirected_isolation_info.network_isolation_key().ToCacheKeyString()); - EXPECT_TRUE( - redirected_isolation_info.network_isolation_key().IsFullyPopulated()); + EXPECT_FALSE(redirected_isolation_info.network_isolation_key().IsEmpty()); EXPECT_FALSE(redirected_isolation_info.network_isolation_key().IsTransient()); EXPECT_TRUE(redirected_isolation_info.site_for_cookies().IsFirstParty( kOrigin1.GetURL())); @@ -175,7 +173,7 @@ isolation_info.request_type()); EXPECT_EQ(kOrigin1, isolation_info.top_frame_origin()); EXPECT_EQ(kOrigin1, isolation_info.frame_origin()); - EXPECT_TRUE(isolation_info.network_isolation_key().IsFullyPopulated()); + EXPECT_FALSE(isolation_info.network_isolation_key().IsEmpty()); EXPECT_TRUE(isolation_info.network_isolation_key().IsTransient()); EXPECT_EQ(std::nullopt, isolation_info.network_isolation_key().ToCacheKeyString()); @@ -193,8 +191,7 @@ redirected_isolation_info.request_type()); EXPECT_EQ(kOrigin3, redirected_isolation_info.top_frame_origin()); EXPECT_EQ(kOrigin3, redirected_isolation_info.frame_origin()); - EXPECT_TRUE( - redirected_isolation_info.network_isolation_key().IsFullyPopulated()); + EXPECT_FALSE(redirected_isolation_info.network_isolation_key().IsEmpty()); EXPECT_TRUE(redirected_isolation_info.network_isolation_key().IsTransient()); EXPECT_EQ( std::nullopt, @@ -226,7 +223,7 @@ isolation_info.network_isolation_key().GetNetworkIsolationPartition()); EXPECT_EQ("https://foo.test https://foo.test 1", isolation_info.network_isolation_key().ToCacheKeyString()); - EXPECT_TRUE(isolation_info.network_isolation_key().IsFullyPopulated()); + EXPECT_FALSE(isolation_info.network_isolation_key().IsEmpty()); EXPECT_FALSE(isolation_info.network_isolation_key().IsTransient()); EXPECT_TRUE( isolation_info.site_for_cookies().IsFirstParty(kOrigin1.GetURL())); @@ -250,8 +247,7 @@ EXPECT_EQ(NetworkIsolationPartition::kProtectedAudienceSellerWorklet, redirected_isolation_info.network_isolation_key() .GetNetworkIsolationPartition()); - EXPECT_TRUE( - redirected_isolation_info.network_isolation_key().IsFullyPopulated()); + EXPECT_FALSE(redirected_isolation_info.network_isolation_key().IsEmpty()); EXPECT_FALSE(redirected_isolation_info.network_isolation_key().IsTransient()); EXPECT_EQ( "https://baz.test https://baz.test 1", @@ -272,7 +268,7 @@ isolation_info.request_type()); EXPECT_EQ(kOrigin1, isolation_info.top_frame_origin()); EXPECT_EQ(kOrigin2, isolation_info.frame_origin()); - EXPECT_TRUE(isolation_info.network_isolation_key().IsFullyPopulated()); + EXPECT_FALSE(isolation_info.network_isolation_key().IsEmpty()); EXPECT_TRUE(isolation_info.network_isolation_key().IsTransient()); EXPECT_EQ(std::nullopt, isolation_info.network_isolation_key().ToCacheKeyString()); @@ -290,8 +286,7 @@ redirected_isolation_info.request_type()); EXPECT_EQ(kOrigin1, redirected_isolation_info.top_frame_origin()); EXPECT_EQ(kOrigin3, redirected_isolation_info.frame_origin()); - EXPECT_TRUE( - redirected_isolation_info.network_isolation_key().IsFullyPopulated()); + EXPECT_FALSE(redirected_isolation_info.network_isolation_key().IsEmpty()); EXPECT_TRUE(redirected_isolation_info.network_isolation_key().IsTransient()); EXPECT_EQ( std::nullopt, @@ -331,7 +326,7 @@ EXPECT_EQ(kOrigin1, isolation_info.frame_origin()); EXPECT_EQ("https://foo.test https://foo.test", isolation_info.network_isolation_key().ToCacheKeyString()); - EXPECT_TRUE(isolation_info.network_isolation_key().IsFullyPopulated()); + EXPECT_FALSE(isolation_info.network_isolation_key().IsEmpty()); EXPECT_FALSE(isolation_info.network_isolation_key().IsTransient()); EXPECT_TRUE( isolation_info.site_for_cookies().IsFirstParty(kOrigin1.GetURL())); @@ -357,7 +352,7 @@ EXPECT_EQ("https://foo.test https://bar.test", isolation_info.network_isolation_key().ToCacheKeyString()); - EXPECT_TRUE(isolation_info.network_isolation_key().IsFullyPopulated()); + EXPECT_FALSE(isolation_info.network_isolation_key().IsEmpty()); EXPECT_FALSE(isolation_info.network_isolation_key().IsTransient()); EXPECT_TRUE(isolation_info.site_for_cookies().IsNull()); EXPECT_FALSE(isolation_info.nonce()); @@ -377,7 +372,7 @@ EXPECT_EQ(IsolationInfo::RequestType::kOther, isolation_info.request_type()); EXPECT_TRUE(isolation_info.top_frame_origin()->opaque()); EXPECT_TRUE(isolation_info.frame_origin()->opaque()); - EXPECT_TRUE(isolation_info.network_isolation_key().IsFullyPopulated()); + EXPECT_FALSE(isolation_info.network_isolation_key().IsEmpty()); EXPECT_TRUE(isolation_info.network_isolation_key().IsTransient()); EXPECT_TRUE(isolation_info.site_for_cookies().IsNull()); EXPECT_FALSE(isolation_info.nonce()); @@ -396,7 +391,7 @@ EXPECT_EQ(IsolationInfo::RequestType::kOther, isolation_info.request_type()); EXPECT_TRUE(isolation_info.top_frame_origin()->opaque()); EXPECT_TRUE(isolation_info.frame_origin()->opaque()); - EXPECT_TRUE(isolation_info.network_isolation_key().IsFullyPopulated()); + EXPECT_FALSE(isolation_info.network_isolation_key().IsEmpty()); EXPECT_TRUE(isolation_info.network_isolation_key().IsTransient()); EXPECT_TRUE(isolation_info.site_for_cookies().IsNull()); ASSERT_TRUE(isolation_info.nonce().has_value()); @@ -429,7 +424,7 @@ EXPECT_EQ("https://foo.test https://foo.test", isolation_info.network_isolation_key().ToCacheKeyString()); - EXPECT_TRUE(isolation_info.network_isolation_key().IsFullyPopulated()); + EXPECT_FALSE(isolation_info.network_isolation_key().IsEmpty()); EXPECT_FALSE(isolation_info.network_isolation_key().IsTransient()); EXPECT_TRUE( isolation_info.site_for_cookies().IsFirstParty(kOrigin1.GetURL())); @@ -464,7 +459,7 @@ EXPECT_EQ("foo://a.foo.com https://foo.test", isolation_info.network_isolation_key().ToCacheKeyString()); - EXPECT_TRUE(isolation_info.network_isolation_key().IsFullyPopulated()); + EXPECT_FALSE(isolation_info.network_isolation_key().IsEmpty()); EXPECT_FALSE(isolation_info.network_isolation_key().IsTransient()); EXPECT_TRUE(isolation_info.site_for_cookies().IsFirstParty(kCustomOriginUrl)); EXPECT_FALSE(isolation_info.nonce());
diff --git a/net/base/network_anonymization_key.cc b/net/base/network_anonymization_key.cc index cbc09855..076ef3c 100644 --- a/net/base/network_anonymization_key.cc +++ b/net/base/network_anonymization_key.cc
@@ -50,11 +50,11 @@ NetworkAnonymizationKey&& network_anonymization_key) = default; NetworkAnonymizationKey::NetworkAnonymizationKey( - const std::optional<SchemefulSite>& top_frame_site, + std::optional<SchemefulSite> top_frame_site, bool is_cross_site, std::optional<base::UnguessableToken> nonce, NetworkIsolationPartition network_isolation_partition) - : data_(base::MakeRefCounted<Data>(top_frame_site, + : data_(base::MakeRefCounted<Data>(std::move(top_frame_site), is_cross_site, std::move(nonce), network_isolation_partition)) {} @@ -84,11 +84,12 @@ NetworkAnonymizationKey NetworkAnonymizationKey::CreateTransient() { SchemefulSite site_with_opaque_origin; - return NetworkAnonymizationKey(site_with_opaque_origin, false); + return NetworkAnonymizationKey(std::move(site_with_opaque_origin), + /*is_cross_site=*/false); } std::string NetworkAnonymizationKey::ToDebugString() const { - if (!IsFullyPopulated()) { + if (IsEmpty()) { return "null"; } @@ -116,13 +117,10 @@ return data_->is_empty(); } -bool NetworkAnonymizationKey::IsFullyPopulated() const { - return !IsEmpty(); -} - bool NetworkAnonymizationKey::IsTransient() const { - if (!IsFullyPopulated()) + if (IsEmpty()) { return true; + } return GetTopFrameSite()->opaque() || GetNonce().has_value(); } @@ -198,7 +196,7 @@ } *network_anonymization_key = NetworkAnonymizationKey( - top_frame_site.value(), is_cross_site, /*nonce=*/std::nullopt, + std::move(top_frame_site), is_cross_site, /*nonce=*/std::nullopt, network_isolation_partition); return true; } @@ -259,11 +257,11 @@ } NetworkAnonymizationKey::Data::Data( - const std::optional<SchemefulSite>& top_frame_site, + std::optional<SchemefulSite> top_frame_site, bool is_cross_site, std::optional<base::UnguessableToken> nonce, NetworkIsolationPartition network_isolation_partition) - : top_frame_site_(top_frame_site), + : top_frame_site_(std::move(top_frame_site)), is_cross_site_(is_cross_site), nonce_(std::move(nonce)), network_isolation_partition_(network_isolation_partition) {}
diff --git a/net/base/network_anonymization_key.h b/net/base/network_anonymization_key.h index 94cf2e36..71d5515 100644 --- a/net/base/network_anonymization_key.h +++ b/net/base/network_anonymization_key.h
@@ -62,6 +62,11 @@ // site, URL) and "triple key" (top frame site, frame site, and URL). The // `is_cross_site` bit carries more information than a double key, but less than // a triple key. +// +// An empty NetworkAnonymizationKey (one where the `top_frame_site` and `nonce` +// are both empty) should be used when network state partitioning is disabled +// (see `IsPartitioningEnabled()`), or for non-web requests where storage +// partitioning should not apply. class NET_EXPORT NetworkAnonymizationKey { public: // Construct an empty key. @@ -81,16 +86,17 @@ // Create a `NetworkAnonymizationKey` from a `top_frame_site`, assuming it is // same-site (see comment on the class, above) and has no nonce. static NetworkAnonymizationKey CreateSameSite( - const SchemefulSite& top_frame_site) { - return NetworkAnonymizationKey(top_frame_site, false, std::nullopt, + const SchemefulSite top_frame_site) { + return NetworkAnonymizationKey(std::move(top_frame_site), false, + std::nullopt, NetworkIsolationPartition::kGeneral); } // Create a `NetworkAnonymizationKey` from a `top_frame_site`, assuming it is // cross-site (see comment on the class, above) and has no nonce. - static NetworkAnonymizationKey CreateCrossSite( - const SchemefulSite& top_frame_site) { - return NetworkAnonymizationKey(top_frame_site, true, std::nullopt, + static NetworkAnonymizationKey CreateCrossSite(SchemefulSite top_frame_site) { + return NetworkAnonymizationKey(std::move(top_frame_site), true, + std::nullopt, NetworkIsolationPartition::kGeneral); } @@ -113,13 +119,13 @@ // Creates a `NetworkAnonymizationKey` from its constituent parts. This // is intended to be used to build a NAK from Mojo, and for tests. static NetworkAnonymizationKey CreateFromParts( - const SchemefulSite& top_frame_site, + SchemefulSite top_frame_site, bool is_cross_site, std::optional<base::UnguessableToken> nonce = std::nullopt, NetworkIsolationPartition network_isolation_partition = NetworkIsolationPartition::kGeneral) { - return NetworkAnonymizationKey(top_frame_site, is_cross_site, nonce, - network_isolation_partition); + return NetworkAnonymizationKey(std::move(top_frame_site), is_cross_site, + nonce, network_isolation_partition); } // Creates a transient non-empty NetworkAnonymizationKey by creating an opaque @@ -130,16 +136,17 @@ // Returns the string representation of the key. std::string ToDebugString() const; - // Returns true if all parts of the key are empty. + // Returns true if this is an empty key (i.e. `top_frame_site` is empty). See + // the note in the class comment regarding empty NetworkAnonymizationKeys. bool IsEmpty() const; - // Returns true if `top_frame_site_` is non-empty. - bool IsFullyPopulated() const; - // Returns true if this key's lifetime is short-lived. It may not make sense // to persist state to disk related to it (e.g., disk cache). // A NetworkAnonymizationKey will be considered transient if // `top_frame_site_` is empty or opaque or if the key has a `nonce_`. + // Note that for an empty NetworkAnonymizationKey, IsTransient() will return + // true but it's still possible to use this key to persist state to disk (and + // this is how persistence is achieved when partitioning is disabled). bool IsTransient() const; // Getters for the top frame, frame site, nonce and is cross site flag. @@ -192,7 +199,7 @@ // Conctruct an empty data. explicit Data(base::PassKey<Data>); - Data(const std::optional<SchemefulSite>& top_frame_site, + Data(std::optional<SchemefulSite> top_frame_site, bool is_cross_site, std::optional<base::UnguessableToken> nonce, NetworkIsolationPartition network_isolation_partition); @@ -268,7 +275,7 @@ private: NetworkAnonymizationKey( - const std::optional<SchemefulSite>& top_frame_site, + std::optional<SchemefulSite> top_frame_site, bool is_cross_site, std::optional<base::UnguessableToken> nonce = std::nullopt, NetworkIsolationPartition network_isolation_partition =
diff --git a/net/base/network_anonymization_key_unittest.cc b/net/base/network_anonymization_key_unittest.cc index 5fb27e6..41840a2 100644 --- a/net/base/network_anonymization_key_unittest.cc +++ b/net/base/network_anonymization_key_unittest.cc
@@ -192,6 +192,10 @@ EXPECT_TRUE(empty_key.IsEmpty()); EXPECT_FALSE(populated_key.IsEmpty()); + + NetworkAnonymizationKey transient_key = + NetworkAnonymizationKey::CreateTransient(); + EXPECT_FALSE(transient_key.IsEmpty()); } TEST_F(NetworkAnonymizationKeyTest, CreateTransient) { @@ -244,21 +248,6 @@ EXPECT_FALSE(populated_double_key.IsTransient()); } -TEST_F(NetworkAnonymizationKeyTest, IsFullyPopulated) { - NetworkAnonymizationKey empty_key; - NetworkAnonymizationKey populated_key = - NetworkAnonymizationKey::CreateFromParts(/*top_frame_site=*/kTestSiteA, - /*is_cross_site=*/false, - /*nonce=*/std::nullopt); - EXPECT_TRUE(populated_key.IsFullyPopulated()); - EXPECT_FALSE(empty_key.IsFullyPopulated()); - NetworkAnonymizationKey empty_frame_site_key = - NetworkAnonymizationKey::CreateFromParts(/*top_frame_site=*/kTestSiteA, - /*is_cross_site=*/false, - /*nonce=*/std::nullopt); - EXPECT_TRUE(empty_frame_site_key.IsFullyPopulated()); -} - TEST_F(NetworkAnonymizationKeyTest, Getters) { NetworkAnonymizationKey key = NetworkAnonymizationKey::CreateFromParts( /*top_frame_site=*/kTestSiteA,
diff --git a/net/base/network_isolation_key.cc b/net/base/network_isolation_key.cc index 0c0e1fc..66a56fa 100644 --- a/net/base/network_isolation_key.cc +++ b/net/base/network_isolation_key.cc
@@ -128,13 +128,10 @@ return return_string; } -bool NetworkIsolationKey::IsFullyPopulated() const { - return !IsEmpty(); -} - bool NetworkIsolationKey::IsTransient() const { - if (!IsFullyPopulated()) + if (IsEmpty()) { return true; + } return IsOpaque(); }
diff --git a/net/base/network_isolation_key.h b/net/base/network_isolation_key.h index a9cdf9e..fd90a0a 100644 --- a/net/base/network_isolation_key.h +++ b/net/base/network_isolation_key.h
@@ -38,6 +38,12 @@ // `frame_site ` -> the schemeful site of the frame. // `network_isolation_partition` -> an extra partition for the HTTP cache for // special use cases. +// +// An empty NetworkIsolationKey (one where the `top_frame_site` is empty) can be +// used for transient network requests where the responses should not be written +// to disk. Note that although a given NetworkIsolationKey may be empty, the +// corresponding NetworkAnonymizationKey (also empty) may still result in +// metadata such as HttpServerProperties being written to disk. class NET_EXPORT NetworkIsolationKey { public: // Full constructor. When a request is initiated by the top frame, it must @@ -89,12 +95,11 @@ // entries may be distinguishable from each other. std::string ToDebugString() const; - // Returns true if all parts of the key are non-empty. - bool IsFullyPopulated() const; - - // Returns true if this key's lifetime is short-lived, or if - // IsFullyPopulated() returns true. It may not make sense to persist state to - // disk related to it (e.g., disk cache). + // Returns true if this key's lifetime is short-lived, or if !IsEmpty() + // returns true. It may not make sense to persist state to disk related to it + // (e.g., disk cache). See the note in the class comment about empty + // NetworkIsolationKeys, though, and how certain data associated with requests + // using them may still be persisted to disk. bool IsTransient() const; // Getters for the top frame and frame sites. These accessors are primarily @@ -146,7 +151,9 @@ return data_->network_isolation_partition(); } - // Returns true if all parts of the key are empty. + // Returns true if this is an empty key (i.e. `top_frame_site`, `frame_site`, + // and `nonce` are empty). See the note in the class comment regarding empty + // NetworkIsolationKeys. bool IsEmpty() const; private:
diff --git a/net/base/network_isolation_key_unittest.cc b/net/base/network_isolation_key_unittest.cc index 61a12d4e..1e90d08 100644 --- a/net/base/network_isolation_key_unittest.cc +++ b/net/base/network_isolation_key_unittest.cc
@@ -25,7 +25,7 @@ TEST(NetworkIsolationKeyTest, EmptyKey) { NetworkIsolationKey key; - EXPECT_FALSE(key.IsFullyPopulated()); + EXPECT_TRUE(key.IsEmpty()); EXPECT_EQ(std::nullopt, key.ToCacheKeyString()); EXPECT_TRUE(key.IsTransient()); EXPECT_EQ("null null", key.ToDebugString()); @@ -34,7 +34,7 @@ TEST(NetworkIsolationKeyTest, NonEmptySameSiteKey) { SchemefulSite site1 = SchemefulSite(GURL("http://a.test/")); NetworkIsolationKey key(site1, site1); - EXPECT_TRUE(key.IsFullyPopulated()); + EXPECT_FALSE(key.IsEmpty()); EXPECT_EQ(site1.Serialize() + " " + site1.Serialize(), key.ToCacheKeyString()); EXPECT_EQ(site1.GetDebugString() + " " + site1.GetDebugString(), @@ -46,7 +46,7 @@ SchemefulSite site1 = SchemefulSite(GURL("http://a.test/")); SchemefulSite site2 = SchemefulSite(GURL("http://b.test/")); NetworkIsolationKey key(site1, site2); - EXPECT_TRUE(key.IsFullyPopulated()); + EXPECT_FALSE(key.IsEmpty()); EXPECT_EQ(site1.Serialize() + " " + site2.Serialize(), key.ToCacheKeyString()); EXPECT_EQ(site1.GetDebugString() + " " + site2.GetDebugString(), @@ -59,7 +59,7 @@ SchemefulSite site2 = SchemefulSite(GURL("http://b.test/")); base::UnguessableToken nonce = base::UnguessableToken::Create(); NetworkIsolationKey key(site1, site2, nonce); - EXPECT_TRUE(key.IsFullyPopulated()); + EXPECT_FALSE(key.IsEmpty()); EXPECT_EQ(std::nullopt, key.ToCacheKeyString()); EXPECT_TRUE(key.IsTransient()); EXPECT_EQ(site1.GetDebugString() + " " + site2.GetDebugString() + @@ -85,7 +85,7 @@ NetworkIsolationKey key( site1, site2, /*nonce=*/std::nullopt, NetworkIsolationPartition::kProtectedAudienceSellerWorklet); - EXPECT_TRUE(key.IsFullyPopulated()); + EXPECT_FALSE(key.IsEmpty()); EXPECT_EQ(NetworkIsolationPartition::kProtectedAudienceSellerWorklet, key.GetNetworkIsolationPartition()); EXPECT_EQ(site1.Serialize() + " " + site2.Serialize() + " 1", @@ -136,7 +136,7 @@ TEST(NetworkIsolationKeyTest, OpaqueOriginKey) { SchemefulSite site_data = SchemefulSite(GURL(kDataUrl)); NetworkIsolationKey key(site_data, site_data); - EXPECT_TRUE(key.IsFullyPopulated()); + EXPECT_FALSE(key.IsEmpty()); EXPECT_EQ(std::nullopt, key.ToCacheKeyString()); EXPECT_TRUE(key.IsTransient()); EXPECT_EQ(site_data.GetDebugString() + " " + site_data.GetDebugString(), @@ -156,7 +156,7 @@ SchemefulSite site1 = SchemefulSite(GURL("http://a.test/")); SchemefulSite site_data = SchemefulSite(GURL(kDataUrl)); NetworkIsolationKey key(site_data, site1); - EXPECT_TRUE(key.IsFullyPopulated()); + EXPECT_FALSE(key.IsEmpty()); EXPECT_EQ(std::nullopt, key.ToCacheKeyString()); EXPECT_TRUE(key.IsTransient()); EXPECT_EQ(site_data.GetDebugString() + " " + site1.GetDebugString(), @@ -176,7 +176,7 @@ SchemefulSite site1 = SchemefulSite(GURL("http://a.test/")); SchemefulSite site_data = SchemefulSite(GURL(kDataUrl)); NetworkIsolationKey key(site1, site_data); - EXPECT_TRUE(key.IsFullyPopulated()); + EXPECT_FALSE(key.IsEmpty()); EXPECT_EQ(std::nullopt, key.ToCacheKeyString()); EXPECT_TRUE(key.IsTransient()); EXPECT_EQ(site1.GetDebugString() + " " + site_data.GetDebugString(), @@ -282,9 +282,9 @@ NetworkIsolationKey key3(site_data_1, site_data_3); // All the keys should be fully populated and transient. - EXPECT_TRUE(key1.IsFullyPopulated()); - EXPECT_TRUE(key2.IsFullyPopulated()); - EXPECT_TRUE(key3.IsFullyPopulated()); + EXPECT_FALSE(key1.IsEmpty()); + EXPECT_FALSE(key2.IsEmpty()); + EXPECT_FALSE(key3.IsEmpty()); EXPECT_TRUE(key1.IsTransient()); EXPECT_TRUE(key2.IsTransient()); EXPECT_TRUE(key3.IsTransient()); @@ -352,7 +352,7 @@ TEST(NetworkIsolationKeyTest, CreateTransientForTesting) { NetworkIsolationKey transient_key = NetworkIsolationKey::CreateTransientForTesting(); - EXPECT_TRUE(transient_key.IsFullyPopulated()); + EXPECT_FALSE(transient_key.IsEmpty()); EXPECT_TRUE(transient_key.IsTransient()); EXPECT_FALSE(transient_key.IsEmpty()); EXPECT_EQ(transient_key, transient_key);
diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc index de467cb..82131de 100644 --- a/net/http/http_cache_transaction.cc +++ b/net/http/http_cache_transaction.cc
@@ -2061,7 +2061,7 @@ if (!(effective_load_flags_ & LOAD_DISABLE_CACHE) && method_ == "POST" && NonErrorResponse(new_response_->headers->response_code()) && (!HttpCache::IsSplitCacheEnabled() || - request_->network_isolation_key.IsFullyPopulated())) { + !request_->network_isolation_key.IsEmpty())) { cache_->DoomMainEntryForUrl(request_->url, request_->network_isolation_key, request_->is_subframe_document_resource, request_->is_main_frame_navigation,
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc index ade7e08..769fd5e7 100644 --- a/net/http/http_network_transaction.cc +++ b/net/http/http_network_transaction.cc
@@ -12,6 +12,7 @@ #include "base/base64url.h" #include "base/compiler_specific.h" +#include "base/debug/dump_without_crashing.h" #include "base/feature_list.h" #include "base/format_macros.h" #include "base/functional/bind.h" @@ -2089,9 +2090,10 @@ if (ShouldResendRequest()) { if (retry_attempts_on_connection_errors_ >= kMaxRetryAttemptsOnConnectionErrors) { - NOTREACHED() << "Failed after " - << retry_attempts_on_connection_errors_ - << " retry attempts for connection errors."; + base::UmaHistogramBoolean( + "Net.NetworkTransaction.TooManyRetriesOnConnectionErrors", true); + base::debug::DumpWithoutCrashing(); + return ERR_TOO_MANY_RETRIES; } retry_attempts_on_connection_errors_++; net_log_.AddEventWithNetErrorCode(
diff --git a/net/socket/client_socket_pool_manager.cc b/net/socket/client_socket_pool_manager.cc index 3a7ff360..aca74747 100644 --- a/net/socket/client_socket_pool_manager.cc +++ b/net/socket/client_socket_pool_manager.cc
@@ -65,8 +65,8 @@ // http and SOCKS proxies. See http://crbug.com/12066 and // http://crbug.com/44501 for details about proxy chain connection limits. auto g_max_sockets_per_proxy_chain = std::to_array<size_t>({ - kDefaultMaxSocketsPerProxyChain, // kNormal - kDefaultMaxSocketsPerProxyChain // kWebSocket + 32, // kNormal + 32 // kWebSocket }); static_assert(
diff --git a/net/socket/client_socket_pool_manager.h b/net/socket/client_socket_pool_manager.h index 18cdddb4..8c767cb 100644 --- a/net/socket/client_socket_pool_manager.h +++ b/net/socket/client_socket_pool_manager.h
@@ -29,8 +29,6 @@ class ProxyInfo; class ProxyChain; -constexpr size_t kDefaultMaxSocketsPerProxyChain = 32; - class NET_EXPORT_PRIVATE ClientSocketPoolManager { public: ClientSocketPoolManager();
diff --git a/net/socket/client_socket_pool_unittest.cc b/net/socket/client_socket_pool_unittest.cc index 34d2d699..903a327 100644 --- a/net/socket/client_socket_pool_unittest.cc +++ b/net/socket/client_socket_pool_unittest.cc
@@ -193,8 +193,8 @@ NetworkAnonymizationKey::CreateSameSite(kSiteBar), SecureDnsPolicy::kAllow, /*disable_cert_network_fetches=*/false); - EXPECT_FALSE(group_id1.network_anonymization_key().IsFullyPopulated()); - EXPECT_FALSE(group_id2.network_anonymization_key().IsFullyPopulated()); + EXPECT_TRUE(group_id1.network_anonymization_key().IsEmpty()); + EXPECT_TRUE(group_id2.network_anonymization_key().IsEmpty()); EXPECT_EQ(group_id1.network_anonymization_key(), group_id2.network_anonymization_key()); EXPECT_EQ(group_id1, group_id2);
diff --git a/net/ssl/ssl_client_session_cache.cc b/net/ssl/ssl_client_session_cache.cc index 59ceed4..72a6f78 100644 --- a/net/ssl/ssl_client_session_cache.cc +++ b/net/ssl/ssl_client_session_cache.cc
@@ -9,6 +9,7 @@ #include <utility> #include "base/containers/flat_set.h" +#include "base/memory_coordinator/memory_coordinator_features.h" #include "base/time/clock.h" #include "base/time/default_clock.h" #include "third_party/boringssl/src/include/openssl/ssl.h" @@ -215,15 +216,29 @@ void SSLClientSessionCache::OnMemoryPressure( base::MemoryPressureLevel memory_pressure_level) { + if (base::FeatureList::IsEnabled(base::kStatefulMemoryPressure)) { + switch (memory_pressure_level) { + case base::MEMORY_PRESSURE_LEVEL_NONE: + cache_.UpdateMaxSize(config_.max_entries); + break; + case base::MEMORY_PRESSURE_LEVEL_MODERATE: + cache_.UpdateMaxSize(config_.max_entries / 2); + break; + case base::MEMORY_PRESSURE_LEVEL_CRITICAL: + cache_.UpdateMaxSize(0); + break; + } + return; + } + switch (memory_pressure_level) { case base::MEMORY_PRESSURE_LEVEL_NONE: - cache_.UpdateMaxSize(config_.max_entries); break; case base::MEMORY_PRESSURE_LEVEL_MODERATE: - cache_.UpdateMaxSize(config_.max_entries / 2); + FlushExpiredSessions(); break; case base::MEMORY_PRESSURE_LEVEL_CRITICAL: - cache_.UpdateMaxSize(0); + Flush(); break; } }
diff --git a/net/ssl/ssl_client_session_cache_unittest.cc b/net/ssl/ssl_client_session_cache_unittest.cc index e5ee01e..9e76032a 100644 --- a/net/ssl/ssl_client_session_cache_unittest.cc +++ b/net/ssl/ssl_client_session_cache_unittest.cc
@@ -5,8 +5,10 @@ #include "net/ssl/ssl_client_session_cache.h" #include "base/memory/memory_pressure_listener_registry.h" +#include "base/memory_coordinator/memory_coordinator_features.h" #include "base/run_loop.h" #include "base/strings/string_number_conversions.h" +#include "base/test/scoped_feature_list.h" #include "base/test/simple_test_clock.h" #include "base/test/task_environment.h" #include "base/time/time.h" @@ -434,12 +436,77 @@ // instead of buildflags once the feature is exposed publicly or moved to base. // Currently, it is internal to components/memory_pressure. #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) +#define MAYBE_TestFlushOnMemoryNotifications \ + DISABLED_TestFlushOnMemoryNotifications +#else +#define MAYBE_TestFlushOnMemoryNotifications TestFlushOnMemoryNotifications +#endif // Test that SSL cache is flushed on low memory notifications +TEST_F(SSLClientSessionCacheTest, MAYBE_TestFlushOnMemoryNotifications) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndDisableFeature(base::kStatefulMemoryPressure); + base::test::TaskEnvironment task_environment; + + // kExpirationCheckCount is set to a suitably large number so the automated + // pruning never triggers. + const size_t kExpirationCheckCount = 1000; + const base::TimeDelta kTimeout = base::Seconds(1000); + + SSLClientSessionCache::Config config; + config.expiration_check_count = kExpirationCheckCount; + std::unique_ptr<base::SimpleTestClock> clock = MakeTestClock(); + SSLClientSessionCache cache(config); + cache.SetClockForTesting(clock.get()); + + // Insert an entry into the session cache. + bssl::UniquePtr<SSL_SESSION> session1 = + MakeTestSession(clock->Now(), kTimeout); + cache.Insert(cache.generation_number(), MakeTestKey("key1"), + bssl::UpRef(session1)); + EXPECT_EQ(session1.get(), cache.Lookup(MakeTestKey("key1")).get()); + EXPECT_EQ(1u, cache.size()); + + // Expire the session. + clock->Advance(kTimeout * 2); + // Add one more session. + bssl::UniquePtr<SSL_SESSION> session2 = + MakeTestSession(clock->Now(), kTimeout); + cache.Insert(cache.generation_number(), MakeTestKey("key2"), + bssl::UpRef(session2)); + EXPECT_EQ(2u, cache.size()); + + // Fire a notification that will flush expired sessions. + base::MemoryPressureListener::NotifyMemoryPressure( + base::MEMORY_PRESSURE_LEVEL_MODERATE); + base::RunLoop().RunUntilIdle(); + + // Expired session's cache should be flushed. + // Lookup returns nullptr, when cache entry not found. + EXPECT_FALSE(cache.Lookup(MakeTestKey("key1"))); + EXPECT_TRUE(cache.Lookup(MakeTestKey("key2"))); + EXPECT_EQ(1u, cache.size()); + + // Fire notification that will flush everything. + base::MemoryPressureListener::NotifyMemoryPressure( + base::MEMORY_PRESSURE_LEVEL_CRITICAL); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(0u, cache.size()); +} + +// Memory pressure listeners are disabled on Windows and Mac, so this test +// is disabled on those platforms as it relies on receiving notifications. +// +// TODO(crbug.com/483018445): Check the kSuppressMemoryMonitor feature flag +// instead of buildflags once the feature is exposed publicly or moved to base. +// Currently, it is internal to components/memory_pressure. +#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) #define MAYBE_MemoryPressure DISABLED_MemoryPressure #else #define MAYBE_MemoryPressure MemoryPressure #endif // Tests that the session cache responds correctly to memory pressure events. TEST_F(SSLClientSessionCacheTest, MAYBE_MemoryPressure) { + base::test::ScopedFeatureList scoped_feature_list( + base::kStatefulMemoryPressure); base::test::TaskEnvironment task_environment( base::test::TaskEnvironment::MainThreadType::IO);
diff --git a/net/third_party/quiche/README.chromium b/net/third_party/quiche/README.chromium index f2540f5..38c0fd0 100644 --- a/net/third_party/quiche/README.chromium +++ b/net/third_party/quiche/README.chromium
@@ -1,6 +1,6 @@ Name: QUICHE URL: https://quiche.googlesource.com/quiche -Revision: 99a5e60cd6d87a0be2e8679ed91111d65a4abeda +Revision: b91dd3088416ab1c47cfc7a078d306e7a2c4fb6b Version: git Update Mechanism: Manual License: BSD-3-Clause
diff --git a/net/third_party/quiche/src b/net/third_party/quiche/src index 99a5e60..b91dd30 160000 --- a/net/third_party/quiche/src +++ b/net/third_party/quiche/src
@@ -1 +1 @@ -Subproject commit 99a5e60cd6d87a0be2e8679ed91111d65a4abeda +Subproject commit b91dd3088416ab1c47cfc7a078d306e7a2c4fb6b
diff --git a/net/url_request/url_request.cc b/net/url_request/url_request.cc index d33c1a3..f83485d 100644 --- a/net/url_request/url_request.cc +++ b/net/url_request/url_request.cc
@@ -1331,7 +1331,7 @@ IsolationInfo URLRequest::CreateIsolationInfoFromNetworkAnonymizationKey( const NetworkAnonymizationKey& network_anonymization_key) { - if (!network_anonymization_key.IsFullyPopulated()) { + if (network_anonymization_key.IsEmpty()) { return IsolationInfo(); }
diff --git a/sandbox/policy/mac/gpu.sb b/sandbox/policy/mac/gpu.sb index 9d98e44..9269f4f2c 100644 --- a/sandbox/policy/mac/gpu.sb +++ b/sandbox/policy/mac/gpu.sb
@@ -25,7 +25,6 @@ (global-name "com.apple.cvmsServ") (global-name "com.apple.gpumemd.source") (global-name "com.apple.lsd.mapdb") - (global-name "com.apple.lsd.modifydb") (global-name "com.apple.powerlog.plxpclogger.xpc") (global-name "com.apple.PowerManagement.control") (global-name "com.apple.SecurityServer") @@ -119,7 +118,10 @@ ) ; crbug.com/980134 -(allow file-read* file-write* +; Restrict file-write to data/create/unlink only — the GPU process does not need +; file-write-xattr or file-write-mode. +; TODO(crbug.com/491422244): Remove file-write-owner needed by WebNN. +(allow file-read* file-write-data file-write-create file-write-owner file-write-unlink (subpath (param darwin-user-cache-dir)) (subpath (param darwin-user-dir)) (subpath (param darwin-user-temp-dir))
diff --git a/services/accessibility/android/BUILD.gn b/services/accessibility/android/BUILD.gn index 891dc1a..e260c1d 100644 --- a/services/accessibility/android/BUILD.gn +++ b/services/accessibility/android/BUILD.gn
@@ -2,10 +2,11 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +assert(is_chromeos) + source_set("android_lib") { public_deps = [ "//ash/public/cpp", - "//chrome/app:generated_resources_grit", "//extensions/browser/api/automation_internal", "//services/accessibility/android/public/mojom", ] @@ -28,6 +29,8 @@ "pane_title_handler.cc", "pane_title_handler.h", ] + + deps = [ "//ash/strings" ] } static_library("test_support") {
diff --git a/services/accessibility/android/DEPS b/services/accessibility/android/DEPS index fbaa778..defd11c1 100644 --- a/services/accessibility/android/DEPS +++ b/services/accessibility/android/DEPS
@@ -1,6 +1,6 @@ include_rules = [ "+ash/public/cpp/app_types_util.h", - "+chrome/grit/generated_resources.h", + "+ash/strings", "+extensions/browser/api/automation_internal/automation_event_router.h", "+ui/accessibility", "+ui/base/l10n",
diff --git a/services/accessibility/android/accessibility_node_info_data_wrapper.cc b/services/accessibility/android/accessibility_node_info_data_wrapper.cc index 7256754..f3bd649 100644 --- a/services/accessibility/android/accessibility_node_info_data_wrapper.cc +++ b/services/accessibility/android/accessibility_node_info_data_wrapper.cc
@@ -6,10 +6,10 @@ #include <algorithm> +#include "ash/strings/grit/ash_strings.h" #include "base/memory/raw_ptr.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" -#include "chrome/grit/generated_resources.h" #include "services/accessibility/android/android_accessibility_util.h" #include "services/accessibility/android/ax_tree_source_android.h" #include "ui/accessibility/ax_enums.mojom.h"
diff --git a/services/accessibility/android/accessibility_node_info_data_wrapper_unittest.cc b/services/accessibility/android/accessibility_node_info_data_wrapper_unittest.cc index 39cea9f2..0154dbf 100644 --- a/services/accessibility/android/accessibility_node_info_data_wrapper_unittest.cc +++ b/services/accessibility/android/accessibility_node_info_data_wrapper_unittest.cc
@@ -8,8 +8,8 @@ #include <memory> #include <utility> +#include "ash/strings/grit/ash_strings.h" #include "base/memory/raw_ptr.h" -#include "chrome/grit/generated_resources.h" #include "services/accessibility/android/accessibility_window_info_data_wrapper.h" #include "services/accessibility/android/android_accessibility_util.h" #include "services/accessibility/android/ax_tree_source_android.h"
diff --git a/services/accessibility/android/accessibility_window_info_data_wrapper.cc b/services/accessibility/android/accessibility_window_info_data_wrapper.cc index ab70f63..175cb3eb5 100644 --- a/services/accessibility/android/accessibility_window_info_data_wrapper.cc +++ b/services/accessibility/android/accessibility_window_info_data_wrapper.cc
@@ -3,10 +3,10 @@ // found in the LICENSE file. #include "services/accessibility/android/accessibility_window_info_data_wrapper.h" -#include "base/memory/raw_ptr.h" +#include "ash/strings/grit/ash_strings.h" +#include "base/memory/raw_ptr.h" #include "base/notreached.h" -#include "chrome/grit/generated_resources.h" #include "services/accessibility/android/android_accessibility_util.h" #include "services/accessibility/android/ax_tree_source_android.h" #include "ui/accessibility/ax_enums.mojom.h"
diff --git a/services/device/geolocation/geolocation_provider_impl.cc b/services/device/geolocation/geolocation_provider_impl.cc index 0031e43..97513f2a 100644 --- a/services/device/geolocation/geolocation_provider_impl.cc +++ b/services/device/geolocation/geolocation_provider_impl.cc
@@ -124,9 +124,16 @@ OnClientsChanged(); if (base::FeatureList::IsEnabled( content_settings::features::kApproximateGeolocationPermission)) { - if (enable_high_accuracy && high_accuracy_result_) { - callback.Run(*high_accuracy_result_); - } else if (!enable_high_accuracy && low_accuracy_result_) { + if (enable_high_accuracy) { + // If high accuracy is requested, we prefer to return a cached + // high-accuracy result. If one is not available, we fall back to a + // cached low-accuracy result. + if (high_accuracy_result_) { + callback.Run(*high_accuracy_result_); + } else if (low_accuracy_result_) { + callback.Run(*low_accuracy_result_); + } + } else if (low_accuracy_result_) { callback.Run(*low_accuracy_result_); } } else { @@ -238,6 +245,7 @@ result_.reset(); low_accuracy_result_.reset(); high_accuracy_result_.reset(); + last_low_accuracy_result_time_ = base::TimeTicks(); } task_runner()->PostTask( FROM_HERE, base::BindOnce(&GeolocationProviderImpl::StopProviders, @@ -380,17 +388,28 @@ // When the `kApproximateGeolocationPermission` feature is enabled, // location updates are dispatched to the appropriate callbacks based on // the `is_precise` flag. - if (result->get_position()->is_precise) { + bool is_precise = result->get_position()->is_precise; + if (is_precise) { high_accuracy_result_ = std::move(result); high_accuracy_callbacks_.Notify(*high_accuracy_result_); } else { - low_accuracy_result_ = std::move(result); - low_accuracy_callbacks_.Notify(*low_accuracy_result_); - // When in concurrent mode, we also forward approximate location to - // precise request client. - if (!high_accuracy_callbacks_.empty()) { - high_accuracy_result_ = low_accuracy_result_.Clone(); - high_accuracy_callbacks_.Notify(*high_accuracy_result_); + base::TimeTicks now = base::TimeTicks::Now(); + // Approximate location updates are throttled to a 15-minute window. + // This prevents malicious sites from collecting enough approximate + // positions to reconstruct a precise location, significantly + // increasing the difficulty of such attacks. + if (!low_accuracy_result_ || !low_accuracy_result_->is_position() || + now - last_low_accuracy_result_time_ >= + kApproximateGeolocationUpdateInterval) { + low_accuracy_result_ = std::move(result); + last_low_accuracy_result_time_ = now; + low_accuracy_callbacks_.Notify(*low_accuracy_result_); + // When in concurrent mode, we also forward approximate location to + // precise request client. + if (!high_accuracy_callbacks_.empty()) { + high_accuracy_result_ = low_accuracy_result_.Clone(); + high_accuracy_callbacks_.Notify(*high_accuracy_result_); + } } } } else {
diff --git a/services/device/geolocation/geolocation_provider_impl.h b/services/device/geolocation/geolocation_provider_impl.h index f1b7c2d..e776cbf 100644 --- a/services/device/geolocation/geolocation_provider_impl.h +++ b/services/device/geolocation/geolocation_provider_impl.h
@@ -167,6 +167,9 @@ static constexpr char kSystemPermissionDeniedErrorTechnical[] = "User has not allowed access to system location"; + static constexpr base::TimeDelta kApproximateGeolocationUpdateInterval = + base::Minutes(15); + private: friend struct base::DefaultSingletonTraits<GeolocationProviderImpl>; GeolocationProviderImpl(); @@ -260,6 +263,8 @@ // accuracy level receive the correct location updates. mojom::GeopositionResultPtr high_accuracy_result_; mojom::GeopositionResultPtr low_accuracy_result_; + // The time when the last low accuracy result was notified. + base::TimeTicks last_low_accuracy_result_time_; // True only in testing, where we want to use a custom position. bool ignore_location_updates_ = false;
diff --git a/services/device/geolocation/geolocation_provider_impl_unittest.cc b/services/device/geolocation/geolocation_provider_impl_unittest.cc index 1d682f2f..1f05c35 100644 --- a/services/device/geolocation/geolocation_provider_impl_unittest.cc +++ b/services/device/geolocation/geolocation_provider_impl_unittest.cc
@@ -59,7 +59,8 @@ protected: GeolocationProviderTest() : task_environment_( - base::test::SingleThreadTaskEnvironment::MainThreadType::UI) { + base::test::SingleThreadTaskEnvironment::MainThreadType::UI, + base::test::SingleThreadTaskEnvironment::TimeSource::MOCK_TIME) { mojom::Geoposition& position1 = *position_result1_->get_position(); position1.latitude = 12; position1.longitude = 34; @@ -102,7 +103,6 @@ } void RunUntilIdle() { task_environment_.RunUntilIdle(); } - protected: // Called on test thread. void SetFakeLocationProviderManager(); bool ProvidersStarted(); @@ -124,6 +124,8 @@ GeolocationProviderImpl::kSystemPermissionDeniedErrorMessage, GeolocationProviderImpl::kSystemPermissionDeniedErrorTechnical)); + base::test::SingleThreadTaskEnvironment task_environment_; + private: // Called on provider thread. bool GetProvidersStarted(); @@ -137,8 +139,6 @@ // test completes. base::ShadowingAtExitManager at_exit_; - base::test::SingleThreadTaskEnvironment task_environment_; - base::ThreadChecker thread_checker_; // Owned by the GeolocationProviderImpl class. @@ -584,6 +584,110 @@ approximate_position_result_->get_position()->latitude); } +TEST_F(GeolocationProviderApproxGeoTest, + AddHighAccuracyCallbackWithLowAccuracyCache) { + SetFakeLocationProviderManager(); + SetSystemPermission(LocationSystemPermissionStatus::kAllowed); + + // 1. Send an approximate location update to populate the cache. + TestFuture<mojom::GeopositionResultPtr> low_accuracy_future; + base::MockCallback<GeolocationProviderImpl::LocationUpdateCallback> + low_accuracy_callback; + EXPECT_CALL(low_accuracy_callback, Run) + .WillOnce([&](const mojom::GeopositionResult& result) { + low_accuracy_future.SetValue(result.Clone()); + }); + base::CallbackListSubscription low_accuracy_subscription = + provider()->AddLocationUpdateCallback(low_accuracy_callback.Get(), + /*enable_high_accuracy=*/false); + SendMockLocation(*approximate_position_result_); + EXPECT_TRUE(low_accuracy_future.Wait()); + + // 2. Add a high accuracy callback. It should receive the cached approximate + // location result immediately. + base::MockCallback<GeolocationProviderImpl::LocationUpdateCallback> + high_accuracy_callback; + TestFuture<mojom::GeopositionResultPtr> high_accuracy_future; + EXPECT_CALL(high_accuracy_callback, Run) + .WillOnce([&](const mojom::GeopositionResult& result) { + high_accuracy_future.SetValue(result.Clone()); + }); + base::CallbackListSubscription high_accuracy_subscription = + provider()->AddLocationUpdateCallback(high_accuracy_callback.Get(), + /*enable_high_accuracy=*/true); + EXPECT_EQ(high_accuracy_future.Get()->get_position()->latitude, + approximate_position_result_->get_position()->latitude); +} + +TEST_F(GeolocationProviderApproxGeoTest, ThrottlingApproximateUpdates) { + SetFakeLocationProviderManager(); + SetSystemPermission(LocationSystemPermissionStatus::kAllowed); + + base::test::TestFuture<mojom::GeopositionResultPtr> low_accuracy_future; + + base::MockCallback<GeolocationProviderImpl::LocationUpdateCallback> + low_accuracy_callback; + EXPECT_CALL(low_accuracy_callback, Run) + .WillRepeatedly([&](const mojom::GeopositionResult& result) { + low_accuracy_future.SetValue(result.Clone()); + }); + base::CallbackListSubscription low_accuracy_subscription = + provider()->AddLocationUpdateCallback(low_accuracy_callback.Get(), + /*enable_high_accuracy=*/false); + + // 1. First approximate update should be delivered. + SendMockLocation(*approximate_position_result_); + auto result1 = low_accuracy_future.Take(); + EXPECT_TRUE(result1->is_position()); + EXPECT_EQ(result1->get_position()->latitude, + approximate_position_result_->get_position()->latitude); + + // 2. Subsequent update within 15 minutes should be ignored. + auto second_approx_result = approximate_position_result_.Clone(); + second_approx_result->get_position()->latitude = 5.0; + SendMockLocation(*second_approx_result); + + // Deterministically flush the Geolocation thread and then the Main thread. + // Since SendMockLocation posts to Geolocation, which then posts back to Main, + // a PostTaskAndReply to Geolocation will arrive at Main AFTER the + // location update has been processed. + base::test::TestFuture<void> flush_future; + provider()->task_runner()->PostTaskAndReply(FROM_HERE, base::DoNothing(), + flush_future.GetCallback()); + EXPECT_TRUE(flush_future.Wait()); + EXPECT_FALSE(low_accuracy_future.IsReady()); + + // 3. Fast-forward 14 minutes (still within 15 mins) - still ignored. + task_environment_.FastForwardBy(base::Minutes(14)); + SendMockLocation(*second_approx_result); + base::test::TestFuture<void> flush_future2; + provider()->task_runner()->PostTaskAndReply(FROM_HERE, base::DoNothing(), + flush_future2.GetCallback()); + EXPECT_TRUE(flush_future2.Wait()); + EXPECT_FALSE(low_accuracy_future.IsReady()); + + // 4. Fast-forward past 15 minutes - next update should be accepted. + task_environment_.FastForwardBy(base::Minutes(2)); // Total 16 mins + SendMockLocation(*second_approx_result); + auto result2 = low_accuracy_future.Take(); + EXPECT_TRUE(result2->is_position()); + EXPECT_EQ(result2->get_position()->latitude, 5.0); + + // 5. Error should always be delivered and reset throttling. + SendMockLocation(*error_result_); + auto result3 = low_accuracy_future.Take(); + EXPECT_TRUE(result3->is_error()); + + // Since last successful result was just replaced by an error, + // the next successful result should be delivered immediately. + auto third_approx_result = approximate_position_result_.Clone(); + third_approx_result->get_position()->latitude = 7.0; + SendMockLocation(*third_approx_result); + auto result4 = low_accuracy_future.Take(); + EXPECT_TRUE(result4->is_position()); + EXPECT_EQ(result4->get_position()->latitude, 7.0); +} + #if BUILDFLAG(OS_LEVEL_GEOLOCATION_PERMISSION_SUPPORTED) TEST_F(GeolocationProviderTest, StartProviderAfterSystemPermissionGranted) { SetFakeLocationProviderManager();
diff --git a/services/device/public/cpp/usb/tools/usb_ids.py b/services/device/public/cpp/usb/tools/usb_ids.py index 81fe0d7..0294766 100644 --- a/services/device/public/cpp/usb/tools/usb_ids.py +++ b/services/device/public/cpp/usb/tools/usb_ids.py
@@ -14,6 +14,7 @@ name = name.replace("\\", "\\\\") name = name.replace('"', r'\"') name = name.replace("?", r"\?") + name = name.replace('\0', r'\u0000') return name def ParseTable(input_path): @@ -46,7 +47,21 @@ return table -def GenerateDeviceDefinitions(table): +def GenerateStringRelPointer(data, output_tables): + # At time of writing, there are 1232 strings that appear more than once in the + # USB ID database. + # Since this script concatenates all strings together, rather than leaving + # them as individual literals, the linker can't deduplicate them for us + # anymore; so do it manually here. + if data not in output_tables["offset_by_string"]: + data_with_nul = data + '\0' + output_tables["offset_by_string"][data] = output_tables["string_bytes"] + output_tables["strings"].append(data_with_nul) + output_tables["string_bytes"] += len(bytes(data_with_nul, 'utf-8')) + off = output_tables["offset_by_string"][data] + return "base::subtle::IndexPointer<char, device::usb_strings>("+str(off)+")" + +def GenerateDeviceDefinitions(table, output_tables): output = "" for vendor_id in sorted(table.keys()): @@ -57,13 +72,15 @@ output += "static const UsbProduct vendor_%.4x_products[] = {\n" % \ vendor["id"] for product in vendor["products"]: - output += " {0x%.4x, \"%s\"},\n" % (product["id"], - EscapeName(product["name"])) + output += " {0x%.4x, %s/*%s*/},\n" % ( + product["id"], + GenerateStringRelPointer(product["name"], output_tables), + product["name"]) output += "};\n" return output -def GenerateVendorDefinitions(table): +def GenerateVendorDefinitions(table, output_tables): output = "static const UsbVendor vendors[] = {\n" for vendor_id in sorted(table.keys()): @@ -72,9 +89,11 @@ product_table = "{}" if len(vendor["products"]) != 0: product_table = "vendor_%.4x_products" % (vendor["id"]) - output += " {\"%s\", %s, 0x%.4x},\n" % (EscapeName(vendor["name"]), - product_table, - vendor["id"]) + output += " {%s/*%s*/, 0x%.4x, %s},\n" % ( + GenerateStringRelPointer(vendor["name"], output_tables), + vendor["name"], + vendor["id"], + product_table) output += "};\n" output += "const base::span<const UsbVendor> UsbIds::vendors_ = vendors;\n" @@ -89,19 +108,26 @@ (opts, args) = parser.parse_args() table = ParseTable(opts.input) + output_tables = {"strings":[], "string_bytes":0, "offset_by_string":{}} + + device_definitions = GenerateDeviceDefinitions(table, output_tables) + vendor_definitions = GenerateVendorDefinitions(table, output_tables) + output = """// Generated from %s #ifndef GENERATED_USB_IDS_H_ #define GENERATED_USB_IDS_H_ #include <stddef.h> +#include "base/memory/index_pointer.h" #include "services/device/public/cpp/usb/usb_ids.h" namespace device { """ % (opts.input) - output += GenerateDeviceDefinitions(table) - output += GenerateVendorDefinitions(table) + output += "const char usb_strings[] = \"" + EscapeName(''.join(output_tables["strings"])) + "\";" + output += device_definitions + output += vendor_definitions output += """ } // namespace device
diff --git a/services/device/public/cpp/usb/usb_ids.cc b/services/device/public/cpp/usb/usb_ids.cc index e15342f2..6b0ac87 100644 --- a/services/device/public/cpp/usb/usb_ids.cc +++ b/services/device/public/cpp/usb/usb_ids.cc
@@ -10,7 +10,10 @@ // static const UsbVendor* UsbIds::FindVendor(uint16_t vendor_id) { - const UsbVendor key = {/*name=*/{}, /*products=*/{}, vendor_id}; + const UsbVendor key = { + /*unused name*/ base::subtle::IndexPointer<char, usb_strings>(0), + vendor_id, + /*products=*/{}}; auto it = std::ranges::lower_bound( vendors_, key, [](const auto& a, const auto& b) { return a.id < b.id; }); if (it == vendors_.end() || it->id != vendor_id) { @@ -35,7 +38,9 @@ return nullptr; } - const UsbProduct key = {product_id, /*name=*/{}}; + const UsbProduct key = { + product_id, + /*unused name*/ base::subtle::IndexPointer<char, usb_strings>(0)}; auto it = std::ranges::lower_bound( vendor->products, key, [](const auto& a, const auto& b) { return a.id < b.id; });
diff --git a/services/device/public/cpp/usb/usb_ids.h b/services/device/public/cpp/usb/usb_ids.h index 5f9d030..c941e2f4 100644 --- a/services/device/public/cpp/usb/usb_ids.h +++ b/services/device/public/cpp/usb/usb_ids.h
@@ -9,13 +9,16 @@ #include <stdint.h> #include "base/containers/span.h" +#include "base/memory/index_pointer.h" #include "base/memory/raw_ptr_exclusion.h" namespace device { +extern const char usb_strings[]; + struct UsbProduct { const uint16_t id; - const char* name; + base::subtle::IndexPointer<char, usb_strings> name; }; // This structure is used in an array so the cumulative size is significant. @@ -23,10 +26,10 @@ // Chose field size based on contained data to further reduce structure size. // For example, uint16_t instead of size_t. struct UsbVendor { - const char* name; + base::subtle::IndexPointer<char, usb_strings> name; + const uint16_t id; // TODO(367764863) Rewrite to base::raw_span. RAW_PTR_EXCLUSION const base::span<const UsbProduct> products; - const uint16_t id; }; // UsbIds provides a static mapping from a vendor ID to a name, as well as a
diff --git a/services/network/network_service_unittest.cc b/services/network/network_service_unittest.cc index 39d8675f..dfe51a9 100644 --- a/services/network/network_service_unittest.cc +++ b/services/network/network_service_unittest.cc
@@ -1136,13 +1136,12 @@ // Tests that NetworkService::SetMaxConnectionsPerProxyChain() (1) modifies // globals in net::ClientSocketPoolManager (2) saturates out of bound values. TEST_F(NetworkServiceTest, SetMaxConnectionsPerProxyChain) { - const size_t kDefault = net::kDefaultMaxSocketsPerProxyChain; + const size_t kDefault = 32; const size_t kMin = 6; const size_t kMax = 99; // Starts off at default value. - EXPECT_EQ(net::kDefaultMaxSocketsPerProxyChain, - GetGlobalMaxConnectionsPerProxyChain()); + EXPECT_EQ(kDefault, GetGlobalMaxConnectionsPerProxyChain()); // Anything less than kMin saturates to kMin. service()->SetMaxConnectionsPerProxyChain(kMin - 1);
diff --git a/services/on_device_model/ml/chrome_ml.cc b/services/on_device_model/ml/chrome_ml.cc index 4f58572..61f70149 100644 --- a/services/on_device_model/ml/chrome_ml.cc +++ b/services/on_device_model/ml/chrome_ml.cc
@@ -11,6 +11,7 @@ #include "base/check.h" #include "base/compiler_specific.h" #include "base/debug/crash_logging.h" +#include "base/logging.h" #include "base/memory/ptr_util.h" #include "base/memory/ref_counted.h" #include "base/metrics/histogram_functions.h" @@ -87,6 +88,7 @@ // Collect crash reports on unknown errors. NOTREACHED() << "ChromeML(GPU) Error: " << msg; } else { + LOG(ERROR) << "Terminating On-Device Model Service: " << msg_str; base::Process::TerminateCurrentProcessImmediately(0); } }
diff --git a/services/webnn/tflite/graph_builder_tflite.cc b/services/webnn/tflite/graph_builder_tflite.cc index 9cc896a..984596dc 100644 --- a/services/webnn/tflite/graph_builder_tflite.cc +++ b/services/webnn/tflite/graph_builder_tflite.cc
@@ -755,21 +755,27 @@ // https://source.chromium.org/chromium/chromium/src/+/main:third_party/tflite/src/tensorflow/lite/kernels/internal/reference/gather.h;l=43;drc=49db932a0bdfca060c3e8b0d063a7e8c9f5d2fa5 /*gather_input=*/ {kFloat16To32AndInt8To64AndUint8, SupportedRanks::NonScalarUpTo(8)}, + // Clamping indices to the input dimensions requires a broadcasting + // MIN/MAX op, which is limited to 5D. /*gather_indices=*/ {DataTypeConstraint::kGatherScatterIndicesSupportedDataTypes, - SupportedRanks::UpTo(8)}, + SupportedRanks::UpTo(5)}, // Scalar is not supported: // https://source.chromium.org/chromium/chromium/src/+/main:third_party/tflite/src/tensorflow/lite/kernels/gather_nd.cc /*gather_elements_input=*/ {kFloat16To32AndInt8To64AndUint8, SupportedRanks::NonScalarUpTo(8)}, + // Clamping indices to the input dimensions requires a broadcasting + // MIN/MAX op, which is limited to 5D. /*gather_elements_indices=*/ {DataTypeConstraint::kGatherScatterIndicesSupportedDataTypes, - SupportedRanks::NonScalarUpTo(8)}, + SupportedRanks::NonScalarUpTo(5)}, /*gather_nd_input=*/ {kFloat16To32AndInt8To64AndUint8, SupportedRanks::NonScalarUpTo(8)}, + // Clamping indices to the input dimensions requires a broadcasting + // MIN/MAX op, which is limited to 5D. /*gather_nd_indices=*/ {DataTypeConstraint::kGatherScatterIndicesSupportedDataTypes, - SupportedRanks::NonScalarUpTo(8)}, + SupportedRanks::NonScalarUpTo(5)}, /*gelu_input=*/ {DataTypeConstraint::kFloat16To32, SupportedRanks::UpTo(8)}, /*gemm_a=*/ @@ -884,8 +890,10 @@ {kFloat16To32AndInt8To64AndUint32, SupportedRanks::NonScalarUpTo(8)}, // The indices of tfl.scatter_nd only support int32. // https://www.tensorflow.org/mlir/tfl_ops#operands_117 + // Clamping indices to the input dimensions requires a broadcasting + // MIN/MAX op, which is limited to 5D. /*scatter_nd_indices=*/ - {{OperandDataType::kInt32}, SupportedRanks::NonScalarUpTo(8)}, + {{OperandDataType::kInt32}, SupportedRanks::NonScalarUpTo(5)}, /*scatter_nd_updates=*/ {kFloat16To32AndInt8To64AndUint32, SupportedRanks::NonScalarUpTo(8)}, // Polyfilled with linear. @@ -4053,6 +4061,23 @@ } } + if (conv2d.kind == mojom::Conv2d::Kind::kTransposed) { + // Calculate the col2im temp tensor size [input_height * input_width, + // filter_height * filter_width * output_depth]. + const base::CheckedNumeric<int32_t> col2im_elements = + base::CheckedNumeric<int32_t>(input_size2d.height) * + input_size2d.width * filter_size2d.height * filter_size2d.width * + output_channels; + + // Check against the 32-bit signed integer limit to avoid overflow in + // TFLite. + if (!col2im_elements.IsValid()) { + return base::unexpected( + "convTranspose2d doesn't support configurations that require an " + "internal computation buffer exceeding INT32_MAX elements."); + } + } + ASSIGN_OR_RETURN( TfLitePadding padding_mode, GetTfLitePaddingMode(*conv2d.padding, input_size2d, filter_size2d,
diff --git a/services/webnn/webnn_graph_builder_impl.cc b/services/webnn/webnn_graph_builder_impl.cc index 2e3d595c..f79ca683 100644 --- a/services/webnn/webnn_graph_builder_impl.cc +++ b/services/webnn/webnn_graph_builder_impl.cc
@@ -2789,7 +2789,8 @@ bool use_xnnpack = false; #if BUILDFLAG(BUILD_TFLITE_WITH_XNNPACK) if (base::FeatureList::IsEnabled( - kWebNNUseXNNPackForConstantTransposeFolding)) { + kWebNNUseXNNPackForConstantTransposeFolding) && + rank <= XNN_MAX_TENSOR_DIMS) { use_xnnpack = true; } #endif // BUILDFLAG(BUILD_TFLITE_WITH_XNNPACK)
diff --git a/sql/database.cc b/sql/database.cc index 95c3739..8c330359 100644 --- a/sql/database.cc +++ b/sql/database.cc
@@ -70,6 +70,7 @@ #include "sql/statement_id.h" #include "sql/streaming_blob_handle.h" #include "sql/transaction.h" +#include "third_party/abseil-cpp/absl/cleanup/cleanup.h" #include "third_party/perfetto/include/perfetto/tracing/traced_proto.h" #include "third_party/sqlite/sqlite3.h" @@ -578,6 +579,11 @@ DCHECK_NE(path_string, kSqliteOpenInMemoryPath) << "Path conflicts with SQLite magic identifier"; + absl::Cleanup report_success = [this, open_timer = base::ElapsedTimer()] { + RecordTimingHistogram("Sql.Database.DatabaseOpenTime.", + open_timer.Elapsed()); + }; + // Preload the database before opening it to ensure it's working with the // exclusive mode. if (options_.preload_) {
diff --git a/sql/database_unittest.cc b/sql/database_unittest.cc index 02f3561f..16988ff 100644 --- a/sql/database_unittest.cc +++ b/sql/database_unittest.cc
@@ -2598,6 +2598,7 @@ ASSERT_TRUE(db_->Open(db_path_)); tester.ExpectTotalCount("Sql.Database.Success.SqliteOpenTime.Test", 1); tester.ExpectTotalCount("Sql.Database.Success.OpenInternalTime.Test", 1); + tester.ExpectTotalCount("Sql.Database.DatabaseOpenTime.Test", 1); } TEST_P(SQLDatabaseTest, OpenFailsAfterCorruptSizeInHeader) { @@ -2847,11 +2848,13 @@ tester.ExpectTotalCount("Sql.Database.Success.OpenInternalTime.Test", 1); tester.ExpectTotalCount("Sql.Database.Success.SqliteOpenTime.Test", 1); + tester.ExpectTotalCount("Sql.Database.DatabaseOpenTime.Test", 1); ASSERT_NO_FATAL_FAILURE(OpenDatabase(false)); tester.ExpectTotalCount("Sql.Database.Success.OpenInternalTime.Test", 2); tester.ExpectTotalCount("Sql.Database.Success.SqliteOpenTime.Test", 2); + tester.ExpectTotalCount("Sql.Database.DatabaseOpenTime.Test", 2); } TEST_P(ReadOnlySQLDatabaseTest, CreateAndSelect) {
diff --git a/testing/buildbot/chrome.json b/testing/buildbot/chrome.json index bdec476f..fdd46f8c 100644 --- a/testing/buildbot/chrome.json +++ b/testing/buildbot/chrome.json
@@ -372,6 +372,7 @@ "libfake" ], "autotest_name": "chromium", + "ci_only": true, "cros_board": "betty", "dut_pool": "vmlab", "experiment_percentage": 100, @@ -645,6 +646,7 @@ "--gtest_filter=\"VaapiTest.*\"" ], "autotest_name": "chromium", + "ci_only": true, "cros_board": "betty", "dut_pool": "vmlab", "experiment_percentage": 100, @@ -873,6 +875,7 @@ "libfake" ], "autotest_name": "chromium", + "ci_only": true, "cros_board": "betty", "dut_pool": "vmlab", "experiment_percentage": 100, @@ -1146,6 +1149,7 @@ "--gtest_filter=\"VaapiTest.*\"" ], "autotest_name": "chromium", + "ci_only": true, "cros_board": "betty", "dut_pool": "vmlab", "experiment_percentage": 100, @@ -1546,6 +1550,7 @@ "libfake" ], "autotest_name": "chromium", + "ci_only": true, "cros_board": "betty", "dut_pool": "vmlab", "experiment_percentage": 100, @@ -1819,6 +1824,7 @@ "--gtest_filter=\"VaapiTest.*\"" ], "autotest_name": "chromium", + "ci_only": true, "cros_board": "betty", "dut_pool": "vmlab", "experiment_percentage": 100,
diff --git a/testing/buildbot/mixins.pyl b/testing/buildbot/mixins.pyl index ff284015..0469bd5 100644 --- a/testing/buildbot/mixins.pyl +++ b/testing/buildbot/mixins.pyl
@@ -155,6 +155,9 @@ }, }, }, + 'ci_only': { + 'ci_only': True, + }, 'crosier-no-arc': { 'args': [ '--test-launcher-filter-file=../../testing/buildbot/filters/chromeos.reven.chromeos_integration_tests.filter',
diff --git a/testing/libfuzzer/fuzz_test_coverage.md b/testing/libfuzzer/fuzz_test_coverage.md index 762687a..aee4f8c1 100644 --- a/testing/libfuzzer/fuzz_test_coverage.md +++ b/testing/libfuzzer/fuzz_test_coverage.md
@@ -1,31 +1,33 @@ # Generating Local Code Coverage for Fuzz Tests -This guide explains how to generate a local code coverage report for a FuzzTest -integrated into a gtest suite. This is useful for visualizing which code paths -your new fuzz test exercises, ensuring it covers the intended logic before you -upload a CL. +This document explains how to generate a local code coverage report for a +FuzzTest integrated into a gtest suite. A local coverage report helps you +visualize which code paths your fuzz test exercises so you can verify the logic +before you upload a CL. -We will use the central -[coverage.py script](https://chromium.googlesource.com/chromium/src/+/HEAD/docs/testing/code_coverage.md#local-coverage-script), -which automates the process of building with coverage instrumentation, running -the test, and generating an HTML report. +To complete this process, use the +[coverage.py script](https://chromium.googlesource.com/chromium/src/+/HEAD/docs/testing/code_coverage.md#local-coverage-script) +script to automate building with coverage instrumentation, running the test, and +generating an HTML report. -## Step 1: Ensure Your Toolchain is Up to Date +## Update the toolchain -The coverage script and build system depend on the Clang compiler and specific -LLVM tools. Before starting, ensure these are downloaded and current. From the -src directory, run: +The coverage script and build system require the Clang compiler and specific +LLVM tools. -``` -# This downloads the main Clang compiler needed for the build. +In your terminal, navigate to the src directory and update the required tools: + +```shell vpython3 tools/clang/scripts/update.py ``` -## Step 2: Configure the Build with GN +## Configure the build -From the src directory, run: +Create a dedicated build configuration for your coverage build. -``` +In your terminal, from the src directory, generate the configuration: + +```shell # It's recommended to use a descriptive name like 'out/fuzz_coverage' # to keep it separate from your regular builds. gn gen out/fuzz_coverage --args=' @@ -33,71 +35,106 @@ is_component_build=false is_debug=false dcheck_always_on=true -use_remoteexec=true -' +use_remoteexec=true' ``` -### Argument Breakdown: +### Argument breakdown: -* `use_clang_coverage=true`: The essential flag that instructs the compiler to - add coverage instrumentation. -* `is_component_build=false`: Required for coverage builds to work correctly. -* `is_debug=false`: Coverage works best with optimized builds. -* `dcheck_always_on=true`: Recommended for catching issues during test runs. -* `use_remoteexec=true`: Recommended for compiling Chromium fast. +* `use_clang_coverage=true`: Instructs the compiler to add coverage + instrumentation. +* `is_component_build=false`: (Recommended) Code coverage instrumentation + works with both component and non-component builds, but setting this to true + causes the tests to run significantly slower. +* `is_debug=false`: (Recommended) Optimizes the build for coverage. +* `dcheck_always_on=true`: (Recommended) Catches issues during test runs. +* `use_remoteexec=true`: (Recommended) Compiles Chromium fast. -## Step 3: Build the Instrumented Test Target +## Build the test target Compile the test suite that contains your FuzzTest. For example, if your fuzz test `MyFuzzer.MyTest` is located in `//foo/my_fuzzer_unittest.cc`, and this file is part of the `foo_unittests` target, you would build `foo_unittests`. -``` +In your terminal, compile the test target: + +```shell # Replace foo_unittests with your actual test target autoninja -C out/fuzz_coverage foo_unittests ``` -## Step 4: Run the Coverage Script +## Run the coverage script -Now, execute the `coverage.py` script. The key is to use the `--gtest_filter` -argument to run only your specific fuzz test. This gives you a precise report on -the coverage contributed by that test alone. +Run the `coverage.py` script. Use the `--gtest_filter` argument to run only your +specific fuzz test. Isolating the test produces a precise report on the coverage +contributed by that test alone. -``` +In your terminal, run the script: + +```shell # Customize the arguments below for your specific test. vpython3 tools/code_coverage/coverage.py \ - foo_unittests \ - -b out/fuzz_coverage \ - -o out/my_fuzz_test_report \ - -c 'out/fuzz_coverage/foo_unittests --gtest_filter=MyFuzzTestSuite.*' \ - -f foo/ \ - --no-component-view +foo_unittests \ +-b out/fuzz_coverage \ +-o out/my_fuzz_test_report \ +-c 'out/fuzz_coverage/foo_unittests --gtest_filter=MyFuzzTestSuite.*' \ +-f foo/ \ +--no-component-view ``` -#### Command Breakdown: +### Command breakdown: -* `foo_unittests`: The name of the test target you are analyzing. +* `foo_unittests`: Specifies the test target you are analyzing. * `-b out/fuzz_coverage`: Specifies the build directory from Step 2. -* `-o out/my_fuzz_test_report`: A new directory where the final HTML report - will be saved. -* `-c '...'`: The exact command to execute. - * `out/fuzz_coverage/foo_unittests`: The path to the instrumented test +* `-o out/my_fuzz_test_report`: Specifies the output directory for the final + HTML report. +* `-c '...'`: Defines the command to execute the test binary. + * `out/fuzz_coverage/foo_unittests`: Specifies the path to the test binary. - * `--gtest_filter=MyFuzzTestSuite.*`: (Crucial) Isolates your fuzz test. - Replace MyFuzzTestSuite with the name of your test suite. Using .* runs - all tests within that suite. -* `-f foo/`: (Optional, but highly recommended) Filters the report to only - show files in the specified directory, making it easier to analyze your - changes. + * `--gtest_filter=MyFuzzTestSuite.*`: Isolates your fuzz test. Replace + MyFuzzTestSuite with the name of your test suite. Using .* runs all + tests within that suite. +* `-f foo/`: (Recommended) Filters the report to only show files in the + specified directory. * `--no-component-view`: Prevents the script from fetching a - directory-to-component mapping from the network, which can avoid potential - 403 Forbidden errors in some network environments. + directory-to-component mapping from the network, which avoids a 403 + Forbidden error. -## Step 5: View the Report +## View the report -The script will generate a set of HTML files in the output directory you -specified (-o). Open the main index.html file in a browser to view the report. +The script generates a set of HTML files in your specified output directory. To +organize the data, the script creates a sub-directory named after your target +operating system (for example, `linux`, `mac`, or `win`). The index.html file is +located inside this platform sub-directory. -Navigate through the directory view to your changed files. Lines covered by your -fuzz test will be highlighted in green, giving you a clear visual confirmation -of its impact. +### View on a local machine + +If you build the test on your local machine, open the +`out/my_fuzz_test_report/<PLATFORM>/index.html` file in a browser. Replace +`<PLATFORM>` with your target operating system + +### View from a remote machine + +If you build the test on a remote machine or virtual machine, start an HTTP +server to access the report from your local browser. + +In your remote terminal, navigate to the out directory: + +```shell +cd out/my_fuzz_test_report +``` + +Start an HTTP server: + +```shell +python3 -m http.server 8000 +``` + +On your local machine, open a browser and navigate to +`<REMOTE_IP>:8000/<PLATFORM>/index.html`. Replace `<REMOTE_IP>` with your remote +machine's IP address or hostname, and replace `<PLATFORM>` with your target +operating system (for example, `linux`). + + +When you open the report, navigate the directory view to your changed files. The +report highlights lines covered by your fuzz test in green so you can verify the +test's impact.
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index b6d8f0e..c3e81c1 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -9563,6 +9563,24 @@ ] } ], + "ExtensionServiceWorkerVoter": [ + { + "platforms": [ + "chromeos", + "linux", + "mac", + "windows" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "ExtensionServiceWorkerVoter" + ] + } + ] + } + ], "ExtensionsToolbarAndMenuRedesign": [ { "platforms": [ @@ -12513,21 +12531,6 @@ ] } ], - "IOSManualLogUploadsInTheFRE": [ - { - "platforms": [ - "ios" - ], - "experiments": [ - { - "name": "Enabled", - "enable_features": [ - "ManualLogUploadsInTheFRE" - ] - } - ] - } - ], "IOSMostVisitedTilesCustomization": [ { "platforms": [ @@ -17873,6 +17876,21 @@ ] } ], + "Prerender2WarmUpCompositorForWebView": [ + { + "platforms": [ + "android_webview" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "Prerender2WarmUpCompositorForWebView" + ] + } + ] + } + ], "PreserveDiscardableImageMapQuality": [ { "platforms": [ @@ -24791,26 +24809,6 @@ ] } ], - "WhatsNewRefresh": [ - { - "platforms": [ - "linux", - "mac", - "windows" - ], - "experiments": [ - { - "name": "Enabled", - "params": { - "en_site_id": "p5xavcMU50ugnJ3q1cK0R26c3Tsi" - }, - "enable_features": [ - "WhatsNewDesktopRefresh" - ] - } - ] - } - ], "WidevinePersistentLicenseSupport": [ { "platforms": [
diff --git a/third_party/android_deps/autorolled/VERSION.txt b/third_party/android_deps/autorolled/VERSION.txt index 6cdc9b5..366621b2 100644 --- a/third_party/android_deps/autorolled/VERSION.txt +++ b/third_party/android_deps/autorolled/VERSION.txt
@@ -1 +1 @@ -f36d9ba44179b7a.c7def96894a3cd1 \ No newline at end of file +22f398fc87d9d94.d02a74a4e608b5b \ No newline at end of file
diff --git a/third_party/android_deps/autorolled/bill_of_materials.json b/third_party/android_deps/autorolled/bill_of_materials.json index d1fea271..fffe4013 100644 --- a/third_party/android_deps/autorolled/bill_of_materials.json +++ b/third_party/android_deps/autorolled/bill_of_materials.json
@@ -2,17 +2,17 @@ { "name": "activity", "group": "androidx.activity", - "version": "1.13.0" + "version": "1.14.0-SNAPSHOT" }, { "name": "activity-compose", "group": "androidx.activity", - "version": "1.13.0" + "version": "1.14.0-SNAPSHOT" }, { "name": "activity-ktx", "group": "androidx.activity", - "version": "1.13.0" + "version": "1.14.0-SNAPSHOT" }, { "name": "annotation", @@ -1642,7 +1642,17 @@ { "name": "dalvik-dx", "group": "com.jakewharton.android.repackaged", - "version": "11.0.0_r3" + "version": "9.0.0_r3" + }, + { + "name": "dexmaker", + "group": "com.linkedin.dexmaker", + "version": "2.28.6" + }, + { + "name": "dexmaker-mockito-inline", + "group": "com.linkedin.dexmaker", + "version": "2.28.6" }, { "name": "curtains", @@ -1782,52 +1792,52 @@ { "name": "grpc-android", "group": "io.grpc", - "version": "1.79.0" + "version": "1.80.0" }, { "name": "grpc-api", "group": "io.grpc", - "version": "1.79.0" + "version": "1.80.0" }, { "name": "grpc-binder", "group": "io.grpc", - "version": "1.79.0" + "version": "1.80.0" }, { "name": "grpc-context", "group": "io.grpc", - "version": "1.79.0" + "version": "1.80.0" }, { "name": "grpc-core", "group": "io.grpc", - "version": "1.79.0" + "version": "1.80.0" }, { "name": "grpc-inprocess", "group": "io.grpc", - "version": "1.79.0" + "version": "1.80.0" }, { "name": "grpc-protobuf-lite", "group": "io.grpc", - "version": "1.79.0" + "version": "1.80.0" }, { "name": "grpc-stub", "group": "io.grpc", - "version": "1.79.0" + "version": "1.80.0" }, { "name": "grpc-testing", "group": "io.grpc", - "version": "1.79.0" + "version": "1.80.0" }, { "name": "grpc-util", "group": "io.grpc", - "version": "1.79.0" + "version": "1.80.0" }, { "name": "perfmark-api", @@ -1862,17 +1872,12 @@ { "name": "byte-buddy", "group": "net.bytebuddy", - "version": "1.17.6" + "version": "1.17.7" }, { "name": "byte-buddy-agent", "group": "net.bytebuddy", - "version": "1.17.6" - }, - { - "name": "byte-buddy-android", - "group": "net.bytebuddy", - "version": "1.17.6" + "version": "1.17.7" }, { "name": "bcprov-jdk18on", @@ -2062,17 +2067,17 @@ { "name": "mockito-android", "group": "org.mockito", - "version": "5.19.0" + "version": "5.23.0" }, { "name": "mockito-core", "group": "org.mockito", - "version": "5.19.0" + "version": "5.23.0" }, { "name": "mockito-subclass", "group": "org.mockito", - "version": "5.19.0" + "version": "5.23.0" }, { "name": "objenesis",
diff --git a/third_party/android_deps/autorolled/build.gradle b/third_party/android_deps/autorolled/build.gradle index 317e760..541819d 100644 --- a/third_party/android_deps/autorolled/build.gradle +++ b/third_party/android_deps/autorolled/build.gradle
@@ -14,9 +14,9 @@ // cache the resolved values of all the '+' versions when we are not trying to // roll (e.g. when the main project imports this subproject). project.ext.versionCache = [:] -versionCache['androidx.activity:activity'] = '1.13.0' -versionCache['androidx.activity:activity-compose'] = '1.13.0' -versionCache['androidx.activity:activity-ktx'] = '1.13.0' +versionCache['androidx.activity:activity'] = '1.14.0-SNAPSHOT' +versionCache['androidx.activity:activity-compose'] = '1.14.0-SNAPSHOT' +versionCache['androidx.activity:activity-ktx'] = '1.14.0-SNAPSHOT' versionCache['androidx.annotation:annotation'] = '1.10.0-alpha01' versionCache['androidx.annotation:annotation-experimental'] = '1.6.0-rc01' versionCache['androidx.annotation:annotation-jvm'] = '1.10.0-alpha01' @@ -342,7 +342,9 @@ versionCache['com.google.testparameterinjector:test-parameter-injector'] = '1.18' versionCache['com.googlecode.java-diff-utils:diffutils'] = '1.3.0' versionCache['com.ibm.icu:icu4j'] = '77.1' -versionCache['com.jakewharton.android.repackaged:dalvik-dx'] = '11.0.0_r3' +versionCache['com.jakewharton.android.repackaged:dalvik-dx'] = '9.0.0_r3' +versionCache['com.linkedin.dexmaker:dexmaker'] = '2.28.6' +versionCache['com.linkedin.dexmaker:dexmaker-mockito-inline'] = '2.28.6' versionCache['com.squareup.curtains:curtains'] = '1.2.4' versionCache['com.squareup.leakcanary:leakcanary-android'] = '3.0-alpha-8' versionCache['com.squareup.leakcanary:leakcanary-android-core'] = '3.0-alpha-8' @@ -370,25 +372,24 @@ versionCache['com.squareup.wire:wire-runtime-jvm'] = '6.0.0' versionCache['com.squareup:javapoet'] = '1.13.0' versionCache['com.squareup:javawriter'] = '2.1.1' -versionCache['io.grpc:grpc-android'] = '1.79.0' -versionCache['io.grpc:grpc-api'] = '1.79.0' -versionCache['io.grpc:grpc-binder'] = '1.79.0' -versionCache['io.grpc:grpc-context'] = '1.79.0' -versionCache['io.grpc:grpc-core'] = '1.79.0' -versionCache['io.grpc:grpc-inprocess'] = '1.79.0' -versionCache['io.grpc:grpc-protobuf-lite'] = '1.79.0' -versionCache['io.grpc:grpc-stub'] = '1.79.0' -versionCache['io.grpc:grpc-testing'] = '1.79.0' -versionCache['io.grpc:grpc-util'] = '1.79.0' +versionCache['io.grpc:grpc-android'] = '1.80.0' +versionCache['io.grpc:grpc-api'] = '1.80.0' +versionCache['io.grpc:grpc-binder'] = '1.80.0' +versionCache['io.grpc:grpc-context'] = '1.80.0' +versionCache['io.grpc:grpc-core'] = '1.80.0' +versionCache['io.grpc:grpc-inprocess'] = '1.80.0' +versionCache['io.grpc:grpc-protobuf-lite'] = '1.80.0' +versionCache['io.grpc:grpc-stub'] = '1.80.0' +versionCache['io.grpc:grpc-testing'] = '1.80.0' +versionCache['io.grpc:grpc-util'] = '1.80.0' versionCache['io.perfmark:perfmark-api'] = '0.27.0' versionCache['io.reactivex.rxjava2:rxandroid'] = '2.1.1' versionCache['io.reactivex.rxjava2:rxjava'] = '2.2.6' versionCache['javax.annotation:javax.annotation-api'] = '1.3.2' versionCache['javax.inject:javax.inject'] = '1' versionCache['junit:junit'] = '4.13.2' -versionCache['net.bytebuddy:byte-buddy'] = '1.17.6' -versionCache['net.bytebuddy:byte-buddy-agent'] = '1.17.6' -versionCache['net.bytebuddy:byte-buddy-android'] = '1.17.6' +versionCache['net.bytebuddy:byte-buddy'] = '1.17.7' +versionCache['net.bytebuddy:byte-buddy-agent'] = '1.17.7' versionCache['org.bouncycastle:bcprov-jdk18on'] = '1.81' versionCache['org.ccil.cowan.tagsoup:tagsoup'] = '1.2.1' versionCache['org.checkerframework:checker-compat-qual'] = '2.5.5' @@ -426,9 +427,9 @@ versionCache['org.jetbrains:annotations'] = '23.0.0' versionCache['org.jsoup:jsoup'] = '1.15.1' versionCache['org.jspecify:jspecify'] = '1.0.0' -versionCache['org.mockito:mockito-android'] = '5.19.0' -versionCache['org.mockito:mockito-core'] = '5.19.0' -versionCache['org.mockito:mockito-subclass'] = '5.19.0' +versionCache['org.mockito:mockito-android'] = '5.23.0' +versionCache['org.mockito:mockito-core'] = '5.23.0' +versionCache['org.mockito:mockito-subclass'] = '5.23.0' versionCache['org.objenesis:objenesis'] = '3.3' versionCache['org.ow2.asm:asm'] = '9.9.1' versionCache['org.ow2.asm:asm-commons'] = '9.9.1'
diff --git a/third_party/android_deps/autorolled/build.gradle.template b/third_party/android_deps/autorolled/build.gradle.template index 2cab5984..93d7970 100644 --- a/third_party/android_deps/autorolled/build.gradle.template +++ b/third_party/android_deps/autorolled/build.gradle.template
@@ -48,7 +48,7 @@ // A dependency of androidx.xr.runtime:runtime, but must be listed here in // order to be auto-rolled and not manually rolled. - compileLatest 'com.google.ar:impress:+' + compileLatest 'com.google.ar:impress:0.0.10' // Play Services & Firebase compileLatest 'com.google.android.gms:play-services-auth-api-phone:+'
diff --git a/third_party/android_deps/autorolled/committed/libs/io_grpc_grpc_android/README.chromium b/third_party/android_deps/autorolled/committed/libs/io_grpc_grpc_android/README.chromium index 1189a4be..22f8096 100644 --- a/third_party/android_deps/autorolled/committed/libs/io_grpc_grpc_android/README.chromium +++ b/third_party/android_deps/autorolled/committed/libs/io_grpc_grpc_android/README.chromium
@@ -1,7 +1,7 @@ Name: io.grpc:grpc-android Short Name: grpc-android -URL: https://repo.maven.apache.org/maven2/io/grpc/grpc-android/1.79.0/grpc-android-1.79.0.aar -Version: 1.79.0 +URL: https://repo.maven.apache.org/maven2/io/grpc/grpc-android/1.80.0/grpc-android-1.80.0.aar +Version: 1.80.0 Update Mechanism: Autoroll License: Apache-2.0 License File: LICENSE
diff --git a/third_party/android_deps/autorolled/committed/libs/io_grpc_grpc_api/README.chromium b/third_party/android_deps/autorolled/committed/libs/io_grpc_grpc_api/README.chromium index 3363fe2..43bc6355 100644 --- a/third_party/android_deps/autorolled/committed/libs/io_grpc_grpc_api/README.chromium +++ b/third_party/android_deps/autorolled/committed/libs/io_grpc_grpc_api/README.chromium
@@ -1,7 +1,7 @@ Name: io.grpc:grpc-api Short Name: grpc-api -URL: https://repo.maven.apache.org/maven2/io/grpc/grpc-api/1.79.0/grpc-api-1.79.0.jar -Version: 1.79.0 +URL: https://repo.maven.apache.org/maven2/io/grpc/grpc-api/1.80.0/grpc-api-1.80.0.jar +Version: 1.80.0 Update Mechanism: Autoroll License: Apache-2.0 License File: LICENSE
diff --git a/third_party/android_deps/autorolled/committed/libs/io_grpc_grpc_binder/README.chromium b/third_party/android_deps/autorolled/committed/libs/io_grpc_grpc_binder/README.chromium index 2345cb8..d6118386 100644 --- a/third_party/android_deps/autorolled/committed/libs/io_grpc_grpc_binder/README.chromium +++ b/third_party/android_deps/autorolled/committed/libs/io_grpc_grpc_binder/README.chromium
@@ -1,7 +1,7 @@ Name: io.grpc:grpc-binder Short Name: grpc-binder -URL: https://repo.maven.apache.org/maven2/io/grpc/grpc-binder/1.79.0/grpc-binder-1.79.0.aar -Version: 1.79.0 +URL: https://repo.maven.apache.org/maven2/io/grpc/grpc-binder/1.80.0/grpc-binder-1.80.0.aar +Version: 1.80.0 Update Mechanism: Autoroll License: Apache-2.0 License File: LICENSE
diff --git a/third_party/android_deps/autorolled/committed/libs/io_grpc_grpc_context/README.chromium b/third_party/android_deps/autorolled/committed/libs/io_grpc_grpc_context/README.chromium index 9f594e9..b3daad0 100644 --- a/third_party/android_deps/autorolled/committed/libs/io_grpc_grpc_context/README.chromium +++ b/third_party/android_deps/autorolled/committed/libs/io_grpc_grpc_context/README.chromium
@@ -1,7 +1,7 @@ Name: io.grpc:grpc-context Short Name: grpc-context -URL: https://repo.maven.apache.org/maven2/io/grpc/grpc-context/1.79.0/grpc-context-1.79.0.jar -Version: 1.79.0 +URL: https://repo.maven.apache.org/maven2/io/grpc/grpc-context/1.80.0/grpc-context-1.80.0.jar +Version: 1.80.0 Update Mechanism: Autoroll License: Apache-2.0 License File: LICENSE
diff --git a/third_party/android_deps/autorolled/committed/libs/io_grpc_grpc_core/README.chromium b/third_party/android_deps/autorolled/committed/libs/io_grpc_grpc_core/README.chromium index 5dbf8e3f..af268ff 100644 --- a/third_party/android_deps/autorolled/committed/libs/io_grpc_grpc_core/README.chromium +++ b/third_party/android_deps/autorolled/committed/libs/io_grpc_grpc_core/README.chromium
@@ -1,7 +1,7 @@ Name: io.grpc:grpc-core Short Name: grpc-core -URL: https://repo.maven.apache.org/maven2/io/grpc/grpc-core/1.79.0/grpc-core-1.79.0.jar -Version: 1.79.0 +URL: https://repo.maven.apache.org/maven2/io/grpc/grpc-core/1.80.0/grpc-core-1.80.0.jar +Version: 1.80.0 Update Mechanism: Autoroll License: Apache-2.0 License File: LICENSE
diff --git a/third_party/android_deps/autorolled/committed/libs/io_grpc_grpc_inprocess/README.chromium b/third_party/android_deps/autorolled/committed/libs/io_grpc_grpc_inprocess/README.chromium index 0aff6fa1..9a40a8dc 100644 --- a/third_party/android_deps/autorolled/committed/libs/io_grpc_grpc_inprocess/README.chromium +++ b/third_party/android_deps/autorolled/committed/libs/io_grpc_grpc_inprocess/README.chromium
@@ -1,7 +1,7 @@ Name: io.grpc:grpc-inprocess Short Name: grpc-inprocess -URL: https://repo.maven.apache.org/maven2/io/grpc/grpc-inprocess/1.79.0/grpc-inprocess-1.79.0.jar -Version: 1.79.0 +URL: https://repo.maven.apache.org/maven2/io/grpc/grpc-inprocess/1.80.0/grpc-inprocess-1.80.0.jar +Version: 1.80.0 Update Mechanism: Autoroll License: Apache-2.0 License File: LICENSE
diff --git a/third_party/android_deps/autorolled/committed/libs/io_grpc_grpc_protobuf_lite/README.chromium b/third_party/android_deps/autorolled/committed/libs/io_grpc_grpc_protobuf_lite/README.chromium index ae783d5b..146c370c 100644 --- a/third_party/android_deps/autorolled/committed/libs/io_grpc_grpc_protobuf_lite/README.chromium +++ b/third_party/android_deps/autorolled/committed/libs/io_grpc_grpc_protobuf_lite/README.chromium
@@ -1,7 +1,7 @@ Name: io.grpc:grpc-protobuf-lite Short Name: grpc-protobuf-lite -URL: https://repo.maven.apache.org/maven2/io/grpc/grpc-protobuf-lite/1.79.0/grpc-protobuf-lite-1.79.0.jar -Version: 1.79.0 +URL: https://repo.maven.apache.org/maven2/io/grpc/grpc-protobuf-lite/1.80.0/grpc-protobuf-lite-1.80.0.jar +Version: 1.80.0 Update Mechanism: Autoroll License: Apache-2.0 License File: LICENSE
diff --git a/third_party/android_deps/autorolled/committed/libs/io_grpc_grpc_stub/README.chromium b/third_party/android_deps/autorolled/committed/libs/io_grpc_grpc_stub/README.chromium index 6fc0fc5..09db2f3 100644 --- a/third_party/android_deps/autorolled/committed/libs/io_grpc_grpc_stub/README.chromium +++ b/third_party/android_deps/autorolled/committed/libs/io_grpc_grpc_stub/README.chromium
@@ -1,7 +1,7 @@ Name: io.grpc:grpc-stub Short Name: grpc-stub -URL: https://repo.maven.apache.org/maven2/io/grpc/grpc-stub/1.79.0/grpc-stub-1.79.0.jar -Version: 1.79.0 +URL: https://repo.maven.apache.org/maven2/io/grpc/grpc-stub/1.80.0/grpc-stub-1.80.0.jar +Version: 1.80.0 Update Mechanism: Autoroll License: Apache-2.0 License File: LICENSE
diff --git a/third_party/android_deps/autorolled/committed/libs/io_grpc_grpc_testing/README.chromium b/third_party/android_deps/autorolled/committed/libs/io_grpc_grpc_testing/README.chromium index f9efb58..12949df 100644 --- a/third_party/android_deps/autorolled/committed/libs/io_grpc_grpc_testing/README.chromium +++ b/third_party/android_deps/autorolled/committed/libs/io_grpc_grpc_testing/README.chromium
@@ -1,7 +1,7 @@ Name: io.grpc:grpc-testing Short Name: grpc-testing -URL: https://repo.maven.apache.org/maven2/io/grpc/grpc-testing/1.79.0/grpc-testing-1.79.0.jar -Version: 1.79.0 +URL: https://repo.maven.apache.org/maven2/io/grpc/grpc-testing/1.80.0/grpc-testing-1.80.0.jar +Version: 1.80.0 Update Mechanism: Autoroll License: Apache-2.0 License File: LICENSE
diff --git a/third_party/android_deps/autorolled/committed/libs/io_grpc_grpc_util/README.chromium b/third_party/android_deps/autorolled/committed/libs/io_grpc_grpc_util/README.chromium index e476dad..2b8b96e8 100644 --- a/third_party/android_deps/autorolled/committed/libs/io_grpc_grpc_util/README.chromium +++ b/third_party/android_deps/autorolled/committed/libs/io_grpc_grpc_util/README.chromium
@@ -1,7 +1,7 @@ Name: io.grpc:grpc-util Short Name: grpc-util -URL: https://repo.maven.apache.org/maven2/io/grpc/grpc-util/1.79.0/grpc-util-1.79.0.jar -Version: 1.79.0 +URL: https://repo.maven.apache.org/maven2/io/grpc/grpc-util/1.80.0/grpc-util-1.80.0.jar +Version: 1.80.0 Update Mechanism: Autoroll License: Apache-2.0 License File: LICENSE
diff --git a/third_party/android_deps/build.gradle b/third_party/android_deps/build.gradle index 81d57328..baf8049 100644 --- a/third_party/android_deps/build.gradle +++ b/third_party/android_deps/build.gradle
@@ -44,7 +44,7 @@ // exclude it in ChromiumDepGraph. androidTestCompile 'com.google.protobuf:protobuf-lite:3.0.0' - String mockitoVersion = '5.19.0' + String mockitoVersion = '5.23.0' androidTestCompile "org.mockito:mockito-android:${mockitoVersion}" androidTestCompile "org.mockito:mockito-core:${mockitoVersion}" androidTestCompile "org.mockito:mockito-subclass:${mockitoVersion}"
diff --git a/third_party/android_deps/libs/com_linkedin_dexmaker_dexmaker/3pp/3pp.pb b/third_party/android_deps/libs/com_linkedin_dexmaker_dexmaker/3pp/3pp.pb new file mode 100644 index 0000000..d743b51b --- /dev/null +++ b/third_party/android_deps/libs/com_linkedin_dexmaker_dexmaker/3pp/3pp.pb
@@ -0,0 +1,16 @@ +# Copyright 2021 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# This is generated, do not edit. Update BuildConfigGenerator.groovy instead. + +create { + source { + script { name: "fetch.py" } + } +} + +upload { + pkg_prefix: "chromium/third_party/android_deps/libs" + universal: true +}
diff --git a/third_party/android_deps/libs/com_linkedin_dexmaker_dexmaker/3pp/fetch.py b/third_party/android_deps/libs/com_linkedin_dexmaker_dexmaker/3pp/fetch.py new file mode 100755 index 0000000..4b26dac --- /dev/null +++ b/third_party/android_deps/libs/com_linkedin_dexmaker_dexmaker/3pp/fetch.py
@@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +# Copyright 2021 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# This is generated, do not edit. Update BuildConfigGenerator.groovy and +# 3ppFetch.template instead. + +import pathlib +import sys + +_3PP_DIR = pathlib.Path(__file__).resolve().parent +sys.path.insert(0, str(_3PP_DIR.parents[2])) +import fetch_common + +_REPO_URL = 'https://repo.maven.apache.org/maven2' +SPEC = fetch_common.Spec(repo_url=_REPO_URL, + group_name='com/linkedin/dexmaker', + module_name='dexmaker', + file_ext='jar', + patch_version='cr2', + version_override=None, + version_filter=None) + +if __name__ == '__main__': + fetch_common.main(SPEC)
diff --git a/third_party/android_deps/libs/com_linkedin_dexmaker_dexmaker/LICENSE b/third_party/android_deps/libs/com_linkedin_dexmaker_dexmaker/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/third_party/android_deps/libs/com_linkedin_dexmaker_dexmaker/LICENSE
@@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License.
diff --git a/third_party/android_deps/libs/com_linkedin_dexmaker_dexmaker/OWNERS b/third_party/android_deps/libs/com_linkedin_dexmaker_dexmaker/OWNERS new file mode 100644 index 0000000..aea47a05 --- /dev/null +++ b/third_party/android_deps/libs/com_linkedin_dexmaker_dexmaker/OWNERS
@@ -0,0 +1 @@ +file://third_party/android_deps/OWNERS
diff --git a/third_party/android_deps/libs/com_linkedin_dexmaker_dexmaker/README.chromium b/third_party/android_deps/libs/com_linkedin_dexmaker_dexmaker/README.chromium new file mode 100644 index 0000000..b61466a --- /dev/null +++ b/third_party/android_deps/libs/com_linkedin_dexmaker_dexmaker/README.chromium
@@ -0,0 +1,19 @@ +Name: Dexmaker +Short Name: dexmaker +URL: https://repo.maven.apache.org/maven2/com/linkedin/dexmaker/dexmaker/2.28.6/dexmaker-2.28.6.jar +Version: 2.28.6 +Update Mechanism: Manual +License: Apache-2.0 +License File: LICENSE +CPEPrefix: unknown +Security Critical: no +Shipped: no + +Description: +A utility for doing compile or runtime code generation targeting Android's Dalvik VM + +See also: https://github.com/linkedin/dexmaker + + +Local Modifications: +No modifications.
diff --git a/third_party/android_deps/libs/com_linkedin_dexmaker_dexmaker/cipd.yaml b/third_party/android_deps/libs/com_linkedin_dexmaker_dexmaker/cipd.yaml new file mode 100644 index 0000000..f3e13afd --- /dev/null +++ b/third_party/android_deps/libs/com_linkedin_dexmaker_dexmaker/cipd.yaml
@@ -0,0 +1,10 @@ +# Copyright 2018 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# To create CIPD package run the following command. +# cipd create --pkg-def cipd.yaml -tag version:2@2.28.6.cr2 +package: chromium/third_party/android_deps/libs/com_linkedin_dexmaker_dexmaker +description: "Dexmaker" +data: +- file: dexmaker.jar
diff --git a/third_party/android_deps/libs/com_linkedin_dexmaker_dexmaker_mockito_inline/3pp/3pp.pb b/third_party/android_deps/libs/com_linkedin_dexmaker_dexmaker_mockito_inline/3pp/3pp.pb new file mode 100644 index 0000000..d743b51b --- /dev/null +++ b/third_party/android_deps/libs/com_linkedin_dexmaker_dexmaker_mockito_inline/3pp/3pp.pb
@@ -0,0 +1,16 @@ +# Copyright 2021 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# This is generated, do not edit. Update BuildConfigGenerator.groovy instead. + +create { + source { + script { name: "fetch.py" } + } +} + +upload { + pkg_prefix: "chromium/third_party/android_deps/libs" + universal: true +}
diff --git a/third_party/android_deps/libs/com_linkedin_dexmaker_dexmaker_mockito_inline/3pp/fetch.py b/third_party/android_deps/libs/com_linkedin_dexmaker_dexmaker_mockito_inline/3pp/fetch.py new file mode 100755 index 0000000..b6019aa --- /dev/null +++ b/third_party/android_deps/libs/com_linkedin_dexmaker_dexmaker_mockito_inline/3pp/fetch.py
@@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +# Copyright 2021 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# This is generated, do not edit. Update BuildConfigGenerator.groovy and +# 3ppFetch.template instead. + +import pathlib +import sys + +_3PP_DIR = pathlib.Path(__file__).resolve().parent +sys.path.insert(0, str(_3PP_DIR.parents[2])) +import fetch_common + +_REPO_URL = 'https://repo.maven.apache.org/maven2' +SPEC = fetch_common.Spec(repo_url=_REPO_URL, + group_name='com/linkedin/dexmaker', + module_name='dexmaker-mockito-inline', + file_ext='aar', + patch_version='cr2', + version_override=None, + version_filter=None) + +if __name__ == '__main__': + fetch_common.main(SPEC)
diff --git a/third_party/android_deps/libs/com_linkedin_dexmaker_dexmaker_mockito_inline/LICENSE b/third_party/android_deps/libs/com_linkedin_dexmaker_dexmaker_mockito_inline/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/third_party/android_deps/libs/com_linkedin_dexmaker_dexmaker_mockito_inline/LICENSE
@@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License.
diff --git a/third_party/android_deps/libs/com_linkedin_dexmaker_dexmaker_mockito_inline/OWNERS b/third_party/android_deps/libs/com_linkedin_dexmaker_dexmaker_mockito_inline/OWNERS new file mode 100644 index 0000000..aea47a05 --- /dev/null +++ b/third_party/android_deps/libs/com_linkedin_dexmaker_dexmaker_mockito_inline/OWNERS
@@ -0,0 +1 @@ +file://third_party/android_deps/OWNERS
diff --git a/third_party/android_deps/libs/com_linkedin_dexmaker_dexmaker_mockito_inline/README.chromium b/third_party/android_deps/libs/com_linkedin_dexmaker_dexmaker_mockito_inline/README.chromium new file mode 100644 index 0000000..ceafc6d --- /dev/null +++ b/third_party/android_deps/libs/com_linkedin_dexmaker_dexmaker_mockito_inline/README.chromium
@@ -0,0 +1,19 @@ +Name: Dexmaker +Short Name: dexmaker-mockito-inline +URL: https://repo.maven.apache.org/maven2/com/linkedin/dexmaker/dexmaker-mockito-inline/2.28.6/dexmaker-mockito-inline-2.28.6.aar +Version: 2.28.6 +Update Mechanism: Manual +License: Apache-2.0 +License File: LICENSE +CPEPrefix: unknown +Security Critical: no +Shipped: no + +Description: +Implementation of the Mockito Inline API for use on the Android Dalvik VM + +See also: https://github.com/linkedin/dexmaker + + +Local Modifications: +No modifications.
diff --git a/third_party/android_deps/libs/com_linkedin_dexmaker_dexmaker_mockito_inline/cipd.yaml b/third_party/android_deps/libs/com_linkedin_dexmaker_dexmaker_mockito_inline/cipd.yaml new file mode 100644 index 0000000..0c2edcc --- /dev/null +++ b/third_party/android_deps/libs/com_linkedin_dexmaker_dexmaker_mockito_inline/cipd.yaml
@@ -0,0 +1,10 @@ +# Copyright 2018 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# To create CIPD package run the following command. +# cipd create --pkg-def cipd.yaml -tag version:2@2.28.6.cr2 +package: chromium/third_party/android_deps/libs/com_linkedin_dexmaker_dexmaker_mockito_inline +description: "Dexmaker" +data: +- file: dexmaker-mockito-inline.aar
diff --git a/third_party/android_deps/libs/com_linkedin_dexmaker_dexmaker_mockito_inline/com_linkedin_dexmaker_dexmaker_mockito_inline.info b/third_party/android_deps/libs/com_linkedin_dexmaker_dexmaker_mockito_inline/com_linkedin_dexmaker_dexmaker_mockito_inline.info new file mode 100644 index 0000000..c280ae4c0 --- /dev/null +++ b/third_party/android_deps/libs/com_linkedin_dexmaker_dexmaker_mockito_inline/com_linkedin_dexmaker_dexmaker_mockito_inline.info
@@ -0,0 +1,21 @@ +# Generated by //build/android/gyp/aar.py +# To regenerate, use "update_android_aar_prebuilts = true" and run "gn gen". + +aidl = [] +assets = [] +has_classes_jar = true +has_native_libraries = true +has_proguard_flags = false +has_r_text_file = false +is_manifest_empty = true +manifest_package = "com.android.dx.mockito.inline" +native_libraries = [ + "jni/arm64-v8a/libdexmakerjvmtiagent.so", + "jni/armeabi-v7a/libdexmakerjvmtiagent.so", + "jni/riscv64/libdexmakerjvmtiagent.so", + "jni/x86/libdexmakerjvmtiagent.so", + "jni/x86_64/libdexmakerjvmtiagent.so" +] +resources = [] +subjar_tuples = [] +subjars = []
diff --git a/third_party/android_deps/libs/net_bytebuddy_byte_buddy/README.chromium b/third_party/android_deps/libs/net_bytebuddy_byte_buddy/README.chromium index a146d30..1d32f33d 100644 --- a/third_party/android_deps/libs/net_bytebuddy_byte_buddy/README.chromium +++ b/third_party/android_deps/libs/net_bytebuddy_byte_buddy/README.chromium
@@ -1,7 +1,7 @@ Name: Byte Buddy (without dependencies) Short Name: byte-buddy -URL: https://repo.maven.apache.org/maven2/net/bytebuddy/byte-buddy/1.17.6/byte-buddy-1.17.6.jar -Version: 1.17.6 +URL: https://repo.maven.apache.org/maven2/net/bytebuddy/byte-buddy/1.17.7/byte-buddy-1.17.7.jar +Version: 1.17.7 Update Mechanism: Manual License: Apache-2.0 License File: LICENSE
diff --git a/third_party/android_deps/libs/net_bytebuddy_byte_buddy/cipd.yaml b/third_party/android_deps/libs/net_bytebuddy_byte_buddy/cipd.yaml index 953e9ef..9ae5c8d 100644 --- a/third_party/android_deps/libs/net_bytebuddy_byte_buddy/cipd.yaml +++ b/third_party/android_deps/libs/net_bytebuddy_byte_buddy/cipd.yaml
@@ -3,7 +3,7 @@ # found in the LICENSE file. # To create CIPD package run the following command. -# cipd create --pkg-def cipd.yaml -tag version:2@1.17.6.cr2 +# cipd create --pkg-def cipd.yaml -tag version:2@1.17.7.cr2 package: chromium/third_party/android_deps/libs/net_bytebuddy_byte_buddy description: "Byte Buddy (without dependencies)" data:
diff --git a/third_party/android_deps/libs/net_bytebuddy_byte_buddy_agent/README.chromium b/third_party/android_deps/libs/net_bytebuddy_byte_buddy_agent/README.chromium index 965e876..1bef0ee 100644 --- a/third_party/android_deps/libs/net_bytebuddy_byte_buddy_agent/README.chromium +++ b/third_party/android_deps/libs/net_bytebuddy_byte_buddy_agent/README.chromium
@@ -1,7 +1,7 @@ Name: Byte Buddy agent Short Name: byte-buddy-agent -URL: https://repo.maven.apache.org/maven2/net/bytebuddy/byte-buddy-agent/1.17.6/byte-buddy-agent-1.17.6.jar -Version: 1.17.6 +URL: https://repo.maven.apache.org/maven2/net/bytebuddy/byte-buddy-agent/1.17.7/byte-buddy-agent-1.17.7.jar +Version: 1.17.7 Update Mechanism: Manual License: Apache-2.0 License File: LICENSE
diff --git a/third_party/android_deps/libs/net_bytebuddy_byte_buddy_agent/cipd.yaml b/third_party/android_deps/libs/net_bytebuddy_byte_buddy_agent/cipd.yaml index 1f36f9d5..b7450a5 100644 --- a/third_party/android_deps/libs/net_bytebuddy_byte_buddy_agent/cipd.yaml +++ b/third_party/android_deps/libs/net_bytebuddy_byte_buddy_agent/cipd.yaml
@@ -3,7 +3,7 @@ # found in the LICENSE file. # To create CIPD package run the following command. -# cipd create --pkg-def cipd.yaml -tag version:2@1.17.6.cr2 +# cipd create --pkg-def cipd.yaml -tag version:2@1.17.7.cr2 package: chromium/third_party/android_deps/libs/net_bytebuddy_byte_buddy_agent description: "Byte Buddy agent" data:
diff --git a/third_party/android_deps/libs/org_jsoup_jsoup/LICENSE b/third_party/android_deps/libs/org_jsoup_jsoup/LICENSE index e4bf2be9f..0b2f502 100644 --- a/third_party/android_deps/libs/org_jsoup_jsoup/LICENSE +++ b/third_party/android_deps/libs/org_jsoup_jsoup/LICENSE
@@ -1,6 +1,6 @@ The MIT License -Copyright (c) 2009-2025 Jonathan Hedley <https://jsoup.org/> +Copyright (c) 2009-2026 Jonathan Hedley <https://jsoup.org/> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal
diff --git a/third_party/android_deps/libs/org_mockito_mockito_android/3pp/fetch.py b/third_party/android_deps/libs/org_mockito_mockito_android/3pp/fetch.py index 2563c41..363603c 100755 --- a/third_party/android_deps/libs/org_mockito_mockito_android/3pp/fetch.py +++ b/third_party/android_deps/libs/org_mockito_mockito_android/3pp/fetch.py
@@ -17,7 +17,7 @@ SPEC = fetch_common.Spec(repo_url=_REPO_URL, group_name='org/mockito', module_name='mockito-android', - file_ext='jar', + file_ext='aar', patch_version='cr2', version_override=None, version_filter=None)
diff --git a/third_party/android_deps/libs/org_mockito_mockito_android/README.chromium b/third_party/android_deps/libs/org_mockito_mockito_android/README.chromium index fafb27e2..7cc9fdac 100644 --- a/third_party/android_deps/libs/org_mockito_mockito_android/README.chromium +++ b/third_party/android_deps/libs/org_mockito_mockito_android/README.chromium
@@ -1,7 +1,7 @@ Name: mockito-android Short Name: mockito-android -URL: https://repo.maven.apache.org/maven2/org/mockito/mockito-android/5.19.0/mockito-android-5.19.0.jar -Version: 5.19.0 +URL: https://repo.maven.apache.org/maven2/org/mockito/mockito-android/5.23.0/mockito-android-5.23.0.aar +Version: 5.23.0 Update Mechanism: Manual License: MIT License File: LICENSE
diff --git a/third_party/android_deps/libs/org_mockito_mockito_android/cipd.yaml b/third_party/android_deps/libs/org_mockito_mockito_android/cipd.yaml index 6fefb000e..71625ff4 100644 --- a/third_party/android_deps/libs/org_mockito_mockito_android/cipd.yaml +++ b/third_party/android_deps/libs/org_mockito_mockito_android/cipd.yaml
@@ -3,8 +3,8 @@ # found in the LICENSE file. # To create CIPD package run the following command. -# cipd create --pkg-def cipd.yaml -tag version:2@5.19.0.cr2 +# cipd create --pkg-def cipd.yaml -tag version:2@5.23.0.cr2 package: chromium/third_party/android_deps/libs/org_mockito_mockito_android description: "mockito-android" data: -- file: mockito-android.jar +- file: mockito-android.aar
diff --git a/third_party/android_deps/libs/org_mockito_mockito_android/org_mockito_mockito_android.info b/third_party/android_deps/libs/org_mockito_mockito_android/org_mockito_mockito_android.info new file mode 100644 index 0000000..a6ca7ac --- /dev/null +++ b/third_party/android_deps/libs/org_mockito_mockito_android/org_mockito_mockito_android.info
@@ -0,0 +1,14 @@ +# Generated by //build/android/gyp/aar.py +# To regenerate, use "update_android_aar_prebuilts = true" and run "gn gen". + +aidl = [] +assets = [] +has_classes_jar = true +has_native_libraries = false +has_proguard_flags = false +has_r_text_file = false +is_manifest_empty = true +manifest_package = "org.mockito.android" +resources = [] +subjar_tuples = [] +subjars = []
diff --git a/third_party/android_deps/libs/org_mockito_mockito_core/README.chromium b/third_party/android_deps/libs/org_mockito_mockito_core/README.chromium index 68c3833..dec22d1 100644 --- a/third_party/android_deps/libs/org_mockito_mockito_core/README.chromium +++ b/third_party/android_deps/libs/org_mockito_mockito_core/README.chromium
@@ -1,7 +1,7 @@ Name: mockito-core Short Name: mockito-core -URL: https://repo.maven.apache.org/maven2/org/mockito/mockito-core/5.19.0/mockito-core-5.19.0.jar -Version: 5.19.0 +URL: https://repo.maven.apache.org/maven2/org/mockito/mockito-core/5.23.0/mockito-core-5.23.0.jar +Version: 5.23.0 Update Mechanism: Manual License: MIT License File: LICENSE
diff --git a/third_party/android_deps/libs/org_mockito_mockito_core/cipd.yaml b/third_party/android_deps/libs/org_mockito_mockito_core/cipd.yaml index 93c1bd5..1bde6f15 100644 --- a/third_party/android_deps/libs/org_mockito_mockito_core/cipd.yaml +++ b/third_party/android_deps/libs/org_mockito_mockito_core/cipd.yaml
@@ -3,7 +3,7 @@ # found in the LICENSE file. # To create CIPD package run the following command. -# cipd create --pkg-def cipd.yaml -tag version:2@5.19.0.cr2 +# cipd create --pkg-def cipd.yaml -tag version:2@5.23.0.cr2 package: chromium/third_party/android_deps/libs/org_mockito_mockito_core description: "mockito-core" data:
diff --git a/third_party/android_deps/libs/org_mockito_mockito_subclass/README.chromium b/third_party/android_deps/libs/org_mockito_mockito_subclass/README.chromium index 69835a1..27ef2cf 100644 --- a/third_party/android_deps/libs/org_mockito_mockito_subclass/README.chromium +++ b/third_party/android_deps/libs/org_mockito_mockito_subclass/README.chromium
@@ -1,7 +1,7 @@ Name: mockito-subclass Short Name: mockito-subclass -URL: https://repo.maven.apache.org/maven2/org/mockito/mockito-subclass/5.19.0/mockito-subclass-5.19.0.jar -Version: 5.19.0 +URL: https://repo.maven.apache.org/maven2/org/mockito/mockito-subclass/5.23.0/mockito-subclass-5.23.0.jar +Version: 5.23.0 Update Mechanism: Manual License: MIT License File: LICENSE
diff --git a/third_party/android_deps/libs/org_mockito_mockito_subclass/cipd.yaml b/third_party/android_deps/libs/org_mockito_mockito_subclass/cipd.yaml index f5e36ab..2a5edcd 100644 --- a/third_party/android_deps/libs/org_mockito_mockito_subclass/cipd.yaml +++ b/third_party/android_deps/libs/org_mockito_mockito_subclass/cipd.yaml
@@ -3,7 +3,7 @@ # found in the LICENSE file. # To create CIPD package run the following command. -# cipd create --pkg-def cipd.yaml -tag version:2@5.19.0.cr2 +# cipd create --pkg-def cipd.yaml -tag version:2@5.23.0.cr2 package: chromium/third_party/android_deps/libs/org_mockito_mockito_subclass description: "mockito-subclass" data:
diff --git a/third_party/androidx/bill_of_materials.json b/third_party/androidx/bill_of_materials.json index 106a865..c72866a9 100644 --- a/third_party/androidx/bill_of_materials.json +++ b/third_party/androidx/bill_of_materials.json
@@ -2,17 +2,17 @@ { "name": "activity", "group": "androidx.activity", - "version": "1.13.0" + "version": "1.14.0-SNAPSHOT" }, { "name": "activity-compose", "group": "androidx.activity", - "version": "1.13.0" + "version": "1.14.0-SNAPSHOT" }, { "name": "activity-ktx", "group": "androidx.activity", - "version": "1.13.0" + "version": "1.14.0-SNAPSHOT" }, { "name": "annotation",
diff --git a/third_party/androidx/build.gradle b/third_party/androidx/build.gradle index eea26c6a..8a89bf1 100644 --- a/third_party/androidx/build.gradle +++ b/third_party/androidx/build.gradle
@@ -15,9 +15,9 @@ // versions when we are not trying to roll (e.g. when the main project // imports the androidx subproject). project.ext.versionCache = [:] -versionCache['androidx.activity:activity'] = '1.13.0' -versionCache['androidx.activity:activity-compose'] = '1.13.0' -versionCache['androidx.activity:activity-ktx'] = '1.13.0' +versionCache['androidx.activity:activity'] = '1.14.0-SNAPSHOT' +versionCache['androidx.activity:activity-compose'] = '1.14.0-SNAPSHOT' +versionCache['androidx.activity:activity-ktx'] = '1.14.0-SNAPSHOT' versionCache['androidx.annotation:annotation'] = '1.10.0-SNAPSHOT' versionCache['androidx.annotation:annotation-experimental'] = '1.6.0-SNAPSHOT' versionCache['androidx.annotation:annotation-jvm'] = '1.10.0-SNAPSHOT' @@ -340,7 +340,7 @@ google() maven { // This URL is generated by the fetch_all_androidx.py script. - url 'https://androidx.dev/snapshots/builds/15039720/artifacts/repository' + url 'https://androidx.dev/snapshots/builds/15042599/artifacts/repository' } mavenCentral() }
diff --git a/third_party/androidx/build.gradle.template b/third_party/androidx/build.gradle.template index 4df810b..f78ca6c 100644 --- a/third_party/androidx/build.gradle.template +++ b/third_party/androidx/build.gradle.template
@@ -114,10 +114,10 @@ // ChromeXR dependencies should be left at a fixed version // to prevent breakages. - compile 'androidx.xr.arcore:arcore:1.0.0-alpha07' - compile 'androidx.xr.arcore:arcore-openxr:1.0.0-alpha07' - compile 'androidx.xr.runtime:runtime:1.0.0-alpha07' - compile('androidx.xr.scenecore:scenecore:1.0.0-alpha08') { + compile 'androidx.xr.arcore:arcore:1.0.0-alpha10' + compile 'androidx.xr.arcore:arcore-openxr:1.0.0-alpha10' + compile 'androidx.xr.runtime:runtime:1.0.0-alpha10' + compile('androidx.xr.scenecore:scenecore:1.0.0-alpha11') { // The target 'androidx_xr_scenecore_spatial_core_java' was // generating a dep on':androidx_test_rules_java' which causes // breakages.
diff --git a/third_party/androidx/committed/libs/androidx_activity_activity/README.chromium b/third_party/androidx/committed/libs/androidx_activity_activity/README.chromium index 4e51b22..e2087e8 100644 --- a/third_party/androidx/committed/libs/androidx_activity_activity/README.chromium +++ b/third_party/androidx/committed/libs/androidx_activity_activity/README.chromium
@@ -1,7 +1,7 @@ Name: Activity Short Name: activity -URL: https://dl.google.com/dl/android/maven2/androidx/activity/activity/1.13.0/activity-1.13.0.aar -Version: 1.13.0 +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/activity/activity/1.14.0-SNAPSHOT/activity-1.14.0-20260317.212834-1.aar +Version: 1.14.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0 License File: LICENSE @@ -13,7 +13,7 @@ Description: Provides the base Activity subclass and the relevant hooks to build a composable structure on top. -See also: https://developer.android.com/jetpack/androidx/releases/activity#1.13.0 +See also: https://developer.android.com/jetpack/androidx/releases/activity#1.14.0-SNAPSHOT Local Modifications:
diff --git a/third_party/androidx/committed/libs/androidx_activity_activity/androidx_activity_activity.info b/third_party/androidx/committed/libs/androidx_activity_activity/androidx_activity_activity.info index a74cfd8..205acc7 100644 --- a/third_party/androidx/committed/libs/androidx_activity_activity/androidx_activity_activity.info +++ b/third_party/androidx/committed/libs/androidx_activity_activity/androidx_activity_activity.info
@@ -5,7 +5,7 @@ assets = [] has_classes_jar = true has_native_libraries = false -has_proguard_flags = true +has_proguard_flags = false has_r_text_file = true is_manifest_empty = true manifest_package = "androidx.activity"
diff --git a/third_party/androidx/committed/libs/androidx_activity_activity_compose/README.chromium b/third_party/androidx/committed/libs/androidx_activity_activity_compose/README.chromium index 56cd10a7..f9b9f0e6 100644 --- a/third_party/androidx/committed/libs/androidx_activity_activity_compose/README.chromium +++ b/third_party/androidx/committed/libs/androidx_activity_activity_compose/README.chromium
@@ -1,7 +1,7 @@ Name: Activity Compose Short Name: activity-compose -URL: https://dl.google.com/dl/android/maven2/androidx/activity/activity-compose/1.13.0/activity-compose-1.13.0.aar -Version: 1.13.0 +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/activity/activity-compose/1.14.0-SNAPSHOT/activity-compose-1.14.0-20260317.212834-1.aar +Version: 1.14.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0 License File: LICENSE @@ -13,7 +13,7 @@ Description: Compose integration with Activity -See also: https://developer.android.com/jetpack/androidx/releases/activity#1.13.0 +See also: https://developer.android.com/jetpack/androidx/releases/activity#1.14.0-SNAPSHOT Local Modifications:
diff --git a/third_party/androidx/committed/libs/androidx_activity_activity_compose/androidx_activity_activity_compose.info b/third_party/androidx/committed/libs/androidx_activity_activity_compose/androidx_activity_activity_compose.info index 54056f35..b00885b1 100644 --- a/third_party/androidx/committed/libs/androidx_activity_activity_compose/androidx_activity_activity_compose.info +++ b/third_party/androidx/committed/libs/androidx_activity_activity_compose/androidx_activity_activity_compose.info
@@ -5,7 +5,7 @@ assets = [] has_classes_jar = true has_native_libraries = false -has_proguard_flags = true +has_proguard_flags = false has_r_text_file = false is_manifest_empty = true manifest_package = "androidx.activity.compose"
diff --git a/third_party/androidx/committed/libs/androidx_activity_activity_ktx/README.chromium b/third_party/androidx/committed/libs/androidx_activity_activity_ktx/README.chromium index 48280ab1..e6fef98 100644 --- a/third_party/androidx/committed/libs/androidx_activity_activity_ktx/README.chromium +++ b/third_party/androidx/committed/libs/androidx_activity_activity_ktx/README.chromium
@@ -1,7 +1,7 @@ Name: Activity Kotlin Extensions Short Name: activity-ktx -URL: https://dl.google.com/dl/android/maven2/androidx/activity/activity-ktx/1.13.0/activity-ktx-1.13.0.aar -Version: 1.13.0 +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/activity/activity-ktx/1.14.0-SNAPSHOT/activity-ktx-1.14.0-20260317.212834-1.aar +Version: 1.14.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0 License File: LICENSE @@ -13,7 +13,7 @@ Description: Kotlin extensions for 'activity' artifact -See also: https://developer.android.com/jetpack/androidx/releases/activity#1.13.0 +See also: https://developer.android.com/jetpack/androidx/releases/activity#1.14.0-SNAPSHOT Local Modifications:
diff --git a/third_party/androidx/committed/libs/androidx_activity_activity_ktx/androidx_activity_activity_ktx.info b/third_party/androidx/committed/libs/androidx_activity_activity_ktx/androidx_activity_activity_ktx.info index 2ab3ecc..889a9ab 100644 --- a/third_party/androidx/committed/libs/androidx_activity_activity_ktx/androidx_activity_activity_ktx.info +++ b/third_party/androidx/committed/libs/androidx_activity_activity_ktx/androidx_activity_activity_ktx.info
@@ -5,7 +5,7 @@ assets = [] has_classes_jar = true has_native_libraries = false -has_proguard_flags = true +has_proguard_flags = false has_r_text_file = false is_manifest_empty = true manifest_package = "androidx.activity.ktx"
diff --git a/third_party/androidx/committed/libs/androidx_annotation_annotation_experimental/README.chromium b/third_party/androidx/committed/libs/androidx_annotation_annotation_experimental/README.chromium index b712f426..cab9aae 100644 --- a/third_party/androidx/committed/libs/androidx_annotation_annotation_experimental/README.chromium +++ b/third_party/androidx/committed/libs/androidx_annotation_annotation_experimental/README.chromium
@@ -1,6 +1,6 @@ Name: Experimental annotation Short Name: annotation-experimental -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/annotation/annotation-experimental/1.6.0-SNAPSHOT/annotation-experimental-1.6.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/annotation/annotation-experimental/1.6.0-SNAPSHOT/annotation-experimental-1.6.0-20260317.212834-1.aar Version: 1.6.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_annotation_annotation_jvm/README.chromium b/third_party/androidx/committed/libs/androidx_annotation_annotation_jvm/README.chromium index a28decc5..4de89f98 100644 --- a/third_party/androidx/committed/libs/androidx_annotation_annotation_jvm/README.chromium +++ b/third_party/androidx/committed/libs/androidx_annotation_annotation_jvm/README.chromium
@@ -1,6 +1,6 @@ Name: Annotation Short Name: annotation-jvm -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/annotation/annotation-jvm/1.10.0-SNAPSHOT/annotation-jvm-1.10.0-20260317.131640-1.jar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/annotation/annotation-jvm/1.10.0-SNAPSHOT/annotation-jvm-1.10.0-20260317.212834-1.jar Version: 1.10.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_appcompat_appcompat/README.chromium b/third_party/androidx/committed/libs/androidx_appcompat_appcompat/README.chromium index 137856f..3a01725 100644 --- a/third_party/androidx/committed/libs/androidx_appcompat_appcompat/README.chromium +++ b/third_party/androidx/committed/libs/androidx_appcompat_appcompat/README.chromium
@@ -1,6 +1,6 @@ Name: AppCompat Short Name: appcompat -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/appcompat/appcompat/1.8.0-SNAPSHOT/appcompat-1.8.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/appcompat/appcompat/1.8.0-SNAPSHOT/appcompat-1.8.0-20260317.212834-1.aar Version: 1.8.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_appcompat_appcompat_resources/README.chromium b/third_party/androidx/committed/libs/androidx_appcompat_appcompat_resources/README.chromium index 2c610525..57f42381 100644 --- a/third_party/androidx/committed/libs/androidx_appcompat_appcompat_resources/README.chromium +++ b/third_party/androidx/committed/libs/androidx_appcompat_appcompat_resources/README.chromium
@@ -1,6 +1,6 @@ Name: AppCompat Resources Short Name: appcompat-resources -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/appcompat/appcompat-resources/1.8.0-SNAPSHOT/appcompat-resources-1.8.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/appcompat/appcompat-resources/1.8.0-SNAPSHOT/appcompat-resources-1.8.0-20260317.212834-1.aar Version: 1.8.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_appsearch_appsearch/README.chromium b/third_party/androidx/committed/libs/androidx_appsearch_appsearch/README.chromium index 2c91e07b..7589c88d 100644 --- a/third_party/androidx/committed/libs/androidx_appsearch_appsearch/README.chromium +++ b/third_party/androidx/committed/libs/androidx_appsearch_appsearch/README.chromium
@@ -1,6 +1,6 @@ Name: AppSearch Short Name: appsearch -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/appsearch/appsearch/1.2.0-SNAPSHOT/appsearch-1.2.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/appsearch/appsearch/1.2.0-SNAPSHOT/appsearch-1.2.0-20260317.212834-1.aar Version: 1.2.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_appsearch_appsearch_builtin_types/README.chromium b/third_party/androidx/committed/libs/androidx_appsearch_appsearch_builtin_types/README.chromium index 60fa51e4..99ded1c 100644 --- a/third_party/androidx/committed/libs/androidx_appsearch_appsearch_builtin_types/README.chromium +++ b/third_party/androidx/committed/libs/androidx_appsearch_appsearch_builtin_types/README.chromium
@@ -1,6 +1,6 @@ Name: AppSearch Builtin Types Short Name: appsearch-builtin-types -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/appsearch/appsearch-builtin-types/1.2.0-SNAPSHOT/appsearch-builtin-types-1.2.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/appsearch/appsearch-builtin-types/1.2.0-SNAPSHOT/appsearch-builtin-types-1.2.0-20260317.212834-1.aar Version: 1.2.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_appsearch_appsearch_platform_storage/README.chromium b/third_party/androidx/committed/libs/androidx_appsearch_appsearch_platform_storage/README.chromium index b7e8bd5..5f12ca6 100644 --- a/third_party/androidx/committed/libs/androidx_appsearch_appsearch_platform_storage/README.chromium +++ b/third_party/androidx/committed/libs/androidx_appsearch_appsearch_platform_storage/README.chromium
@@ -1,6 +1,6 @@ Name: AppSearch Platform Storage Short Name: appsearch-platform-storage -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/appsearch/appsearch-platform-storage/1.2.0-SNAPSHOT/appsearch-platform-storage-1.2.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/appsearch/appsearch-platform-storage/1.2.0-SNAPSHOT/appsearch-platform-storage-1.2.0-20260317.212834-1.aar Version: 1.2.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_arch_core_core_common/README.chromium b/third_party/androidx/committed/libs/androidx_arch_core_core_common/README.chromium index e4995b1f..b973de93 100644 --- a/third_party/androidx/committed/libs/androidx_arch_core_core_common/README.chromium +++ b/third_party/androidx/committed/libs/androidx_arch_core_core_common/README.chromium
@@ -1,6 +1,6 @@ Name: Arch-Common Short Name: core-common -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/arch/core/core-common/2.3.0-SNAPSHOT/core-common-2.3.0-20260317.131640-1.jar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/arch/core/core-common/2.3.0-SNAPSHOT/core-common-2.3.0-20260317.212834-1.jar Version: 2.3.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_arch_core_core_runtime/README.chromium b/third_party/androidx/committed/libs/androidx_arch_core_core_runtime/README.chromium index aafd42e..91eca072 100644 --- a/third_party/androidx/committed/libs/androidx_arch_core_core_runtime/README.chromium +++ b/third_party/androidx/committed/libs/androidx_arch_core_core_runtime/README.chromium
@@ -1,6 +1,6 @@ Name: Arch-Runtime Short Name: core-runtime -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/arch/core/core-runtime/2.3.0-SNAPSHOT/core-runtime-2.3.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/arch/core/core-runtime/2.3.0-SNAPSHOT/core-runtime-2.3.0-20260317.212834-1.aar Version: 2.3.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_autofill_autofill/README.chromium b/third_party/androidx/committed/libs/androidx_autofill_autofill/README.chromium index db63ecd6..05484da6 100644 --- a/third_party/androidx/committed/libs/androidx_autofill_autofill/README.chromium +++ b/third_party/androidx/committed/libs/androidx_autofill_autofill/README.chromium
@@ -1,6 +1,6 @@ Name: Autofill Short Name: autofill -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/autofill/autofill/1.4.0-SNAPSHOT/autofill-1.4.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/autofill/autofill/1.4.0-SNAPSHOT/autofill-1.4.0-20260317.212834-1.aar Version: 1.4.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_benchmark_benchmark_common/README.chromium b/third_party/androidx/committed/libs/androidx_benchmark_benchmark_common/README.chromium index 00bfe59..c8e582a 100644 --- a/third_party/androidx/committed/libs/androidx_benchmark_benchmark_common/README.chromium +++ b/third_party/androidx/committed/libs/androidx_benchmark_benchmark_common/README.chromium
@@ -1,6 +1,6 @@ Name: Benchmark - Common Short Name: benchmark-common -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/benchmark/benchmark-common/1.5.0-SNAPSHOT/benchmark-common-1.5.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/benchmark/benchmark-common/1.5.0-SNAPSHOT/benchmark-common-1.5.0-20260317.212834-1.aar Version: 1.5.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_benchmark_benchmark_junit4/README.chromium b/third_party/androidx/committed/libs/androidx_benchmark_benchmark_junit4/README.chromium index 64a8807a..af2f2a2 100644 --- a/third_party/androidx/committed/libs/androidx_benchmark_benchmark_junit4/README.chromium +++ b/third_party/androidx/committed/libs/androidx_benchmark_benchmark_junit4/README.chromium
@@ -1,6 +1,6 @@ Name: Benchmark - JUnit4 Short Name: benchmark-junit4 -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/benchmark/benchmark-junit4/1.5.0-SNAPSHOT/benchmark-junit4-1.5.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/benchmark/benchmark-junit4/1.5.0-SNAPSHOT/benchmark-junit4-1.5.0-20260317.212834-1.aar Version: 1.5.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_benchmark_benchmark_macro/README.chromium b/third_party/androidx/committed/libs/androidx_benchmark_benchmark_macro/README.chromium index 6ef34e5f..2d48ca68 100644 --- a/third_party/androidx/committed/libs/androidx_benchmark_benchmark_macro/README.chromium +++ b/third_party/androidx/committed/libs/androidx_benchmark_benchmark_macro/README.chromium
@@ -1,6 +1,6 @@ Name: Benchmark - Macrobenchmark Short Name: benchmark-macro -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/benchmark/benchmark-macro/1.5.0-SNAPSHOT/benchmark-macro-1.5.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/benchmark/benchmark-macro/1.5.0-SNAPSHOT/benchmark-macro-1.5.0-20260317.212834-1.aar Version: 1.5.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_benchmark_benchmark_macro_junit4/README.chromium b/third_party/androidx/committed/libs/androidx_benchmark_benchmark_macro_junit4/README.chromium index 6a547dc..8790675 100644 --- a/third_party/androidx/committed/libs/androidx_benchmark_benchmark_macro_junit4/README.chromium +++ b/third_party/androidx/committed/libs/androidx_benchmark_benchmark_macro_junit4/README.chromium
@@ -1,6 +1,6 @@ Name: Benchmark - Macrobenchmark JUnit4 Short Name: benchmark-macro-junit4 -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/benchmark/benchmark-macro-junit4/1.5.0-SNAPSHOT/benchmark-macro-junit4-1.5.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/benchmark/benchmark-macro-junit4/1.5.0-SNAPSHOT/benchmark-macro-junit4-1.5.0-20260317.212834-1.aar Version: 1.5.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_benchmark_benchmark_traceprocessor_android/README.chromium b/third_party/androidx/committed/libs/androidx_benchmark_benchmark_traceprocessor_android/README.chromium index 860bbd4a..ce79696 100644 --- a/third_party/androidx/committed/libs/androidx_benchmark_benchmark_traceprocessor_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_benchmark_benchmark_traceprocessor_android/README.chromium
@@ -1,6 +1,6 @@ Name: Benchmark TraceProcessor Short Name: benchmark-traceprocessor-android -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/benchmark/benchmark-traceprocessor-android/1.5.0-SNAPSHOT/benchmark-traceprocessor-android-1.5.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/benchmark/benchmark-traceprocessor-android/1.5.0-SNAPSHOT/benchmark-traceprocessor-android-1.5.0-20260317.212834-1.aar Version: 1.5.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_biometric_biometric/README.chromium b/third_party/androidx/committed/libs/androidx_biometric_biometric/README.chromium index 6b0132e5..80626e01 100644 --- a/third_party/androidx/committed/libs/androidx_biometric_biometric/README.chromium +++ b/third_party/androidx/committed/libs/androidx_biometric_biometric/README.chromium
@@ -1,6 +1,6 @@ Name: Biometric Short Name: biometric -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/biometric/biometric/1.4.0-SNAPSHOT/biometric-1.4.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/biometric/biometric/1.4.0-SNAPSHOT/biometric-1.4.0-20260317.212834-1.aar Version: 1.4.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_browser_browser/README.chromium b/third_party/androidx/committed/libs/androidx_browser_browser/README.chromium index e5fab8c6..515057a6 100644 --- a/third_party/androidx/committed/libs/androidx_browser_browser/README.chromium +++ b/third_party/androidx/committed/libs/androidx_browser_browser/README.chromium
@@ -1,6 +1,6 @@ Name: Browser Short Name: browser -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/browser/browser/1.10.0-SNAPSHOT/browser-1.10.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/browser/browser/1.10.0-SNAPSHOT/browser-1.10.0-20260317.212834-1.aar Version: 1.10.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_cardview_cardview/README.chromium b/third_party/androidx/committed/libs/androidx_cardview_cardview/README.chromium index ab0e57e..09b8a407 100644 --- a/third_party/androidx/committed/libs/androidx_cardview_cardview/README.chromium +++ b/third_party/androidx/committed/libs/androidx_cardview_cardview/README.chromium
@@ -1,6 +1,6 @@ Name: CardView Short Name: cardview -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/cardview/cardview/1.1.0-SNAPSHOT/cardview-1.1.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/cardview/cardview/1.1.0-SNAPSHOT/cardview-1.1.0-20260317.212834-1.aar Version: 1.1.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_collection_collection_jvm/README.chromium b/third_party/androidx/committed/libs/androidx_collection_collection_jvm/README.chromium index 3491bab..b335a13 100644 --- a/third_party/androidx/committed/libs/androidx_collection_collection_jvm/README.chromium +++ b/third_party/androidx/committed/libs/androidx_collection_collection_jvm/README.chromium
@@ -1,6 +1,6 @@ Name: collections Short Name: collection-jvm -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/collection/collection-jvm/1.7.0-SNAPSHOT/collection-jvm-1.7.0-20260317.131640-1.jar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/collection/collection-jvm/1.7.0-SNAPSHOT/collection-jvm-1.7.0-20260317.212834-1.jar Version: 1.7.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_collection_collection_ktx/README.chromium b/third_party/androidx/committed/libs/androidx_collection_collection_ktx/README.chromium index 338ca26b6..42cfe42 100644 --- a/third_party/androidx/committed/libs/androidx_collection_collection_ktx/README.chromium +++ b/third_party/androidx/committed/libs/androidx_collection_collection_ktx/README.chromium
@@ -1,6 +1,6 @@ Name: Collections Kotlin Extensions Short Name: collection-ktx -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/collection/collection-ktx/1.7.0-SNAPSHOT/collection-ktx-1.7.0-20260317.131640-1.jar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/collection/collection-ktx/1.7.0-SNAPSHOT/collection-ktx-1.7.0-20260317.212834-1.jar Version: 1.7.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_animation_animation_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_animation_animation_android/README.chromium index 7f07fb2..a1cae0e 100644 --- a/third_party/androidx/committed/libs/androidx_compose_animation_animation_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_compose_animation_animation_android/README.chromium
@@ -1,6 +1,6 @@ Name: Compose Animation Short Name: animation-android -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/compose/animation/animation-android/1.11.0-SNAPSHOT/animation-android-1.11.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/compose/animation/animation-android/1.11.0-SNAPSHOT/animation-android-1.11.0-20260317.212834-1.aar Version: 1.11.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_animation_animation_core_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_animation_animation_core_android/README.chromium index 0233325..bcd88d8 100644 --- a/third_party/androidx/committed/libs/androidx_compose_animation_animation_core_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_compose_animation_animation_core_android/README.chromium
@@ -1,6 +1,6 @@ Name: Compose Animation Core Short Name: animation-core-android -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/compose/animation/animation-core-android/1.11.0-SNAPSHOT/animation-core-android-1.11.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/compose/animation/animation-core-android/1.11.0-SNAPSHOT/animation-core-android-1.11.0-20260317.212834-1.aar Version: 1.11.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_foundation_foundation_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_foundation_foundation_android/README.chromium index dac2baa..d5942d0 100644 --- a/third_party/androidx/committed/libs/androidx_compose_foundation_foundation_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_compose_foundation_foundation_android/README.chromium
@@ -1,6 +1,6 @@ Name: Compose Foundation Short Name: foundation-android -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/compose/foundation/foundation-android/1.11.0-SNAPSHOT/foundation-android-1.11.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/compose/foundation/foundation-android/1.11.0-SNAPSHOT/foundation-android-1.11.0-20260317.212834-1.aar Version: 1.11.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_foundation_foundation_layout_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_foundation_foundation_layout_android/README.chromium index caf5169..f1958aaa 100644 --- a/third_party/androidx/committed/libs/androidx_compose_foundation_foundation_layout_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_compose_foundation_foundation_layout_android/README.chromium
@@ -1,6 +1,6 @@ Name: Compose Layouts Short Name: foundation-layout-android -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/compose/foundation/foundation-layout-android/1.11.0-SNAPSHOT/foundation-layout-android-1.11.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/compose/foundation/foundation-layout-android/1.11.0-SNAPSHOT/foundation-layout-android-1.11.0-20260317.212834-1.aar Version: 1.11.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_material3_material3_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_material3_material3_android/README.chromium index bc6b25c..6faa681 100644 --- a/third_party/androidx/committed/libs/androidx_compose_material3_material3_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_compose_material3_material3_android/README.chromium
@@ -1,6 +1,6 @@ Name: Compose Material3 Components Short Name: material3-android -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/compose/material3/material3-android/1.5.0-SNAPSHOT/material3-android-1.5.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/compose/material3/material3-android/1.5.0-SNAPSHOT/material3-android-1.5.0-20260317.212834-1.aar Version: 1.5.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_material_material_ripple_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_material_material_ripple_android/README.chromium index 48cb959..2d2b8f9b 100644 --- a/third_party/androidx/committed/libs/androidx_compose_material_material_ripple_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_compose_material_material_ripple_android/README.chromium
@@ -1,6 +1,6 @@ Name: Compose Material Ripple Short Name: material-ripple-android -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/compose/material/material-ripple-android/1.11.0-SNAPSHOT/material-ripple-android-1.11.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/compose/material/material-ripple-android/1.11.0-SNAPSHOT/material-ripple-android-1.11.0-20260317.212834-1.aar Version: 1.11.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_android/README.chromium index ebcf0c7c4..2c1388a 100644 --- a/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_android/README.chromium
@@ -1,6 +1,6 @@ Name: Compose Runtime Short Name: runtime-android -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/compose/runtime/runtime-android/1.11.0-SNAPSHOT/runtime-android-1.11.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/compose/runtime/runtime-android/1.11.0-SNAPSHOT/runtime-android-1.11.0-20260317.212834-1.aar Version: 1.11.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_annotation_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_annotation_android/README.chromium index 2b7edfe..6f83b8f 100644 --- a/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_annotation_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_annotation_android/README.chromium
@@ -1,6 +1,6 @@ Name: Compose Runtime Annotation Short Name: runtime-annotation-android -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/compose/runtime/runtime-annotation-android/1.11.0-SNAPSHOT/runtime-annotation-android-1.11.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/compose/runtime/runtime-annotation-android/1.11.0-SNAPSHOT/runtime-annotation-android-1.11.0-20260317.212834-1.aar Version: 1.11.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_retain_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_retain_android/README.chromium index bf29d1d3..ec1b964 100644 --- a/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_retain_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_retain_android/README.chromium
@@ -1,6 +1,6 @@ Name: Compose Runtime Retain Short Name: runtime-retain-android -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/compose/runtime/runtime-retain-android/1.11.0-SNAPSHOT/runtime-retain-android-1.11.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/compose/runtime/runtime-retain-android/1.11.0-SNAPSHOT/runtime-retain-android-1.11.0-20260317.212834-1.aar Version: 1.11.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_saveable_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_saveable_android/README.chromium index 01ba327c..0e964d3 100644 --- a/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_saveable_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_saveable_android/README.chromium
@@ -1,6 +1,6 @@ Name: Compose Saveable Short Name: runtime-saveable-android -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/compose/runtime/runtime-saveable-android/1.11.0-SNAPSHOT/runtime-saveable-android-1.11.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/compose/runtime/runtime-saveable-android/1.11.0-SNAPSHOT/runtime-saveable-android-1.11.0-20260317.212834-1.aar Version: 1.11.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_ui_ui_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_ui_ui_android/README.chromium index ccc5c1b..7c56cfc 100644 --- a/third_party/androidx/committed/libs/androidx_compose_ui_ui_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_compose_ui_ui_android/README.chromium
@@ -1,6 +1,6 @@ Name: Compose UI Short Name: ui-android -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/compose/ui/ui-android/1.11.0-SNAPSHOT/ui-android-1.11.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/compose/ui/ui-android/1.11.0-SNAPSHOT/ui-android-1.11.0-20260317.212834-1.aar Version: 1.11.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_ui_ui_geometry_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_ui_ui_geometry_android/README.chromium index 40b29f21..23745047 100644 --- a/third_party/androidx/committed/libs/androidx_compose_ui_ui_geometry_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_compose_ui_ui_geometry_android/README.chromium
@@ -1,6 +1,6 @@ Name: Compose Geometry Short Name: ui-geometry-android -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/compose/ui/ui-geometry-android/1.11.0-SNAPSHOT/ui-geometry-android-1.11.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/compose/ui/ui-geometry-android/1.11.0-SNAPSHOT/ui-geometry-android-1.11.0-20260317.212834-1.aar Version: 1.11.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_ui_ui_graphics_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_ui_ui_graphics_android/README.chromium index 100bcf0..abcd3d3 100644 --- a/third_party/androidx/committed/libs/androidx_compose_ui_ui_graphics_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_compose_ui_ui_graphics_android/README.chromium
@@ -1,6 +1,6 @@ Name: Compose Graphics Short Name: ui-graphics-android -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/compose/ui/ui-graphics-android/1.11.0-SNAPSHOT/ui-graphics-android-1.11.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/compose/ui/ui-graphics-android/1.11.0-SNAPSHOT/ui-graphics-android-1.11.0-20260317.212834-1.aar Version: 1.11.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_android/README.chromium index f3b4c2f..fc71b932 100644 --- a/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_android/README.chromium
@@ -1,6 +1,6 @@ Name: Compose Testing Short Name: ui-test-android -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/compose/ui/ui-test-android/1.11.0-SNAPSHOT/ui-test-android-1.11.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/compose/ui/ui-test-android/1.11.0-SNAPSHOT/ui-test-android-1.11.0-20260317.212834-1.aar Version: 1.11.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_junit4_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_junit4_android/README.chromium index 03fed0ba..42972a9 100644 --- a/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_junit4_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_junit4_android/README.chromium
@@ -1,6 +1,6 @@ Name: Compose Testing for JUnit4 Short Name: ui-test-junit4-android -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/compose/ui/ui-test-junit4-android/1.11.0-SNAPSHOT/ui-test-junit4-android-1.11.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/compose/ui/ui-test-junit4-android/1.11.0-SNAPSHOT/ui-test-junit4-android-1.11.0-20260317.212834-1.aar Version: 1.11.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_manifest/README.chromium b/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_manifest/README.chromium index 13301317..5236ef3c 100644 --- a/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_manifest/README.chromium +++ b/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_manifest/README.chromium
@@ -1,6 +1,6 @@ Name: Compose Testing manifest dependency Short Name: ui-test-manifest -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/compose/ui/ui-test-manifest/1.11.0-SNAPSHOT/ui-test-manifest-1.11.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/compose/ui/ui-test-manifest/1.11.0-SNAPSHOT/ui-test-manifest-1.11.0-20260317.212834-1.aar Version: 1.11.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_ui_ui_text_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_ui_ui_text_android/README.chromium index 3cb49e7..cbec4bb 100644 --- a/third_party/androidx/committed/libs/androidx_compose_ui_ui_text_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_compose_ui_ui_text_android/README.chromium
@@ -1,6 +1,6 @@ Name: Compose UI Text Short Name: ui-text-android -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/compose/ui/ui-text-android/1.11.0-SNAPSHOT/ui-text-android-1.11.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/compose/ui/ui-text-android/1.11.0-SNAPSHOT/ui-text-android-1.11.0-20260317.212834-1.aar Version: 1.11.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_ui_ui_text_google_fonts/README.chromium b/third_party/androidx/committed/libs/androidx_compose_ui_ui_text_google_fonts/README.chromium index 20b7f2520..af41b3e 100644 --- a/third_party/androidx/committed/libs/androidx_compose_ui_ui_text_google_fonts/README.chromium +++ b/third_party/androidx/committed/libs/androidx_compose_ui_ui_text_google_fonts/README.chromium
@@ -1,6 +1,6 @@ Name: Compose Google Fonts integration Short Name: ui-text-google-fonts -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/compose/ui/ui-text-google-fonts/1.11.0-SNAPSHOT/ui-text-google-fonts-1.11.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/compose/ui/ui-text-google-fonts/1.11.0-SNAPSHOT/ui-text-google-fonts-1.11.0-20260317.212834-1.aar Version: 1.11.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_ui_ui_unit_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_ui_ui_unit_android/README.chromium index eee1802b..aba61bc1 100644 --- a/third_party/androidx/committed/libs/androidx_compose_ui_ui_unit_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_compose_ui_ui_unit_android/README.chromium
@@ -1,6 +1,6 @@ Name: Compose Unit Short Name: ui-unit-android -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/compose/ui/ui-unit-android/1.11.0-SNAPSHOT/ui-unit-android-1.11.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/compose/ui/ui-unit-android/1.11.0-SNAPSHOT/ui-unit-android-1.11.0-20260317.212834-1.aar Version: 1.11.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_ui_ui_util_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_ui_ui_util_android/README.chromium index b17fd40..2093eefd 100644 --- a/third_party/androidx/committed/libs/androidx_compose_ui_ui_util_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_compose_ui_ui_util_android/README.chromium
@@ -1,6 +1,6 @@ Name: Compose Util Short Name: ui-util-android -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/compose/ui/ui-util-android/1.11.0-SNAPSHOT/ui-util-android-1.11.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/compose/ui/ui-util-android/1.11.0-SNAPSHOT/ui-util-android-1.11.0-20260317.212834-1.aar Version: 1.11.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_constraintlayout_constraintlayout/README.chromium b/third_party/androidx/committed/libs/androidx_constraintlayout_constraintlayout/README.chromium index b48571f..cd07689 100644 --- a/third_party/androidx/committed/libs/androidx_constraintlayout_constraintlayout/README.chromium +++ b/third_party/androidx/committed/libs/androidx_constraintlayout_constraintlayout/README.chromium
@@ -1,6 +1,6 @@ Name: ConstraintLayout Short Name: constraintlayout -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/constraintlayout/constraintlayout/2.3.0-SNAPSHOT/constraintlayout-2.3.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/constraintlayout/constraintlayout/2.3.0-SNAPSHOT/constraintlayout-2.3.0-20260317.212834-1.aar Version: 2.3.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_constraintlayout_constraintlayout_core/README.chromium b/third_party/androidx/committed/libs/androidx_constraintlayout_constraintlayout_core/README.chromium index ddffe3b..c5192f1 100644 --- a/third_party/androidx/committed/libs/androidx_constraintlayout_constraintlayout_core/README.chromium +++ b/third_party/androidx/committed/libs/androidx_constraintlayout_constraintlayout_core/README.chromium
@@ -1,6 +1,6 @@ Name: ConstraintLayout Core Short Name: constraintlayout-core -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/constraintlayout/constraintlayout-core/1.2.0-SNAPSHOT/constraintlayout-core-1.2.0-20260317.131640-1.jar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/constraintlayout/constraintlayout-core/1.2.0-SNAPSHOT/constraintlayout-core-1.2.0-20260317.212834-1.jar Version: 1.2.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_core_core/README.chromium b/third_party/androidx/committed/libs/androidx_core_core/README.chromium index 3d9e671..dd528197 100644 --- a/third_party/androidx/committed/libs/androidx_core_core/README.chromium +++ b/third_party/androidx/committed/libs/androidx_core_core/README.chromium
@@ -1,6 +1,6 @@ Name: Core Short Name: core -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/core/core/1.19.0-SNAPSHOT/core-1.19.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/core/core/1.19.0-SNAPSHOT/core-1.19.0-20260317.212834-1.aar Version: 1.19.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_core_core_ktx/README.chromium b/third_party/androidx/committed/libs/androidx_core_core_ktx/README.chromium index 1da14c84c..a3ce76d 100644 --- a/third_party/androidx/committed/libs/androidx_core_core_ktx/README.chromium +++ b/third_party/androidx/committed/libs/androidx_core_core_ktx/README.chromium
@@ -1,6 +1,6 @@ Name: Core Kotlin Extensions Short Name: core-ktx -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/core/core-ktx/1.19.0-SNAPSHOT/core-ktx-1.19.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/core/core-ktx/1.19.0-SNAPSHOT/core-ktx-1.19.0-20260317.212834-1.aar Version: 1.19.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_core_core_pip/README.chromium b/third_party/androidx/committed/libs/androidx_core_core_pip/README.chromium index 6e55bd9..8a32bb6 100644 --- a/third_party/androidx/committed/libs/androidx_core_core_pip/README.chromium +++ b/third_party/androidx/committed/libs/androidx_core_core_pip/README.chromium
@@ -1,6 +1,6 @@ Name: androidx.core:core-pip Short Name: core-pip -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/core/core-pip/1.0.0-SNAPSHOT/core-pip-1.0.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/core/core-pip/1.0.0-SNAPSHOT/core-pip-1.0.0-20260317.212834-1.aar Version: 1.0.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_core_core_viewtree/README.chromium b/third_party/androidx/committed/libs/androidx_core_core_viewtree/README.chromium index 38a8ad7..b987a70f 100644 --- a/third_party/androidx/committed/libs/androidx_core_core_viewtree/README.chromium +++ b/third_party/androidx/committed/libs/androidx_core_core_viewtree/README.chromium
@@ -1,6 +1,6 @@ Name: androidx.core:core-viewtree Short Name: core-viewtree -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/core/core-viewtree/1.1.0-SNAPSHOT/core-viewtree-1.1.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/core/core-viewtree/1.1.0-SNAPSHOT/core-viewtree-1.1.0-20260317.212834-1.aar Version: 1.1.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_credentials_credentials/README.chromium b/third_party/androidx/committed/libs/androidx_credentials_credentials/README.chromium index 29c5ce9..2298fd7 100644 --- a/third_party/androidx/committed/libs/androidx_credentials_credentials/README.chromium +++ b/third_party/androidx/committed/libs/androidx_credentials_credentials/README.chromium
@@ -1,6 +1,6 @@ Name: Credentials Short Name: credentials -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/credentials/credentials/1.6.0-SNAPSHOT/credentials-1.6.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/credentials/credentials/1.6.0-SNAPSHOT/credentials-1.6.0-20260317.212834-1.aar Version: 1.6.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_credentials_credentials_play_services_auth/README.chromium b/third_party/androidx/committed/libs/androidx_credentials_credentials_play_services_auth/README.chromium index 73747efa..1735228 100644 --- a/third_party/androidx/committed/libs/androidx_credentials_credentials_play_services_auth/README.chromium +++ b/third_party/androidx/committed/libs/androidx_credentials_credentials_play_services_auth/README.chromium
@@ -1,6 +1,6 @@ Name: Credentials Play Services Auth Short Name: credentials-play-services-auth -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/credentials/credentials-play-services-auth/1.6.0-SNAPSHOT/credentials-play-services-auth-1.6.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/credentials/credentials-play-services-auth/1.6.0-SNAPSHOT/credentials-play-services-auth-1.6.0-20260317.212834-1.aar Version: 1.6.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_credentials_registry_registry_provider/README.chromium b/third_party/androidx/committed/libs/androidx_credentials_registry_registry_provider/README.chromium index 804296d..a96cdddf 100644 --- a/third_party/androidx/committed/libs/androidx_credentials_registry_registry_provider/README.chromium +++ b/third_party/androidx/committed/libs/androidx_credentials_registry_registry_provider/README.chromium
@@ -1,6 +1,6 @@ Name: androidx.credentials.registry:registry-provider Short Name: registry-provider -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/credentials/registry/registry-provider/1.0.0-SNAPSHOT/registry-provider-1.0.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/credentials/registry/registry-provider/1.0.0-SNAPSHOT/registry-provider-1.0.0-20260317.212834-1.aar Version: 1.0.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_credentials_registry_registry_provider_play_services/README.chromium b/third_party/androidx/committed/libs/androidx_credentials_registry_registry_provider_play_services/README.chromium index fc3921f..e6f836ea 100644 --- a/third_party/androidx/committed/libs/androidx_credentials_registry_registry_provider_play_services/README.chromium +++ b/third_party/androidx/committed/libs/androidx_credentials_registry_registry_provider_play_services/README.chromium
@@ -1,6 +1,6 @@ Name: androidx.credentials.registry:registry-provider-play-services Short Name: registry-provider-play-services -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/credentials/registry/registry-provider-play-services/1.0.0-SNAPSHOT/registry-provider-play-services-1.0.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/credentials/registry/registry-provider-play-services/1.0.0-SNAPSHOT/registry-provider-play-services-1.0.0-20260317.212834-1.aar Version: 1.0.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_cursoradapter_cursoradapter/README.chromium b/third_party/androidx/committed/libs/androidx_cursoradapter_cursoradapter/README.chromium index 49abe1e..c48e871 100644 --- a/third_party/androidx/committed/libs/androidx_cursoradapter_cursoradapter/README.chromium +++ b/third_party/androidx/committed/libs/androidx_cursoradapter_cursoradapter/README.chromium
@@ -1,6 +1,6 @@ Name: Cursor Adapter Short Name: cursoradapter -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/cursoradapter/cursoradapter/1.1.0-SNAPSHOT/cursoradapter-1.1.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/cursoradapter/cursoradapter/1.1.0-SNAPSHOT/cursoradapter-1.1.0-20260317.212834-1.aar Version: 1.1.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_datastore_datastore_android/README.chromium b/third_party/androidx/committed/libs/androidx_datastore_datastore_android/README.chromium index eb8b251..6125e78 100644 --- a/third_party/androidx/committed/libs/androidx_datastore_datastore_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_datastore_datastore_android/README.chromium
@@ -1,6 +1,6 @@ Name: DataStore Short Name: datastore-android -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/datastore/datastore-android/1.3.0-SNAPSHOT/datastore-android-1.3.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/datastore/datastore-android/1.3.0-SNAPSHOT/datastore-android-1.3.0-20260317.212834-1.aar Version: 1.3.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_datastore_datastore_core_android/README.chromium b/third_party/androidx/committed/libs/androidx_datastore_datastore_core_android/README.chromium index 4bf4227..f5cc8c9 100644 --- a/third_party/androidx/committed/libs/androidx_datastore_datastore_core_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_datastore_datastore_core_android/README.chromium
@@ -1,6 +1,6 @@ Name: DataStore Core Short Name: datastore-core-android -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/datastore/datastore-core-android/1.3.0-SNAPSHOT/datastore-core-android-1.3.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/datastore/datastore-core-android/1.3.0-SNAPSHOT/datastore-core-android-1.3.0-20260317.212834-1.aar Version: 1.3.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_datastore_datastore_core_okio_jvm/README.chromium b/third_party/androidx/committed/libs/androidx_datastore_datastore_core_okio_jvm/README.chromium index 9640404..fff55ff 100644 --- a/third_party/androidx/committed/libs/androidx_datastore_datastore_core_okio_jvm/README.chromium +++ b/third_party/androidx/committed/libs/androidx_datastore_datastore_core_okio_jvm/README.chromium
@@ -1,6 +1,6 @@ Name: DataStore Core Okio Short Name: datastore-core-okio-jvm -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/datastore/datastore-core-okio-jvm/1.3.0-SNAPSHOT/datastore-core-okio-jvm-1.3.0-20260317.131640-1.jar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/datastore/datastore-core-okio-jvm/1.3.0-SNAPSHOT/datastore-core-okio-jvm-1.3.0-20260317.212834-1.jar Version: 1.3.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_android/README.chromium b/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_android/README.chromium index 6c0d8c2..48be0691 100644 --- a/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_android/README.chromium
@@ -1,6 +1,6 @@ Name: Preferences DataStore Short Name: datastore-preferences-android -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/datastore/datastore-preferences-android/1.3.0-SNAPSHOT/datastore-preferences-android-1.3.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/datastore/datastore-preferences-android/1.3.0-SNAPSHOT/datastore-preferences-android-1.3.0-20260317.212834-1.aar Version: 1.3.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_core_android/README.chromium b/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_core_android/README.chromium index b831bea4..0c55de5 100644 --- a/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_core_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_core_android/README.chromium
@@ -1,6 +1,6 @@ Name: Preferences DataStore Core Short Name: datastore-preferences-core-android -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/datastore/datastore-preferences-core-android/1.3.0-SNAPSHOT/datastore-preferences-core-android-1.3.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/datastore/datastore-preferences-core-android/1.3.0-SNAPSHOT/datastore-preferences-core-android-1.3.0-20260317.212834-1.aar Version: 1.3.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_external_protobuf/README.chromium b/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_external_protobuf/README.chromium index 3cf3329..9ad7763 100644 --- a/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_external_protobuf/README.chromium +++ b/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_external_protobuf/README.chromium
@@ -1,6 +1,6 @@ Name: Preferences External Protobuf Short Name: datastore-preferences-external-protobuf -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/datastore/datastore-preferences-external-protobuf/1.3.0-SNAPSHOT/datastore-preferences-external-protobuf-1.3.0-20260317.131640-1.jar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/datastore/datastore-preferences-external-protobuf/1.3.0-SNAPSHOT/datastore-preferences-external-protobuf-1.3.0-20260317.212834-1.jar Version: 1.3.0-SNAPSHOT Update Mechanism: Autoroll License: BSD-3-Clause
diff --git a/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_proto/README.chromium b/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_proto/README.chromium index 7e8f235..bd69516 100644 --- a/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_proto/README.chromium +++ b/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_proto/README.chromium
@@ -1,6 +1,6 @@ Name: Preferences DataStore Proto Short Name: datastore-preferences-proto -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/datastore/datastore-preferences-proto/1.3.0-SNAPSHOT/datastore-preferences-proto-1.3.0-20260317.131640-1.jar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/datastore/datastore-preferences-proto/1.3.0-SNAPSHOT/datastore-preferences-proto-1.3.0-20260317.212834-1.jar Version: 1.3.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_drawerlayout_drawerlayout/README.chromium b/third_party/androidx/committed/libs/androidx_drawerlayout_drawerlayout/README.chromium index 30d8459..9875f6f7 100644 --- a/third_party/androidx/committed/libs/androidx_drawerlayout_drawerlayout/README.chromium +++ b/third_party/androidx/committed/libs/androidx_drawerlayout_drawerlayout/README.chromium
@@ -1,6 +1,6 @@ Name: Drawer Layout Short Name: drawerlayout -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/drawerlayout/drawerlayout/1.3.0-SNAPSHOT/drawerlayout-1.3.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/drawerlayout/drawerlayout/1.3.0-SNAPSHOT/drawerlayout-1.3.0-20260317.212834-1.aar Version: 1.3.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_fragment_fragment/README.chromium b/third_party/androidx/committed/libs/androidx_fragment_fragment/README.chromium index 23343f8..5efa0148 100644 --- a/third_party/androidx/committed/libs/androidx_fragment_fragment/README.chromium +++ b/third_party/androidx/committed/libs/androidx_fragment_fragment/README.chromium
@@ -1,6 +1,6 @@ Name: fragment Short Name: fragment -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/fragment/fragment/1.9.0-SNAPSHOT/fragment-1.9.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/fragment/fragment/1.9.0-SNAPSHOT/fragment-1.9.0-20260317.212834-1.aar Version: 1.9.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_fragment_fragment_compose/README.chromium b/third_party/androidx/committed/libs/androidx_fragment_fragment_compose/README.chromium index 632ce66a..fb106054 100644 --- a/third_party/androidx/committed/libs/androidx_fragment_fragment_compose/README.chromium +++ b/third_party/androidx/committed/libs/androidx_fragment_fragment_compose/README.chromium
@@ -1,6 +1,6 @@ Name: Fragment Compose Short Name: fragment-compose -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/fragment/fragment-compose/1.9.0-SNAPSHOT/fragment-compose-1.9.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/fragment/fragment-compose/1.9.0-SNAPSHOT/fragment-compose-1.9.0-20260317.212834-1.aar Version: 1.9.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_fragment_fragment_ktx/README.chromium b/third_party/androidx/committed/libs/androidx_fragment_fragment_ktx/README.chromium index 44b2bf1..6cafaed7 100644 --- a/third_party/androidx/committed/libs/androidx_fragment_fragment_ktx/README.chromium +++ b/third_party/androidx/committed/libs/androidx_fragment_fragment_ktx/README.chromium
@@ -1,6 +1,6 @@ Name: Fragment Kotlin Extensions Short Name: fragment-ktx -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/fragment/fragment-ktx/1.9.0-SNAPSHOT/fragment-ktx-1.9.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/fragment/fragment-ktx/1.9.0-SNAPSHOT/fragment-ktx-1.9.0-20260317.212834-1.aar Version: 1.9.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_fragment_fragment_testing/README.chromium b/third_party/androidx/committed/libs/androidx_fragment_fragment_testing/README.chromium index 37c7f39..7ce95fe 100644 --- a/third_party/androidx/committed/libs/androidx_fragment_fragment_testing/README.chromium +++ b/third_party/androidx/committed/libs/androidx_fragment_fragment_testing/README.chromium
@@ -1,6 +1,6 @@ Name: Fragment Testing Extensions Short Name: fragment-testing -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/fragment/fragment-testing/1.9.0-SNAPSHOT/fragment-testing-1.9.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/fragment/fragment-testing/1.9.0-SNAPSHOT/fragment-testing-1.9.0-20260317.212834-1.aar Version: 1.9.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_fragment_fragment_testing_manifest/README.chromium b/third_party/androidx/committed/libs/androidx_fragment_fragment_testing_manifest/README.chromium index ecfc393..6688316 100644 --- a/third_party/androidx/committed/libs/androidx_fragment_fragment_testing_manifest/README.chromium +++ b/third_party/androidx/committed/libs/androidx_fragment_fragment_testing_manifest/README.chromium
@@ -1,6 +1,6 @@ Name: Fragment Testing Manifest dependency Short Name: fragment-testing-manifest -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/fragment/fragment-testing-manifest/1.9.0-SNAPSHOT/fragment-testing-manifest-1.9.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/fragment/fragment-testing-manifest/1.9.0-SNAPSHOT/fragment-testing-manifest-1.9.0-20260317.212834-1.aar Version: 1.9.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_graphics_graphics_path/README.chromium b/third_party/androidx/committed/libs/androidx_graphics_graphics_path/README.chromium index d586d6b..114faf2 100644 --- a/third_party/androidx/committed/libs/androidx_graphics_graphics_path/README.chromium +++ b/third_party/androidx/committed/libs/androidx_graphics_graphics_path/README.chromium
@@ -1,6 +1,6 @@ Name: Android Graphics Path Short Name: graphics-path -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/graphics/graphics-path/1.1.0-SNAPSHOT/graphics-path-1.1.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/graphics/graphics-path/1.1.0-SNAPSHOT/graphics-path-1.1.0-20260317.212834-1.aar Version: 1.1.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_interpolator_interpolator/README.chromium b/third_party/androidx/committed/libs/androidx_interpolator_interpolator/README.chromium index fbc17de..415b3e5 100644 --- a/third_party/androidx/committed/libs/androidx_interpolator_interpolator/README.chromium +++ b/third_party/androidx/committed/libs/androidx_interpolator_interpolator/README.chromium
@@ -1,6 +1,6 @@ Name: Interpolators Short Name: interpolator -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/interpolator/interpolator/1.1.0-SNAPSHOT/interpolator-1.1.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/interpolator/interpolator/1.1.0-SNAPSHOT/interpolator-1.1.0-20260317.212834-1.aar Version: 1.1.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_leanback_leanback/README.chromium b/third_party/androidx/committed/libs/androidx_leanback_leanback/README.chromium index b32c0ad..ed332e5 100644 --- a/third_party/androidx/committed/libs/androidx_leanback_leanback/README.chromium +++ b/third_party/androidx/committed/libs/androidx_leanback_leanback/README.chromium
@@ -1,6 +1,6 @@ Name: Leanback Short Name: leanback -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/leanback/leanback/1.3.0-SNAPSHOT/leanback-1.3.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/leanback/leanback/1.3.0-SNAPSHOT/leanback-1.3.0-20260317.212834-1.aar Version: 1.3.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_leanback_leanback_grid/README.chromium b/third_party/androidx/committed/libs/androidx_leanback_leanback_grid/README.chromium index 27a47d70..02847e4 100644 --- a/third_party/androidx/committed/libs/androidx_leanback_leanback_grid/README.chromium +++ b/third_party/androidx/committed/libs/androidx_leanback_leanback_grid/README.chromium
@@ -1,6 +1,6 @@ Name: Leanback Grid Short Name: leanback-grid -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/leanback/leanback-grid/1.1.0-SNAPSHOT/leanback-grid-1.1.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/leanback/leanback-grid/1.1.0-SNAPSHOT/leanback-grid-1.1.0-20260317.212834-1.aar Version: 1.1.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_common_java8/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_common_java8/README.chromium index 67867bc..3ff8a53 100644 --- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_common_java8/README.chromium +++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_common_java8/README.chromium
@@ -1,6 +1,6 @@ Name: Lifecycle-Common for Java 8 Short Name: lifecycle-common-java8 -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/lifecycle/lifecycle-common-java8/2.11.0-SNAPSHOT/lifecycle-common-java8-2.11.0-20260317.131640-1.jar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/lifecycle/lifecycle-common-java8/2.11.0-SNAPSHOT/lifecycle-common-java8-2.11.0-20260317.212834-1.jar Version: 2.11.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_common_jvm/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_common_jvm/README.chromium index fae39a88..f2cf7693 100644 --- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_common_jvm/README.chromium +++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_common_jvm/README.chromium
@@ -1,6 +1,6 @@ Name: Lifecycle-Common Short Name: lifecycle-common-jvm -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/lifecycle/lifecycle-common-jvm/2.11.0-SNAPSHOT/lifecycle-common-jvm-2.11.0-20260317.131640-1.jar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/lifecycle/lifecycle-common-jvm/2.11.0-SNAPSHOT/lifecycle-common-jvm-2.11.0-20260317.212834-1.jar Version: 2.11.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata/README.chromium index 217097c..538294db 100644 --- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata/README.chromium +++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata/README.chromium
@@ -1,6 +1,6 @@ Name: Lifecycle LiveData Short Name: lifecycle-livedata -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/lifecycle/lifecycle-livedata/2.11.0-SNAPSHOT/lifecycle-livedata-2.11.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/lifecycle/lifecycle-livedata/2.11.0-SNAPSHOT/lifecycle-livedata-2.11.0-20260317.212834-1.aar Version: 2.11.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_core/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_core/README.chromium index ff99756..684f1d0 100644 --- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_core/README.chromium +++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_core/README.chromium
@@ -1,6 +1,6 @@ Name: Lifecycle LiveData Core Short Name: lifecycle-livedata-core -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/lifecycle/lifecycle-livedata-core/2.11.0-SNAPSHOT/lifecycle-livedata-core-2.11.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/lifecycle/lifecycle-livedata-core/2.11.0-SNAPSHOT/lifecycle-livedata-core-2.11.0-20260317.212834-1.aar Version: 2.11.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_core_ktx/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_core_ktx/README.chromium index 4832fae..f7203ca 100644 --- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_core_ktx/README.chromium +++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_core_ktx/README.chromium
@@ -1,6 +1,6 @@ Name: LiveData Core Kotlin Extensions Short Name: lifecycle-livedata-core-ktx -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/lifecycle/lifecycle-livedata-core-ktx/2.11.0-SNAPSHOT/lifecycle-livedata-core-ktx-2.11.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/lifecycle/lifecycle-livedata-core-ktx/2.11.0-SNAPSHOT/lifecycle-livedata-core-ktx-2.11.0-20260317.212834-1.aar Version: 2.11.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_ktx/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_ktx/README.chromium index f9be524..576a1de 100644 --- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_ktx/README.chromium +++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_ktx/README.chromium
@@ -1,6 +1,6 @@ Name: LiveData Kotlin Extensions Short Name: lifecycle-livedata-ktx -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/lifecycle/lifecycle-livedata-ktx/2.11.0-SNAPSHOT/lifecycle-livedata-ktx-2.11.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/lifecycle/lifecycle-livedata-ktx/2.11.0-SNAPSHOT/lifecycle-livedata-ktx-2.11.0-20260317.212834-1.aar Version: 2.11.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_process/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_process/README.chromium index 2d1f2557..d5a1ef80 100644 --- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_process/README.chromium +++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_process/README.chromium
@@ -1,6 +1,6 @@ Name: Lifecycle Process Short Name: lifecycle-process -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/lifecycle/lifecycle-process/2.11.0-SNAPSHOT/lifecycle-process-2.11.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/lifecycle/lifecycle-process/2.11.0-SNAPSHOT/lifecycle-process-2.11.0-20260317.212834-1.aar Version: 2.11.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_android/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_android/README.chromium index c0c242fcc..934b7ac5 100644 --- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_android/README.chromium
@@ -1,6 +1,6 @@ Name: Lifecycle Runtime Short Name: lifecycle-runtime-android -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/lifecycle/lifecycle-runtime-android/2.11.0-SNAPSHOT/lifecycle-runtime-android-2.11.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/lifecycle/lifecycle-runtime-android/2.11.0-SNAPSHOT/lifecycle-runtime-android-2.11.0-20260317.212834-1.aar Version: 2.11.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_compose_android/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_compose_android/README.chromium index e725b09..862deab 100644 --- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_compose_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_compose_android/README.chromium
@@ -1,6 +1,6 @@ Name: Lifecycle Runtime Compose Short Name: lifecycle-runtime-compose-android -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/lifecycle/lifecycle-runtime-compose-android/2.11.0-SNAPSHOT/lifecycle-runtime-compose-android-2.11.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/lifecycle/lifecycle-runtime-compose-android/2.11.0-SNAPSHOT/lifecycle-runtime-compose-android-2.11.0-20260317.212834-1.aar Version: 2.11.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_ktx_android/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_ktx_android/README.chromium index 0dfcb2a..938ce40a 100644 --- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_ktx_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_ktx_android/README.chromium
@@ -1,6 +1,6 @@ Name: Lifecycle Kotlin Extensions Short Name: lifecycle-runtime-ktx-android -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/lifecycle/lifecycle-runtime-ktx-android/2.11.0-SNAPSHOT/lifecycle-runtime-ktx-android-2.11.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/lifecycle/lifecycle-runtime-ktx-android/2.11.0-SNAPSHOT/lifecycle-runtime-ktx-android-2.11.0-20260317.212834-1.aar Version: 2.11.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_service/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_service/README.chromium index 66acbd4..3939117 100644 --- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_service/README.chromium +++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_service/README.chromium
@@ -1,6 +1,6 @@ Name: Lifecycle Service Short Name: lifecycle-service -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/lifecycle/lifecycle-service/2.11.0-SNAPSHOT/lifecycle-service-2.11.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/lifecycle/lifecycle-service/2.11.0-SNAPSHOT/lifecycle-service-2.11.0-20260317.212834-1.aar Version: 2.11.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_android/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_android/README.chromium index bfc90da0..38e88a1 100644 --- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_android/README.chromium
@@ -1,6 +1,6 @@ Name: Lifecycle ViewModel Short Name: lifecycle-viewmodel-android -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/lifecycle/lifecycle-viewmodel-android/2.11.0-SNAPSHOT/lifecycle-viewmodel-android-2.11.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/lifecycle/lifecycle-viewmodel-android/2.11.0-SNAPSHOT/lifecycle-viewmodel-android-2.11.0-20260317.212834-1.aar Version: 2.11.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_compose_android/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_compose_android/README.chromium index 469aa32..b338420 100644 --- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_compose_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_compose_android/README.chromium
@@ -1,6 +1,6 @@ Name: Lifecycle ViewModel Compose Short Name: lifecycle-viewmodel-compose-android -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/lifecycle/lifecycle-viewmodel-compose-android/2.11.0-SNAPSHOT/lifecycle-viewmodel-compose-android-2.11.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/lifecycle/lifecycle-viewmodel-compose-android/2.11.0-SNAPSHOT/lifecycle-viewmodel-compose-android-2.11.0-20260317.212834-1.aar Version: 2.11.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_ktx/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_ktx/README.chromium index 5d7af056..317abf0 100644 --- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_ktx/README.chromium +++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_ktx/README.chromium
@@ -1,6 +1,6 @@ Name: Lifecycle ViewModel Kotlin Extensions Short Name: lifecycle-viewmodel-ktx -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/lifecycle/lifecycle-viewmodel-ktx/2.11.0-SNAPSHOT/lifecycle-viewmodel-ktx-2.11.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/lifecycle/lifecycle-viewmodel-ktx/2.11.0-SNAPSHOT/lifecycle-viewmodel-ktx-2.11.0-20260317.212834-1.aar Version: 2.11.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_savedstate_android/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_savedstate_android/README.chromium index f56a53b..36de90b 100644 --- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_savedstate_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_savedstate_android/README.chromium
@@ -1,6 +1,6 @@ Name: Lifecycle ViewModel with SavedState Short Name: lifecycle-viewmodel-savedstate-android -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/lifecycle/lifecycle-viewmodel-savedstate-android/2.11.0-SNAPSHOT/lifecycle-viewmodel-savedstate-android-2.11.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/lifecycle/lifecycle-viewmodel-savedstate-android/2.11.0-SNAPSHOT/lifecycle-viewmodel-savedstate-android-2.11.0-20260317.212834-1.aar Version: 2.11.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_loader_loader/README.chromium b/third_party/androidx/committed/libs/androidx_loader_loader/README.chromium index 36d8fed..68480ce 100644 --- a/third_party/androidx/committed/libs/androidx_loader_loader/README.chromium +++ b/third_party/androidx/committed/libs/androidx_loader_loader/README.chromium
@@ -1,6 +1,6 @@ Name: loader Short Name: loader -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/loader/loader/1.2.0-SNAPSHOT/loader-1.2.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/loader/loader/1.2.0-SNAPSHOT/loader-1.2.0-20260317.212834-1.aar Version: 1.2.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_media_media/README.chromium b/third_party/androidx/committed/libs/androidx_media_media/README.chromium index 84fce88..ee4410e 100644 --- a/third_party/androidx/committed/libs/androidx_media_media/README.chromium +++ b/third_party/androidx/committed/libs/androidx_media_media/README.chromium
@@ -1,6 +1,6 @@ Name: Media Short Name: media -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/media/media/1.8.0-SNAPSHOT/media-1.8.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/media/media/1.8.0-SNAPSHOT/media-1.8.0-20260317.212834-1.aar Version: 1.8.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_mediarouter_mediarouter/README.chromium b/third_party/androidx/committed/libs/androidx_mediarouter_mediarouter/README.chromium index 995eb89..fd63f54 100644 --- a/third_party/androidx/committed/libs/androidx_mediarouter_mediarouter/README.chromium +++ b/third_party/androidx/committed/libs/androidx_mediarouter_mediarouter/README.chromium
@@ -1,6 +1,6 @@ Name: MediaRouter Short Name: mediarouter -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/mediarouter/mediarouter/1.9.0-SNAPSHOT/mediarouter-1.9.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/mediarouter/mediarouter/1.9.0-SNAPSHOT/mediarouter-1.9.0-20260317.212834-1.aar Version: 1.9.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_navigation_navigation_common_android/README.chromium b/third_party/androidx/committed/libs/androidx_navigation_navigation_common_android/README.chromium index 7508af5d..ba7a774d 100644 --- a/third_party/androidx/committed/libs/androidx_navigation_navigation_common_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_navigation_navigation_common_android/README.chromium
@@ -1,6 +1,6 @@ Name: Navigation Common Short Name: navigation-common-android -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/navigation/navigation-common-android/2.10.0-SNAPSHOT/navigation-common-android-2.10.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/navigation/navigation-common-android/2.10.0-SNAPSHOT/navigation-common-android-2.10.0-20260317.212834-1.aar Version: 2.10.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_navigation_navigation_compose_android/README.chromium b/third_party/androidx/committed/libs/androidx_navigation_navigation_compose_android/README.chromium index 8a7ccfd..58f06ac5 100644 --- a/third_party/androidx/committed/libs/androidx_navigation_navigation_compose_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_navigation_navigation_compose_android/README.chromium
@@ -1,6 +1,6 @@ Name: Compose Navigation Short Name: navigation-compose-android -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/navigation/navigation-compose-android/2.10.0-SNAPSHOT/navigation-compose-android-2.10.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/navigation/navigation-compose-android/2.10.0-SNAPSHOT/navigation-compose-android-2.10.0-20260317.212834-1.aar Version: 2.10.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_navigation_navigation_runtime_android/README.chromium b/third_party/androidx/committed/libs/androidx_navigation_navigation_runtime_android/README.chromium index 9a9b8cdf..96ce9ff0 100644 --- a/third_party/androidx/committed/libs/androidx_navigation_navigation_runtime_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_navigation_navigation_runtime_android/README.chromium
@@ -1,6 +1,6 @@ Name: Navigation Runtime Short Name: navigation-runtime-android -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/navigation/navigation-runtime-android/2.10.0-SNAPSHOT/navigation-runtime-android-2.10.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/navigation/navigation-runtime-android/2.10.0-SNAPSHOT/navigation-runtime-android-2.10.0-20260317.212834-1.aar Version: 2.10.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_navigationevent_navigationevent_android/README.chromium b/third_party/androidx/committed/libs/androidx_navigationevent_navigationevent_android/README.chromium index 516b3665..7565ff93 100644 --- a/third_party/androidx/committed/libs/androidx_navigationevent_navigationevent_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_navigationevent_navigationevent_android/README.chromium
@@ -1,6 +1,6 @@ Name: Navigation Event Short Name: navigationevent-android -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/navigationevent/navigationevent-android/1.1.0-SNAPSHOT/navigationevent-android-1.1.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/navigationevent/navigationevent-android/1.1.0-SNAPSHOT/navigationevent-android-1.1.0-20260317.212834-1.aar Version: 1.1.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_navigationevent_navigationevent_compose_android/README.chromium b/third_party/androidx/committed/libs/androidx_navigationevent_navigationevent_compose_android/README.chromium index 9d1c0acd..65452b73 100644 --- a/third_party/androidx/committed/libs/androidx_navigationevent_navigationevent_compose_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_navigationevent_navigationevent_compose_android/README.chromium
@@ -1,6 +1,6 @@ Name: NavigationEvent Compose Short Name: navigationevent-compose-android -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/navigationevent/navigationevent-compose-android/1.1.0-SNAPSHOT/navigationevent-compose-android-1.1.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/navigationevent/navigationevent-compose-android/1.1.0-SNAPSHOT/navigationevent-compose-android-1.1.0-20260317.212834-1.aar Version: 1.1.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_paging_paging_common_android/README.chromium b/third_party/androidx/committed/libs/androidx_paging_paging_common_android/README.chromium index ed702baf..3952b728 100644 --- a/third_party/androidx/committed/libs/androidx_paging_paging_common_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_paging_paging_common_android/README.chromium
@@ -1,6 +1,6 @@ Name: Paging-Common Short Name: paging-common-android -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/paging/paging-common-android/3.5.0-SNAPSHOT/paging-common-android-3.5.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/paging/paging-common-android/3.5.0-SNAPSHOT/paging-common-android-3.5.0-20260317.212834-1.aar Version: 3.5.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_paging_paging_common_ktx/README.chromium b/third_party/androidx/committed/libs/androidx_paging_paging_common_ktx/README.chromium index cd6bf99..58f9a08 100644 --- a/third_party/androidx/committed/libs/androidx_paging_paging_common_ktx/README.chromium +++ b/third_party/androidx/committed/libs/androidx_paging_paging_common_ktx/README.chromium
@@ -1,6 +1,6 @@ Name: Paging-Common Kotlin Extensions Short Name: paging-common-ktx -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/paging/paging-common-ktx/3.5.0-SNAPSHOT/paging-common-ktx-3.5.0-20260317.131640-1.jar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/paging/paging-common-ktx/3.5.0-SNAPSHOT/paging-common-ktx-3.5.0-20260317.212834-1.jar Version: 3.5.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_paging_paging_compose_android/README.chromium b/third_party/androidx/committed/libs/androidx_paging_paging_compose_android/README.chromium index 933f148..18677d8 100644 --- a/third_party/androidx/committed/libs/androidx_paging_paging_compose_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_paging_paging_compose_android/README.chromium
@@ -1,6 +1,6 @@ Name: Paging-Compose Short Name: paging-compose-android -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/paging/paging-compose-android/3.5.0-SNAPSHOT/paging-compose-android-3.5.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/paging/paging-compose-android/3.5.0-SNAPSHOT/paging-compose-android-3.5.0-20260317.212834-1.aar Version: 3.5.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_paging_paging_runtime/README.chromium b/third_party/androidx/committed/libs/androidx_paging_paging_runtime/README.chromium index afd9cf77..496f9e9 100644 --- a/third_party/androidx/committed/libs/androidx_paging_paging_runtime/README.chromium +++ b/third_party/androidx/committed/libs/androidx_paging_paging_runtime/README.chromium
@@ -1,6 +1,6 @@ Name: Paging-Runtime Short Name: paging-runtime -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/paging/paging-runtime/3.5.0-SNAPSHOT/paging-runtime-3.5.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/paging/paging-runtime/3.5.0-SNAPSHOT/paging-runtime-3.5.0-20260317.212834-1.aar Version: 3.5.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_palette_palette/README.chromium b/third_party/androidx/committed/libs/androidx_palette_palette/README.chromium index 03a8072..9f6ba35 100644 --- a/third_party/androidx/committed/libs/androidx_palette_palette/README.chromium +++ b/third_party/androidx/committed/libs/androidx_palette_palette/README.chromium
@@ -1,6 +1,6 @@ Name: Palette Short Name: palette -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/palette/palette/1.1.0-SNAPSHOT/palette-1.1.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/palette/palette/1.1.0-SNAPSHOT/palette-1.1.0-20260317.212834-1.aar Version: 1.1.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_preference_preference/README.chromium b/third_party/androidx/committed/libs/androidx_preference_preference/README.chromium index 33709be..a6d4545 100644 --- a/third_party/androidx/committed/libs/androidx_preference_preference/README.chromium +++ b/third_party/androidx/committed/libs/androidx_preference_preference/README.chromium
@@ -1,6 +1,6 @@ Name: Preference Short Name: preference -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/preference/preference/1.3.0-SNAPSHOT/preference-1.3.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/preference/preference/1.3.0-SNAPSHOT/preference-1.3.0-20260317.212834-1.aar Version: 1.3.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_profileinstaller_profileinstaller/README.chromium b/third_party/androidx/committed/libs/androidx_profileinstaller_profileinstaller/README.chromium index 7c30fcc..ac1c1ed 100644 --- a/third_party/androidx/committed/libs/androidx_profileinstaller_profileinstaller/README.chromium +++ b/third_party/androidx/committed/libs/androidx_profileinstaller_profileinstaller/README.chromium
@@ -1,6 +1,6 @@ Name: Profile Installer Short Name: profileinstaller -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/profileinstaller/profileinstaller/1.5.0-SNAPSHOT/profileinstaller-1.5.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/profileinstaller/profileinstaller/1.5.0-SNAPSHOT/profileinstaller-1.5.0-20260317.212834-1.aar Version: 1.5.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_recyclerview_recyclerview/README.chromium b/third_party/androidx/committed/libs/androidx_recyclerview_recyclerview/README.chromium index 6a311aef..acb14058 100644 --- a/third_party/androidx/committed/libs/androidx_recyclerview_recyclerview/README.chromium +++ b/third_party/androidx/committed/libs/androidx_recyclerview_recyclerview/README.chromium
@@ -1,6 +1,6 @@ Name: RecyclerView Short Name: recyclerview -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/recyclerview/recyclerview/1.5.0-SNAPSHOT/recyclerview-1.5.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/recyclerview/recyclerview/1.5.0-SNAPSHOT/recyclerview-1.5.0-20260317.212834-1.aar Version: 1.5.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_resourceinspection_resourceinspection_annotation/README.chromium b/third_party/androidx/committed/libs/androidx_resourceinspection_resourceinspection_annotation/README.chromium index eb40ea9..1e28028 100644 --- a/third_party/androidx/committed/libs/androidx_resourceinspection_resourceinspection_annotation/README.chromium +++ b/third_party/androidx/committed/libs/androidx_resourceinspection_resourceinspection_annotation/README.chromium
@@ -1,6 +1,6 @@ Name: Resource Inspection - Annotations Short Name: resourceinspection-annotation -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/resourceinspection/resourceinspection-annotation/1.1.0-SNAPSHOT/resourceinspection-annotation-1.1.0-20260317.131640-1.jar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/resourceinspection/resourceinspection-annotation/1.1.0-SNAPSHOT/resourceinspection-annotation-1.1.0-20260317.212834-1.jar Version: 1.1.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_savedstate_savedstate_android/README.chromium b/third_party/androidx/committed/libs/androidx_savedstate_savedstate_android/README.chromium index e4fc0e0..f5ed8f1c 100644 --- a/third_party/androidx/committed/libs/androidx_savedstate_savedstate_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_savedstate_savedstate_android/README.chromium
@@ -1,6 +1,6 @@ Name: Saved State Short Name: savedstate-android -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/savedstate/savedstate-android/1.5.0-SNAPSHOT/savedstate-android-1.5.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/savedstate/savedstate-android/1.5.0-SNAPSHOT/savedstate-android-1.5.0-20260317.212834-1.aar Version: 1.5.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_savedstate_savedstate_compose_android/README.chromium b/third_party/androidx/committed/libs/androidx_savedstate_savedstate_compose_android/README.chromium index 92f2bb9..df6772e 100644 --- a/third_party/androidx/committed/libs/androidx_savedstate_savedstate_compose_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_savedstate_savedstate_compose_android/README.chromium
@@ -1,6 +1,6 @@ Name: Saved State Compose Short Name: savedstate-compose-android -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/savedstate/savedstate-compose-android/1.5.0-SNAPSHOT/savedstate-compose-android-1.5.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/savedstate/savedstate-compose-android/1.5.0-SNAPSHOT/savedstate-compose-android-1.5.0-20260317.212834-1.aar Version: 1.5.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_savedstate_savedstate_ktx/README.chromium b/third_party/androidx/committed/libs/androidx_savedstate_savedstate_ktx/README.chromium index bbd50e89..0e7e192 100644 --- a/third_party/androidx/committed/libs/androidx_savedstate_savedstate_ktx/README.chromium +++ b/third_party/androidx/committed/libs/androidx_savedstate_savedstate_ktx/README.chromium
@@ -1,6 +1,6 @@ Name: SavedState Kotlin Extensions Short Name: savedstate-ktx -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/savedstate/savedstate-ktx/1.5.0-SNAPSHOT/savedstate-ktx-1.5.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/savedstate/savedstate-ktx/1.5.0-SNAPSHOT/savedstate-ktx-1.5.0-20260317.212834-1.aar Version: 1.5.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_slidingpanelayout_slidingpanelayout/README.chromium b/third_party/androidx/committed/libs/androidx_slidingpanelayout_slidingpanelayout/README.chromium index 40f742153..dce4173e 100644 --- a/third_party/androidx/committed/libs/androidx_slidingpanelayout_slidingpanelayout/README.chromium +++ b/third_party/androidx/committed/libs/androidx_slidingpanelayout_slidingpanelayout/README.chromium
@@ -1,6 +1,6 @@ Name: Sliding Pane Layout Short Name: slidingpanelayout -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/slidingpanelayout/slidingpanelayout/1.3.0-SNAPSHOT/slidingpanelayout-1.3.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/slidingpanelayout/slidingpanelayout/1.3.0-SNAPSHOT/slidingpanelayout-1.3.0-20260317.212834-1.aar Version: 1.3.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_sqlite_sqlite_android/README.chromium b/third_party/androidx/committed/libs/androidx_sqlite_sqlite_android/README.chromium index e5a0453..9018678 100644 --- a/third_party/androidx/committed/libs/androidx_sqlite_sqlite_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_sqlite_sqlite_android/README.chromium
@@ -1,6 +1,6 @@ Name: SQLite Short Name: sqlite-android -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/sqlite/sqlite-android/2.7.0-SNAPSHOT/sqlite-android-2.7.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/sqlite/sqlite-android/2.7.0-SNAPSHOT/sqlite-android-2.7.0-20260317.212834-1.aar Version: 2.7.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_sqlite_sqlite_framework_android/README.chromium b/third_party/androidx/committed/libs/androidx_sqlite_sqlite_framework_android/README.chromium index 0df9f18..a808b42c 100644 --- a/third_party/androidx/committed/libs/androidx_sqlite_sqlite_framework_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_sqlite_sqlite_framework_android/README.chromium
@@ -1,6 +1,6 @@ Name: SQLite Framework Integration Short Name: sqlite-framework-android -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/sqlite/sqlite-framework-android/2.7.0-SNAPSHOT/sqlite-framework-android-2.7.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/sqlite/sqlite-framework-android/2.7.0-SNAPSHOT/sqlite-framework-android-2.7.0-20260317.212834-1.aar Version: 2.7.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_test_uiautomator_uiautomator/README.chromium b/third_party/androidx/committed/libs/androidx_test_uiautomator_uiautomator/README.chromium index 924d9c9..1798c2b 100644 --- a/third_party/androidx/committed/libs/androidx_test_uiautomator_uiautomator/README.chromium +++ b/third_party/androidx/committed/libs/androidx_test_uiautomator_uiautomator/README.chromium
@@ -1,6 +1,6 @@ Name: UIAutomator Short Name: uiautomator -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/test/uiautomator/uiautomator/2.4.0-SNAPSHOT/uiautomator-2.4.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/test/uiautomator/uiautomator/2.4.0-SNAPSHOT/uiautomator-2.4.0-20260317.212834-1.aar Version: 2.4.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_test_uiautomator_uiautomator_shell_android/README.chromium b/third_party/androidx/committed/libs/androidx_test_uiautomator_uiautomator_shell_android/README.chromium index b424ce6..34150741 100644 --- a/third_party/androidx/committed/libs/androidx_test_uiautomator_uiautomator_shell_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_test_uiautomator_uiautomator_shell_android/README.chromium
@@ -1,6 +1,6 @@ Name: Shell Short Name: uiautomator-shell-android -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/test/uiautomator/uiautomator-shell-android/2.4.0-SNAPSHOT/uiautomator-shell-android-2.4.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/test/uiautomator/uiautomator-shell-android/2.4.0-SNAPSHOT/uiautomator-shell-android-2.4.0-20260317.212834-1.aar Version: 2.4.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_tracing_tracing_android/README.chromium b/third_party/androidx/committed/libs/androidx_tracing_tracing_android/README.chromium index da54777d..27c7000 100644 --- a/third_party/androidx/committed/libs/androidx_tracing_tracing_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_tracing_tracing_android/README.chromium
@@ -1,6 +1,6 @@ Name: Tracing Short Name: tracing-android -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/tracing/tracing-android/2.0.0-SNAPSHOT/tracing-android-2.0.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/tracing/tracing-android/2.0.0-SNAPSHOT/tracing-android-2.0.0-20260317.212834-1.aar Version: 2.0.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_tracing_tracing_ktx/README.chromium b/third_party/androidx/committed/libs/androidx_tracing_tracing_ktx/README.chromium index 6c66de7..8a4a795 100644 --- a/third_party/androidx/committed/libs/androidx_tracing_tracing_ktx/README.chromium +++ b/third_party/androidx/committed/libs/androidx_tracing_tracing_ktx/README.chromium
@@ -1,6 +1,6 @@ Name: Tracing Kotlin Extensions Short Name: tracing-ktx -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/tracing/tracing-ktx/2.0.0-SNAPSHOT/tracing-ktx-2.0.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/tracing/tracing-ktx/2.0.0-SNAPSHOT/tracing-ktx-2.0.0-20260317.212834-1.aar Version: 2.0.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_viewpager2_viewpager2/README.chromium b/third_party/androidx/committed/libs/androidx_viewpager2_viewpager2/README.chromium index 0d4e9d96..7f03ac7 100644 --- a/third_party/androidx/committed/libs/androidx_viewpager2_viewpager2/README.chromium +++ b/third_party/androidx/committed/libs/androidx_viewpager2_viewpager2/README.chromium
@@ -1,6 +1,6 @@ Name: ViewPager2 Short Name: viewpager2 -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/viewpager2/viewpager2/1.2.0-SNAPSHOT/viewpager2-1.2.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/viewpager2/viewpager2/1.2.0-SNAPSHOT/viewpager2-1.2.0-20260317.212834-1.aar Version: 1.2.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_webkit_webkit/README.chromium b/third_party/androidx/committed/libs/androidx_webkit_webkit/README.chromium index d5c9e71..50bba07 100644 --- a/third_party/androidx/committed/libs/androidx_webkit_webkit/README.chromium +++ b/third_party/androidx/committed/libs/androidx_webkit_webkit/README.chromium
@@ -1,6 +1,6 @@ Name: Webkit Short Name: webkit -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/webkit/webkit/1.16.0-SNAPSHOT/webkit-1.16.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/webkit/webkit/1.16.0-SNAPSHOT/webkit-1.16.0-20260317.212834-1.aar Version: 1.16.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_window_sidecar_sidecar/README.chromium b/third_party/androidx/committed/libs/androidx_window_sidecar_sidecar/README.chromium index 224bf41..0099754 100644 --- a/third_party/androidx/committed/libs/androidx_window_sidecar_sidecar/README.chromium +++ b/third_party/androidx/committed/libs/androidx_window_sidecar_sidecar/README.chromium
@@ -1,6 +1,6 @@ Name: WindowManager Sidecar Short Name: sidecar -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/window/sidecar/sidecar/1.0.0-SNAPSHOT/sidecar-1.0.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/window/sidecar/sidecar/1.0.0-SNAPSHOT/sidecar-1.0.0-20260317.212834-1.aar Version: 1.0.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_window_window/README.chromium b/third_party/androidx/committed/libs/androidx_window_window/README.chromium index c9587b9..6b045dcf 100644 --- a/third_party/androidx/committed/libs/androidx_window_window/README.chromium +++ b/third_party/androidx/committed/libs/androidx_window_window/README.chromium
@@ -1,6 +1,6 @@ Name: WindowManager Short Name: window -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/window/window/1.6.0-SNAPSHOT/window-1.6.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/window/window/1.6.0-SNAPSHOT/window-1.6.0-20260317.212834-1.aar Version: 1.6.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_window_window_core_android/README.chromium b/third_party/androidx/committed/libs/androidx_window_window_core_android/README.chromium index c7bcaa7..f4a6b5b 100644 --- a/third_party/androidx/committed/libs/androidx_window_window_core_android/README.chromium +++ b/third_party/androidx/committed/libs/androidx_window_window_core_android/README.chromium
@@ -1,6 +1,6 @@ Name: WindowManager Core Short Name: window-core-android -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/window/window-core-android/1.6.0-SNAPSHOT/window-core-android-1.6.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/window/window-core-android/1.6.0-SNAPSHOT/window-core-android-1.6.0-20260317.212834-1.aar Version: 1.6.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_work_work_multiprocess/README.chromium b/third_party/androidx/committed/libs/androidx_work_work_multiprocess/README.chromium index 7ab0935f..5a9894d 100644 --- a/third_party/androidx/committed/libs/androidx_work_work_multiprocess/README.chromium +++ b/third_party/androidx/committed/libs/androidx_work_work_multiprocess/README.chromium
@@ -1,6 +1,6 @@ Name: WorkManager Multiprocess Short Name: work-multiprocess -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/work/work-multiprocess/2.12.0-SNAPSHOT/work-multiprocess-2.12.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/work/work-multiprocess/2.12.0-SNAPSHOT/work-multiprocess-2.12.0-20260317.212834-1.aar Version: 2.12.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_work_work_runtime/README.chromium b/third_party/androidx/committed/libs/androidx_work_work_runtime/README.chromium index f6a3fd3..ebd4916 100644 --- a/third_party/androidx/committed/libs/androidx_work_work_runtime/README.chromium +++ b/third_party/androidx/committed/libs/androidx_work_work_runtime/README.chromium
@@ -1,6 +1,6 @@ Name: WorkManager Runtime Short Name: work-runtime -URL: https://androidx.dev/snapshots/builds/15039720/artifacts/repository/androidx/work/work-runtime/2.12.0-SNAPSHOT/work-runtime-2.12.0-20260317.131640-1.aar +URL: https://androidx.dev/snapshots/builds/15042599/artifacts/repository/androidx/work/work-runtime/2.12.0-SNAPSHOT/work-runtime-2.12.0-20260317.212834-1.aar Version: 2.12.0-SNAPSHOT Update Mechanism: Autoroll License: Apache-2.0
diff --git a/third_party/angle b/third_party/angle index 9fd0c25..f7571cf 160000 --- a/third_party/angle +++ b/third_party/angle
@@ -1 +1 @@ -Subproject commit 9fd0c2508166fb74bcedbd128d502028c712575d +Subproject commit f7571cf4c526b7a9cd0c88424ed6244fac1b55ac
diff --git a/third_party/blink/common/loader/throttling_url_loader.cc b/third_party/blink/common/loader/throttling_url_loader.cc index 8ba759a2..c00d392 100644 --- a/third_party/blink/common/loader/throttling_url_loader.cc +++ b/third_party/blink/common/loader/throttling_url_loader.cc
@@ -281,15 +281,13 @@ const net::NetworkTrafficAnnotationTag& traffic_annotation, scoped_refptr<base::SequencedTaskRunner> task_runner, std::optional<std::vector<std::string>> cors_exempt_header_list, - ClientReceiverDelegate* client_receiver_delegate, - const std::vector<int>* initiator_origin_trial_features) { + ClientReceiverDelegate* client_receiver_delegate) { DCHECK(url_request); std::unique_ptr<ThrottlingURLLoader> loader = CreateLoader(std::move(throttles), client, traffic_annotation, client_receiver_delegate); loader->Start(std::move(factory), request_id, options, url_request, - std::move(task_runner), std::move(cors_exempt_header_list), - initiator_origin_trial_features); + std::move(task_runner), std::move(cors_exempt_header_list)); return loader; } @@ -420,8 +418,7 @@ uint32_t options, network::ResourceRequest* url_request, scoped_refptr<base::SequencedTaskRunner> task_runner, - std::optional<std::vector<std::string>> cors_exempt_header_list, - const std::vector<int>* initiator_origin_trial_features) { + std::optional<std::vector<std::string>> cors_exempt_header_list) { TRACE_EVENT("loading", "ThrottlingURLLoader::Start", perfetto::Flow::FromPointer(this), "request_id", request_id); DCHECK_EQ(DEFERRED_NONE, deferred_stage_);
diff --git a/third_party/blink/public/common/loader/throttling_url_loader.h b/third_party/blink/public/common/loader/throttling_url_loader.h index f6981e4..310ccd5b4 100644 --- a/third_party/blink/public/common/loader/throttling_url_loader.h +++ b/third_party/blink/public/common/loader/throttling_url_loader.h
@@ -123,8 +123,7 @@ scoped_refptr<base::SequencedTaskRunner> task_runner, std::optional<std::vector<std::string>> cors_exempt_header_list = std::nullopt, - ClientReceiverDelegate* client_receiver_delegate = nullptr, - const std::vector<int>* initiator_origin_trial_features = nullptr); + ClientReceiverDelegate* client_receiver_delegate = nullptr); // See the comments at `CreateLoaderAndStart()` above for parameters. static std::unique_ptr<ThrottlingURLLoader> CreateLoader( @@ -137,8 +136,7 @@ uint32_t options, network::ResourceRequest* url_request, scoped_refptr<base::SequencedTaskRunner> task_runner, - std::optional<std::vector<std::string>> cors_exempt_header_list, - const std::vector<int>* initiator_origin_trial_features); + std::optional<std::vector<std::string>> cors_exempt_header_list); ThrottlingURLLoader(const ThrottlingURLLoader&) = delete; ThrottlingURLLoader& operator=(const ThrottlingURLLoader&) = delete;
diff --git a/third_party/blink/public/devtools_protocol/domains/Audits.pdl b/third_party/blink/public/devtools_protocol/domains/Audits.pdl index 0d673d57..536399a 100644 --- a/third_party/blink/public/devtools_protocol/domains/Audits.pdl +++ b/third_party/blink/public/devtools_protocol/domains/Audits.pdl
@@ -688,30 +688,6 @@ # Used for messages about activation disabled reason optional string disableReason - # Metadata about the ad script that was on the stack that caused the current - # script in the `AdAncestry` to be considered ad related. - type AdScriptIdentifier extends object - properties - # The script's v8 identifier. - Runtime.ScriptId scriptId - # v8's debugging id for the v8::Context. - Runtime.UniqueDebuggerId debuggerId - # The script's url (or generated name based on id if inline script). - string name - - # Providence about how an ad script was determined to be such. It is an ad - # because its url matched a filterlist rule, or because some other ad script - # was on the stack when this script was loaded. - type AdAncestry extends object - properties - # The ad-script in the stack when the offending script was loaded. This is - # recursive down to the root script that was tagged due to the filterlist - # rule. - array of AdScriptIdentifier adAncestryChain - # The filterlist rule that caused the root (last) script in - # `adAncestry` to be ad-tagged. - optional string rootScriptFilterlistRule - # The issue warns about blocked calls to privacy sensitive APIs via the # Selective Permissions Intervention. type SelectivePermissionsInterventionIssueDetails extends object @@ -719,7 +695,7 @@ # Which API was intervened on. string apiName # Why the ad script using the API is considered an ad. - AdAncestry adAncestry + Network.AdAncestry adAncestry # The stack trace at the time of the intervention. optional Runtime.StackTrace stackTrace
diff --git a/third_party/blink/public/devtools_protocol/domains/Network.pdl b/third_party/blink/public/devtools_protocol/domains/Network.pdl index de36ac7..504edfe 100644 --- a/third_party/blink/public/devtools_protocol/domains/Network.pdl +++ b/third_party/blink/public/devtools_protocol/domains/Network.pdl
@@ -1799,6 +1799,32 @@ IPAddressSpace initiatorIPAddressSpace LocalNetworkAccessRequestPolicy localNetworkAccessRequestPolicy + # Identifies the script on the stack that caused a resource or element to be + # labeled as an ad. For resources, this indicates the context that triggered + # the fetch. For elements, this indicates the context that caused the element + # to be appended to the DOM. + experimental type AdScriptIdentifier extends object + properties + # The script's V8 identifier. + Runtime.ScriptId scriptId + # V8's debugging ID for the v8::Context. + Runtime.UniqueDebuggerId debuggerId + # The script's url (or generated name based on id if inline script). + string name + + # Encapsulates the script ancestry and the root script filter list rule that + # caused the resource or element to be labeled as an ad. + experimental type AdAncestry extends object + properties + # A chain of `AdScriptIdentifier`s representing the ancestry of an ad + # script that led to the creation of a resource or element. The chain is + # ordered from the script itself (lowest level) up to its root ancestor + # that was flagged by a filter list. + array of AdScriptIdentifier ancestryChain + # The filter list rule that caused the root (last) script in + # `ancestryChain` to be tagged as an ad. + optional string rootScriptFilterlistRule + # Fired when additional information about a requestWillBeSent event is available from the # network stack. Not every requestWillBeSent event will have an additional # requestWillBeSentExtraInfo fired for it, and there is no guarantee whether requestWillBeSent
diff --git a/third_party/blink/public/devtools_protocol/domains/Page.pdl b/third_party/blink/public/devtools_protocol/domains/Page.pdl index 76d6ed4..12734a90 100644 --- a/third_party/blink/public/devtools_protocol/domains/Page.pdl +++ b/third_party/blink/public/devtools_protocol/domains/Page.pdl
@@ -36,31 +36,6 @@ AdFrameType adFrameType optional array of AdFrameExplanation explanations - # Identifies the script which caused a script or frame to be labelled as an - # ad. - experimental type AdScriptId extends object - properties - # Script Id of the script which caused a script or frame to be labelled as - # an ad. - Runtime.ScriptId scriptId - # Id of scriptId's debugger. - Runtime.UniqueDebuggerId debuggerId - - # Encapsulates the script ancestry and the root script filterlist rule that - # caused the frame to be labelled as an ad. Only created when `ancestryChain` - # is not empty. - experimental type AdScriptAncestry extends object - properties - # A chain of `AdScriptId`s representing the ancestry of an ad script that - # led to the creation of a frame. The chain is ordered from the script - # itself (lower level) up to its root ancestor that was flagged by - # filterlist. - array of AdScriptId ancestryChain - # The filterlist rule that caused the root (last) script in - # `ancestryChain` to be ad-tagged. Only populated if the rule is - # available. - optional string rootScriptFilterlistRule - # Indicates whether the frame is a secure context and why it is the case. experimental type SecureContextType extends string enum @@ -843,7 +818,7 @@ # chain is ordered from the most immediate script (in the frame creation # stack) to more distant ancestors (that created the immediately preceding # script). Only sent if frame is labelled as an ad and ids are available. - optional AdScriptAncestry adScriptAncestry + optional Network.AdAncestry adScriptAncestry # Returns present frame tree structure. command getFrameTree
diff --git a/third_party/blink/renderer/core/css/rule_set.h b/third_party/blink/renderer/core/css/rule_set.h index 99a0b00..22e6ce6 100644 --- a/third_party/blink/renderer/core/css/rule_set.h +++ b/third_party/blink/renderer/core/css/rule_set.h
@@ -24,6 +24,7 @@ #define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_RULE_SET_H_ #include "base/compiler_specific.h" +#include "base/containers/span.h" #include "base/gtest_prod_util.h" #include "base/memory/stack_allocated.h" #include "base/substring_set_matcher/substring_set_matcher.h" @@ -119,7 +120,8 @@ // Member functions related to the descendant Bloom filter. const base::span<const uint16_t> DescendantSelectorIdentifierHashes( const Vector<uint16_t>& backing) const { - return UNSAFE_BUFFERS({backing.data() + bloom_hash_pos_, bloom_hash_size_}); + return UNSAFE_BUFFERS( + {base::unchecked, backing.data() + bloom_hash_pos_, bloom_hash_size_}); } void ComputeBloomFilterHashes(const StyleScope* style_scope, Vector<uint16_t>& backing); @@ -248,8 +250,9 @@ if (bucket == nullptr) { return {}; } else { - return UNSAFE_BUFFERS( - {backing.begin() + bucket->value.start_index, bucket->value.length}); + return UNSAFE_BUFFERS({base::unchecked, + backing.begin() + bucket->value.start_index, + bucket->value.length}); } } bool IsEmpty() const { return backing.empty(); } @@ -285,19 +288,22 @@ private: base::span<RuleData> GetRulesFromExtent(Extent extent) { return UNSAFE_BUFFERS( - {backing.begin() + extent.start_index, extent.length}); + {base::unchecked, backing.begin() + extent.start_index, extent.length}); } base::span<const RuleData> GetRulesFromExtent(Extent extent) const { return UNSAFE_BUFFERS( - {backing.begin() + extent.start_index, extent.length}); + + {base::unchecked, backing.begin() + extent.start_index, extent.length}); } base::span<unsigned> GetBucketNumberFromExtent(Extent extent) { - return UNSAFE_BUFFERS( - {bucket_number_.begin() + extent.start_index, extent.length}); + return UNSAFE_BUFFERS({base::unchecked, + bucket_number_.begin() + extent.start_index, + extent.length}); } base::span<const unsigned> GetBucketNumberFromExtent(Extent extent) const { - return UNSAFE_BUFFERS( - {bucket_number_.begin() + extent.start_index, extent.length}); + return UNSAFE_BUFFERS({base::unchecked, + bucket_number_.begin() + extent.start_index, + extent.length}); } RobinHoodMap<AtomicString, Extent> buckets;
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc index 905cb11c..f3d06aa 100644 --- a/third_party/blink/renderer/core/dom/document.cc +++ b/third_party/blink/renderer/core/dom/document.cc
@@ -94,6 +94,7 @@ #include "third_party/blink/renderer/bindings/core/v8/v8_focus_options.h" #include "third_party/blink/renderer/bindings/core/v8/v8_import_node_options.h" #include "third_party/blink/renderer/bindings/core/v8/v8_observable_array_css_style_sheet.h" +#include "third_party/blink/renderer/bindings/core/v8/v8_overscroll_event_init.h" #include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h" #include "third_party/blink/renderer/bindings/core/v8/v8_union_elementcreationoptions_string.h" #include "third_party/blink/renderer/bindings/core/v8/v8_union_htmlscriptelement_svgscriptelement.h" @@ -310,6 +311,7 @@ #include "third_party/blink/renderer/core/mathml_names.h" #include "third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker.h" #include "third_party/blink/renderer/core/origin_trials/origin_trial_context.h" +#include "third_party/blink/renderer/core/overscroll/overscroll_event.h" #include "third_party/blink/renderer/core/page/chrome_client.h" #include "third_party/blink/renderer/core/page/event_with_hit_test_results.h" #include "third_party/blink/renderer/core/page/focus_controller.h" @@ -6577,6 +6579,22 @@ scrollsnapchanging_event); } +void Document::EnqueueOverscrollEvent(const AtomicString& type, + Node* target, + Element* overscroll_target, + bool overscrolling) { + OverscrollEventInit* init = OverscrollEventInit::Create(); + init->setOverscrollTarget(overscroll_target); + // We bubble if we're on the document. + init->setBubbles(target->IsDocumentNode()); + if (type == event_type_names::kOverscrollchanging) { + init->setOverscrolling(overscrolling); + } + Event* overscroll_event = OverscrollEvent::Create(type, init); + overscroll_event->SetTarget(target); + scripted_animation_controller_->EnqueuePerFrameEvent(overscroll_event); +} + void Document::EnqueueMoveEvent() { CHECK( RuntimeEnabledFeatures::DesktopPWAsAdditionalWindowingControlsEnabled());
diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h index 8a0eaf0..251475d 100644 --- a/third_party/blink/renderer/core/dom/document.h +++ b/third_party/blink/renderer/core/dom/document.h
@@ -1611,6 +1611,10 @@ void EnqueueScrollSnapChangingEvent(Node* target, Member<Node>& block_target, Member<Node>& inline_target); + void EnqueueOverscrollEvent(const AtomicString& type, + Node* target, + Element* overscroll_target, + bool overscrolling = false); void DispatchMediaQueryListEvents();
diff --git a/third_party/blink/renderer/core/dom/events/event_target.h b/third_party/blink/renderer/core/dom/events/event_target.h index a73bcb1..d957fde 100644 --- a/third_party/blink/renderer/core/dom/events/event_target.h +++ b/third_party/blink/renderer/core/dom/events/event_target.h
@@ -287,7 +287,10 @@ DEFINE_ATTRIBUTE_EVENT_LISTENER(mouseover, kMouseover) DEFINE_ATTRIBUTE_EVENT_LISTENER(mouseup, kMouseup) DEFINE_ATTRIBUTE_EVENT_LISTENER(mousewheel, kMousewheel) - DEFINE_ATTRIBUTE_EVENT_LISTENER(overscroll, kOverscroll) + DEFINE_ATTRIBUTE_EVENT_LISTENER(overscrollcancel, kOverscrollcancel) + DEFINE_ATTRIBUTE_EVENT_LISTENER(overscrollchanging, kOverscrollchanging) + DEFINE_ATTRIBUTE_EVENT_LISTENER(overscrollend, kOverscrollend) + DEFINE_ATTRIBUTE_EVENT_LISTENER(overscrollstart, kOverscrollstart) DEFINE_ATTRIBUTE_EVENT_LISTENER(pause, kPause) DEFINE_ATTRIBUTE_EVENT_LISTENER(play, kPlay) DEFINE_ATTRIBUTE_EVENT_LISTENER(playing, kPlaying)
diff --git a/third_party/blink/renderer/core/dom/global_event_handlers.idl b/third_party/blink/renderer/core/dom/global_event_handlers.idl index bf47ec92..99cba0fa 100644 --- a/third_party/blink/renderer/core/dom/global_event_handlers.idl +++ b/third_party/blink/renderer/core/dom/global_event_handlers.idl
@@ -80,7 +80,10 @@ attribute EventHandler onmouseover; attribute EventHandler onmouseup; attribute EventHandler onmousewheel; - [RuntimeEnabled=OverscrollGestures] attribute EventHandler onoverscroll; + [RuntimeEnabled=OverscrollGestures] attribute EventHandler onoverscrollcancel; + [RuntimeEnabled=OverscrollGestures] attribute EventHandler onoverscrollchanging; + [RuntimeEnabled=OverscrollGestures] attribute EventHandler onoverscrollend; + [RuntimeEnabled=OverscrollGestures] attribute EventHandler onoverscrollstart; attribute EventHandler onpause; attribute EventHandler onplay; attribute EventHandler onplaying;
diff --git a/third_party/blink/renderer/core/events/event_type_names.json5 b/third_party/blink/renderer/core/events/event_type_names.json5 index 75b56f1..ce1a9c35 100644 --- a/third_party/blink/renderer/core/events/event_type_names.json5 +++ b/third_party/blink/renderer/core/events/event_type_names.json5
@@ -219,7 +219,10 @@ "online", "open", "orientationchange", - "overscroll", + "overscrollcancel", + "overscrollchanging", + "overscrollend", + "overscrollstart", "pagehide", "pagereveal", "pageshow",
diff --git a/third_party/blink/renderer/core/frame/build.gni b/third_party/blink/renderer/core/frame/build.gni index ea488ed7..9da3468 100644 --- a/third_party/blink/renderer/core/frame/build.gni +++ b/third_party/blink/renderer/core/frame/build.gni
@@ -271,6 +271,7 @@ "local_dom_window_test.cc", "local_frame_back_forward_cache_test.cc", "local_frame_client_impl_test.cc", + "local_frame_full_content_spell_check_test.cc", "local_frame_test.cc", "local_frame_ukm_aggregator_test.cc", "local_frame_view_test.cc",
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc index 79e918f..8d1aa44 100644 --- a/third_party/blink/renderer/core/frame/local_frame.cc +++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -127,6 +127,7 @@ #include "third_party/blink/renderer/core/editing/serializers/create_markup_options.h" #include "third_party/blink/renderer/core/editing/serializers/serialization.h" #include "third_party/blink/renderer/core/editing/spellcheck/spell_check_requester.h" +#include "third_party/blink/renderer/core/editing/spellcheck/spell_check_requester_helper.h" #include "third_party/blink/renderer/core/editing/spellcheck/spell_checker.h" #include "third_party/blink/renderer/core/editing/suggestion/text_suggestion_controller.h" #include "third_party/blink/renderer/core/editing/surrounding_text.h" @@ -4270,8 +4271,13 @@ const EphemeralRange range(Position(container_node, 0), Position::LastPositionInNode(*container_node)); + // Some IMEs' functionalities (e.g. Gboard's Add to Personal Dictionary) rely + // on PerformFullContentSpellCheck to perform a full-content spell check. In + // such case, the spell check request cache could have become stale by the + // time this method is called. Therefore, we want to force a fresh request to + // spell check service. GetSpellChecker().GetSpellCheckRequester().RequestCheckingFor( - range, /*request_num=*/0, /*should_force_refresh=*/false); + range, /*request_num=*/0, /*should_force_refresh=*/true); } #endif // BUILDFLAG(IS_ANDROID)
diff --git a/third_party/blink/renderer/core/frame/local_frame_full_content_spell_check_test.cc b/third_party/blink/renderer/core/frame/local_frame_full_content_spell_check_test.cc new file mode 100644 index 0000000..9544622 --- /dev/null +++ b/third_party/blink/renderer/core/frame/local_frame_full_content_spell_check_test.cc
@@ -0,0 +1,129 @@ +// Copyright 2026 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 "build/build_config.h" +#include "third_party/blink/public/common/features.h" +#include "third_party/blink/public/web/web_text_check_client.h" +#include "third_party/blink/renderer/core/editing/frame_selection.h" +#include "third_party/blink/renderer/core/editing/selection_template.h" +#include "third_party/blink/renderer/core/editing/spellcheck/spell_check_test_base.h" +#include "third_party/blink/renderer/core/frame/local_frame.h" +#include "third_party/blink/renderer/core/loader/empty_clients.h" + +#if BUILDFLAG(IS_ANDROID) + +namespace blink { + +class FullContentSpellCheckMockClient : public WebTextCheckClient { + public: + void RequestCheckingOfText( + const WebString& text, + const std::vector<WebSpellingMarker>& markers, + WebTextCheckClient::ShouldForceRefreshTextCheckService force_refresh, + std::unique_ptr<WebTextCheckingCompletion> completion) override { + last_text_ = text; + last_force_refresh_ = force_refresh; + call_count_++; + } + + bool IsSpellCheckingEnabled() const override { return true; } + + int call_count_ = 0; + WebString last_text_; + WebTextCheckClient::ShouldForceRefreshTextCheckService last_force_refresh_ = + WebTextCheckClient::ShouldForceRefreshTextCheckService::kNo; +}; + +class LocalFrameFullContentSpellCheckTest : public SpellCheckTestBase { + protected: + void SetUp() override { + SpellCheckTestBase::SetUp(); + feature_list_.InitAndEnableFeature( + blink::features::kAndroidSpellcheckFullApiBlink); + + mock_client_ = std::make_unique<FullContentSpellCheckMockClient>(); + EmptyLocalFrameClient* frame_client = + static_cast<EmptyLocalFrameClient*>(GetFrame().Client()); + frame_client->SetTextCheckerClientForTesting(mock_client_.get()); + } + + void TearDown() override { + EmptyLocalFrameClient* frame_client = + static_cast<EmptyLocalFrameClient*>(GetFrame().Client()); + frame_client->SetTextCheckerClientForTesting(nullptr); + SpellCheckTestBase::TearDown(); + } + + FullContentSpellCheckMockClient& MockClient() { return *mock_client_; } + + private: + base::test::ScopedFeatureList feature_list_; + std::unique_ptr<FullContentSpellCheckMockClient> mock_client_; +}; + +TEST_F(LocalFrameFullContentSpellCheckTest, TriggersFullCheck) { + SetBodyContent("<div contenteditable>Hello world</div>"); + Element* div = QuerySelector("div"); + div->Focus(); + UpdateAllLifecyclePhasesForTest(); + + GetFrame().PerformFullContentSpellCheck(); + + EXPECT_EQ(MockClient().call_count_, 1); + EXPECT_EQ(MockClient().last_text_, "Hello world"); + EXPECT_EQ(MockClient().last_force_refresh_, + WebTextCheckClient::ShouldForceRefreshTextCheckService::kYes); +} + +TEST_F(LocalFrameFullContentSpellCheckTest, NoEditableRoot) { + SetBodyContent("<div>Hello world</div>"); + UpdateAllLifecyclePhasesForTest(); + + GetFrame().PerformFullContentSpellCheck(); + + EXPECT_EQ(MockClient().call_count_, 0); +} + +TEST_F(LocalFrameFullContentSpellCheckTest, + TriggersFullCheckWhenCursorIsMiddleOfWord) { + SetBodyContent("<div contenteditable>Hello world.</div>"); + Element* div = QuerySelector("div"); + div->Focus(); + + // Simulate the cursor at the word "world". + Node* text = div->firstChild(); + GetFrame().Selection().SetSelection(SelectionInDOMTree::Builder() + .Collapse(Position(text, 8)) + .Extend(Position(text, 8)) + .Build(), + SetSelectionOptions()); + UpdateAllLifecyclePhasesForTest(); + + GetFrame().PerformFullContentSpellCheck(); + + EXPECT_EQ(MockClient().call_count_, 1); + EXPECT_EQ(MockClient().last_text_, "Hello world."); + EXPECT_EQ(MockClient().last_force_refresh_, + WebTextCheckClient::ShouldForceRefreshTextCheckService::kYes); +} + +TEST_F(LocalFrameFullContentSpellCheckTest, + TriggersFullCheckWithNestedElements) { + SetBodyContent("<div contenteditable><i>Hello</i> world.</div>"); + Element* div = QuerySelector("div"); + div->Focus(); + UpdateAllLifecyclePhasesForTest(); + + GetFrame().PerformFullContentSpellCheck(); + + EXPECT_EQ(MockClient().call_count_, 1); + EXPECT_EQ(MockClient().last_text_, "Hello world."); + EXPECT_EQ(MockClient().last_force_refresh_, + WebTextCheckClient::ShouldForceRefreshTextCheckService::kYes); +} + +} // namespace blink + +#endif // BUILDFLAG(IS_ANDROID)
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.cc b/third_party/blink/renderer/core/frame/local_frame_view.cc index 3e8c8cc2..f11dd3cb 100644 --- a/third_party/blink/renderer/core/frame/local_frame_view.cc +++ b/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -756,9 +756,17 @@ ++add_result.stored_value->value; } } - for (auto& root : layout_subtree_root_list_.Ordered()) { - bool should_rebuild_fragments = false; + HeapVector<LayoutObjectWithDepth> ordered_roots = + layout_subtree_root_list_.Ordered(); + for (LayoutObjectWithDepth& root : ordered_roots) { LayoutObject& root_layout_object = *root; + if (!layout_subtree_root_list_.Contains(root_layout_object)) { + // A previous iteration removed the entry from the list. + // This can happen when interleaved style recalc sets the element + // associated the layout subtree root to display:none. + continue; + } + bool should_rebuild_fragments = false; LayoutBox* container_box = root->ContainingNGBox(); if (container_box) { auto it = fragment_tree_spines.find(container_box);
diff --git a/third_party/blink/renderer/core/html/canvas/DEPS b/third_party/blink/renderer/core/html/canvas/DEPS index b916423..7bc2b9cd 100644 --- a/third_party/blink/renderer/core/html/canvas/DEPS +++ b/third_party/blink/renderer/core/html/canvas/DEPS
@@ -1,5 +1,6 @@ include_rules = [ "+base/memory/memory_pressure_listener.h", +"+base/memory_coordinator/memory_coordinator_features.h", "+cc/layers/texture_layer.h", "+cc/layers/texture_layer_client.h", "+components/viz/common/resources/shared_image_format.h",
diff --git a/third_party/blink/renderer/core/html/canvas/unique_font_selector.cc b/third_party/blink/renderer/core/html/canvas/unique_font_selector.cc index 2433b27..110be08d 100644 --- a/third_party/blink/renderer/core/html/canvas/unique_font_selector.cc +++ b/third_party/blink/renderer/core/html/canvas/unique_font_selector.cc
@@ -4,6 +4,8 @@ #include "third_party/blink/renderer/core/html/canvas/unique_font_selector.h" +#include "base/feature_list.h" +#include "base/memory_coordinator/memory_coordinator_features.h" #include "third_party/blink/renderer/core/html/canvas/canvas_font_cache.h" #include "third_party/blink/renderer/platform/fonts/font.h" #include "third_party/blink/renderer/platform/fonts/font_selector.h" @@ -67,13 +69,25 @@ void UniqueFontSelector::OnMemoryPressure( base::MemoryPressureLevel memory_pressure_level) { - // Memory pressure has changed, so the max number of fonts may have been - // updated. Evict excess entries to match the new limit. - EvictExcessEntries(); + if (base::FeatureList::IsEnabled(base::kStatefulMemoryPressure)) { + // Memory pressure has changed, so the max number of fonts may have been + // updated. Evict excess entries to match the new limit. + EvictExcessEntries(); + return; + } + + if (memory_pressure_level == base::MEMORY_PRESSURE_LEVEL_CRITICAL) { + font_cache_.clear(); + lru_list_.clear(); + } } unsigned UniqueFontSelector::GetCurrentMaxFonts() const { - return CanvasFontCache::MaxFonts() * GetMemoryLimitRatio(); + if (base::FeatureList::IsEnabled(base::kStatefulMemoryPressure)) { + return CanvasFontCache::MaxFonts() * GetMemoryLimitRatio(); + } + + return CanvasFontCache::MaxFonts(); } void UniqueFontSelector::EvictExcessEntries() {
diff --git a/third_party/blink/renderer/core/html/html_element.cc b/third_party/blink/renderer/core/html/html_element.cc index 64f80d7..de45be8 100644 --- a/third_party/blink/renderer/core/html/html_element.cc +++ b/third_party/blink/renderer/core/html/html_element.cc
@@ -2593,31 +2593,28 @@ const auto& first_data = container_data->at(0); const auto& second_data = container_data->at(1); - ScrollOffset scroll_origin = - gfx::PointF(scrollable_area->ScrollOrigin()).OffsetFromOrigin(); + gfx::PointF scroll_origin(scrollable_area->ScrollOrigin()); - // We do the math in absolute space, since that's the space in which our - // snap targets are defined. - ScrollOffset old_offset = - scrollable_area->GetScrollOffset() + scroll_origin; ScrollOffset new_offset; - if (old_offset == scroll_origin) { - CHECK(previous_snap_targets.x == first_data.element_id || - previous_snap_targets.y == first_data.element_id); - + if (previous_snap_targets.x == first_data.element_id && + previous_snap_targets.y == first_data.element_id) { gfx::RectF target_rect = second_data.rect; PhysicalSize box_size = overscroll_area_object->PhysicalContentBoxSize(); - // We need to find distances in all 4 directions relative to the current - // scroll offset. - float min_x_offset = std::min(target_rect.x() - old_offset.x(), 0.f); - float min_y_offset = std::min(target_rect.y() - old_offset.y(), 0.f); + // We need to find distances in all 4 directions relative to scroll + // origin. Note that we use scroll origin here instead of current offset + // since we could be in the middle of animating an offset. However we know + // that conceptually we should find the furthest area from the position we + // would be in if the scroll settled. That position is the scroll origin. + float min_x_offset = std::min(target_rect.x() - scroll_origin.x(), 0.f); + float min_y_offset = std::min(target_rect.y() - scroll_origin.y(), 0.f); float max_x_offset = std::max( - target_rect.right() - box_size.width.ToFloat() - old_offset.x(), 0.f); + target_rect.right() - box_size.width.ToFloat() - scroll_origin.x(), + 0.f); float max_y_offset = std::max( - target_rect.bottom() - box_size.height.ToFloat() - old_offset.y(), + target_rect.bottom() - box_size.height.ToFloat() - scroll_origin.y(), 0.f); // These are now distances from scroll offset, so we need to pick a @@ -2633,22 +2630,12 @@ new_offset.set_y(-min_y_offset >= max_y_offset ? min_y_offset : max_y_offset); } - // Now new offset has the delta we need to move relative to the old - // offset. We need to convert that into an actual offset (still in - // absolute space though). - new_offset += old_offset; - } else { - CHECK(previous_snap_targets.x != first_data.element_id || - previous_snap_targets.y != first_data.element_id); - new_offset = scroll_origin; } + ScrollOffset old_offset = scrollable_area->GetScrollOffset(); bool x_changed = new_offset.x() != old_offset.x(); bool y_changed = new_offset.y() != old_offset.y(); - // Convert the offset into scroll origin space. - new_offset -= scroll_origin; - std::unique_ptr<cc::SnapSelectionStrategy> strategy = cc::SnapSelectionStrategy::CreateForEndPosition( scrollable_area->ScrollOffsetToPosition(new_offset), x_changed,
diff --git a/third_party/blink/renderer/core/inspector/ad_tagging_utils.cc b/third_party/blink/renderer/core/inspector/ad_tagging_utils.cc new file mode 100644 index 0000000..5ed6a78 --- /dev/null +++ b/third_party/blink/renderer/core/inspector/ad_tagging_utils.cc
@@ -0,0 +1,37 @@ +// Copyright 2026 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/ad_tagging_utils.h" + +#include "third_party/blink/renderer/core/inspector/v8_inspector_string.h" + +namespace blink { + +std::unique_ptr<protocol::Network::AdAncestry> CreateAdAncestryProtocolObject( + const AdTracker::AdScriptAncestry& ad_ancestry) { + auto ancestry_chain = std::make_unique< + protocol::Array<protocol::Network::AdScriptIdentifier>>(); + for (const auto& ad_script : ad_ancestry.ancestry_chain) { + ancestry_chain->emplace_back( + protocol::Network::AdScriptIdentifier::create() + .setScriptId(String::Number(ad_script.id.value())) + .setDebuggerId( + ToCoreString(ad_script.context_id.toString()->string())) + .setName(ad_script.name) + .build()); + } + + auto ad_ancestry_protocol = protocol::Network::AdAncestry::create() + .setAncestryChain(std::move(ancestry_chain)) + .build(); + + if (ad_ancestry.root_script_filterlist_rule.IsValid()) { + ad_ancestry_protocol->setRootScriptFilterlistRule( + String::FromUTF8(ad_ancestry.root_script_filterlist_rule.ToString())); + } + + return ad_ancestry_protocol; +} + +} // namespace blink
diff --git a/third_party/blink/renderer/core/inspector/ad_tagging_utils.h b/third_party/blink/renderer/core/inspector/ad_tagging_utils.h new file mode 100644 index 0000000..296af8b --- /dev/null +++ b/third_party/blink/renderer/core/inspector/ad_tagging_utils.h
@@ -0,0 +1,21 @@ +// Copyright 2026 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_AD_TAGGING_UTILS_H_ +#define THIRD_PARTY_BLINK_RENDERER_CORE_INSPECTOR_AD_TAGGING_UTILS_H_ + +#include <memory> + +#include "third_party/blink/renderer/core/ad_tracker/ad_tracker.h" +#include "third_party/blink/renderer/core/core_export.h" +#include "third_party/blink/renderer/core/inspector/protocol/network.h" + +namespace blink { + +CORE_EXPORT std::unique_ptr<protocol::Network::AdAncestry> +CreateAdAncestryProtocolObject(const AdTracker::AdScriptAncestry& ad_ancestry); + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_CORE_INSPECTOR_AD_TAGGING_UTILS_H_
diff --git a/third_party/blink/renderer/core/inspector/build.gni b/third_party/blink/renderer/core/inspector/build.gni index 5502a508..f373938 100644 --- a/third_party/blink/renderer/core/inspector/build.gni +++ b/third_party/blink/renderer/core/inspector/build.gni
@@ -3,6 +3,8 @@ # found in the LICENSE file. blink_core_sources_inspector = [ + "ad_tagging_utils.cc", + "ad_tagging_utils.h", "agent_registry.h", "console_message.cc", "console_message.h",
diff --git a/third_party/blink/renderer/core/inspector/inspector_audits_issue.cc b/third_party/blink/renderer/core/inspector/inspector_audits_issue.cc index 5e38e8e..05a3c40 100644 --- a/third_party/blink/renderer/core/inspector/inspector_audits_issue.cc +++ b/third_party/blink/renderer/core/inspector/inspector_audits_issue.cc
@@ -17,6 +17,7 @@ #include "third_party/blink/renderer/core/frame/local_dom_window.h" #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/html/forms/html_select_element.h" +#include "third_party/blink/renderer/core/inspector/ad_tagging_utils.h" #include "third_party/blink/renderer/core/inspector/identifiers_factory.h" #include "third_party/blink/renderer/core/inspector/protocol/audits.h" #include "third_party/blink/renderer/core/inspector/protocol/network.h" @@ -1052,31 +1053,10 @@ const String& api_name, const AdTracker::AdScriptAncestry& ad_ancestry, const SourceLocation& source_location) { - auto ancestry_chain = - std::make_unique<protocol::Array<protocol::Audits::AdScriptIdentifier>>(); - for (const auto& ad_script : ad_ancestry.ancestry_chain) { - ancestry_chain->emplace_back( - protocol::Audits::AdScriptIdentifier::create() - .setScriptId(String::Number(ad_script.id.value())) - .setDebuggerId( - ToCoreString(ad_script.context_id.toString()->string())) - .setName(ad_script.name) - .build()); - } - - auto ad_ancestry_protocol = protocol::Audits::AdAncestry::create() - .setAdAncestryChain(std::move(ancestry_chain)) - .build(); - - if (ad_ancestry.root_script_filterlist_rule.IsValid()) { - ad_ancestry_protocol->setRootScriptFilterlistRule( - String::FromUTF8(ad_ancestry.root_script_filterlist_rule.ToString())); - } - auto intervention_details = protocol::Audits::SelectivePermissionsInterventionIssueDetails::create() .setApiName(api_name) - .setAdAncestry(std::move(ad_ancestry_protocol)) + .setAdAncestry(CreateAdAncestryProtocolObject(ad_ancestry)) .build(); if (source_location.HasStackTrace()) {
diff --git a/third_party/blink/renderer/core/inspector/inspector_page_agent.cc b/third_party/blink/renderer/core/inspector/inspector_page_agent.cc index 73a277e..850f202 100644 --- a/third_party/blink/renderer/core/inspector/inspector_page_agent.cc +++ b/third_party/blink/renderer/core/inspector/inspector_page_agent.cc
@@ -64,6 +64,7 @@ #include "third_party/blink/renderer/core/html/html_frame_owner_element.h" #include "third_party/blink/renderer/core/html/parser/text_resource_decoder.h" #include "third_party/blink/renderer/core/html_names.h" +#include "third_party/blink/renderer/core/inspector/ad_tagging_utils.h" #include "third_party/blink/renderer/core/inspector/identifiers_factory.h" #include "third_party/blink/renderer/core/inspector/inspected_frames.h" #include "third_party/blink/renderer/core/inspector/inspector_css_agent.h" @@ -804,35 +805,10 @@ protocol::Response InspectorPageAgent::getAdScriptAncestry( const String& frame_id, - std::unique_ptr<protocol::Page::AdScriptAncestry>* out_ad_script_ancestry) { + std::unique_ptr<protocol::Network::AdAncestry>* out_ad_script_ancestry) { auto it = frame_ad_script_ancestry_.find(frame_id); if (it != frame_ad_script_ancestry_.end()) { - const AdTracker::AdScriptAncestry& ad_script_ancestry = it->value; - CHECK(!ad_script_ancestry.ancestry_chain.empty()); - - std::vector<std::unique_ptr<protocol::Page::AdScriptId>> ancestry_chain; - for (const auto& ad_script_identifier : ad_script_ancestry.ancestry_chain) { - ancestry_chain.push_back( - protocol::Page::AdScriptId::create() - .setScriptId(String::Number(ad_script_identifier.id.value())) - .setDebuggerId(ToCoreString( - ad_script_identifier.context_id.toString()->string())) - .build()); - } - - std::unique_ptr<protocol::Page::AdScriptAncestry> ancestry = - protocol::Page::AdScriptAncestry::create() - .setAncestryChain( - std::make_unique<protocol::Array<protocol::Page::AdScriptId>>( - std::move(ancestry_chain))) - .build(); - - if (ad_script_ancestry.root_script_filterlist_rule.IsValid()) { - ancestry->setRootScriptFilterlistRule( - String(ad_script_ancestry.root_script_filterlist_rule.ToString())); - } - - *out_ad_script_ancestry = std::move(ancestry); + *out_ad_script_ancestry = CreateAdAncestryProtocolObject(it->value); } return protocol::Response::Success();
diff --git a/third_party/blink/renderer/core/inspector/inspector_page_agent.h b/third_party/blink/renderer/core/inspector/inspector_page_agent.h index 3c71cf4..236392d 100644 --- a/third_party/blink/renderer/core/inspector/inspector_page_agent.h +++ b/third_party/blink/renderer/core/inspector/inspector_page_agent.h
@@ -37,6 +37,7 @@ #include "third_party/blink/renderer/core/ad_tracker/ad_tracker.h" #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/inspector/inspector_base_agent.h" +#include "third_party/blink/renderer/core/inspector/protocol/network.h" #include "third_party/blink/renderer/core/inspector/protocol/page.h" #include "third_party/blink/renderer/core/loader/frame_loader_types.h" #include "third_party/blink/renderer/core/page/chrome_client.h" @@ -146,7 +147,7 @@ std::unique_ptr<GetResourceContentCallback>) override; protocol::Response getAdScriptAncestry( const String& frame_id, - std::unique_ptr<protocol::Page::AdScriptAncestry>* out_ad_script_ancestry) + std::unique_ptr<protocol::Network::AdAncestry>* out_ad_script_ancestry) override; void searchInResource(const String& frame_id, const String& url,
diff --git a/third_party/blink/renderer/core/layout/depth_ordered_layout_object_list.cc b/third_party/blink/renderer/core/layout/depth_ordered_layout_object_list.cc index f4df5f1..36d51800 100644 --- a/third_party/blink/renderer/core/layout/depth_ordered_layout_object_list.cc +++ b/third_party/blink/renderer/core/layout/depth_ordered_layout_object_list.cc
@@ -93,6 +93,10 @@ return depth; } +bool DepthOrderedLayoutObjectList::Contains(LayoutObject& object) const { + return Unordered().Contains(&object); +} + const HeapHashSet<Member<LayoutObject>>& DepthOrderedLayoutObjectList::Unordered() const { return data_->objects();
diff --git a/third_party/blink/renderer/core/layout/depth_ordered_layout_object_list.h b/third_party/blink/renderer/core/layout/depth_ordered_layout_object_list.h index c22ce8c..94d953c 100644 --- a/third_party/blink/renderer/core/layout/depth_ordered_layout_object_list.h +++ b/third_party/blink/renderer/core/layout/depth_ordered_layout_object_list.h
@@ -59,6 +59,7 @@ int size() const; CORE_EXPORT bool IsEmpty() const; + bool Contains(LayoutObject&) const; const HeapHashSet<Member<LayoutObject>>& Unordered() const; const HeapVector<LayoutObjectWithDepth>& Ordered();
diff --git a/third_party/blink/renderer/core/layout/flex/flex_layout_algorithm.cc b/third_party/blink/renderer/core/layout/flex/flex_layout_algorithm.cc index 9ac5d17a..43f6e79f 100644 --- a/third_party/blink/renderer/core/layout/flex/flex_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/flex/flex_layout_algorithm.cc
@@ -1074,8 +1074,7 @@ // being greater than the specified-size. // // We'll never shrink a flex-item under the conditions specified below. - if (RuntimeEnabledFeatures::LayoutFlexCacheFixEnabled() && - min_length_in_main_axis.IsAuto() && + if (min_length_in_main_axis.IsAuto() && specified_size_suggestion <= base_border_size) { // If flex-shrink is zero we can't shrink. if (flex_shrink == 0.f) { @@ -2927,7 +2926,10 @@ return ComputeMinMaxSizeOfMultilineColumnContainer(); } - // Calculate for non-wrappable column items. + // Calculate for non-wrappable column items. Although the + // ComputeMinMaxSizeOfMultilineColumnContainer() machinery would be fully + // capable of handling this scenario as well, we have a fast-path for + // performance reasons. See crrev.com/c/7661041 MinMaxSizes sizes; bool depends_on_block_constraints = false;
diff --git a/third_party/blink/renderer/core/layout/grid/grid_item.cc b/third_party/blink/renderer/core/layout/grid/grid_item.cc index aacd4bd..8fd94487 100644 --- a/third_party/blink/renderer/core/layout/grid/grid_item.cc +++ b/third_party/blink/renderer/core/layout/grid/grid_item.cc
@@ -189,8 +189,6 @@ if (node.IsGrid() && !node.ShouldApplyLayoutContainment() && !node.ShouldApplyPaintContainment() && !style.IsContainerForSizeContainerQueries()) { - // TODO(almaher): If the parent grid is a grid-lanes container, then we only - // consider subgrids in the grid axis. has_subgridded_columns = is_parallel_with_root_grid ? style.GridTemplateColumns().IsSubgriddedAxis() @@ -198,6 +196,16 @@ has_subgridded_rows = is_parallel_with_root_grid ? style.GridTemplateRows().IsSubgriddedAxis() : style.GridTemplateColumns().IsSubgriddedAxis(); + + // If the parent grid is a grid-lanes container, then we only consider + // subgrids in the grid axis. + if (parent_grid_style.IsDisplayGridLanesBox()) { + if (parent_grid_style.GridLanesTrackSizingDirection() == kForColumns) { + has_subgridded_rows = false; + } else { + has_subgridded_columns = false; + } + } } const bool is_out_of_flow = node.IsOutOfFlowPositioned();
diff --git a/third_party/blink/renderer/core/layout/grid_lanes/grid_lanes_layout_algorithm.cc b/third_party/blink/renderer/core/layout/grid_lanes/grid_lanes_layout_algorithm.cc index 5e23b644..d682e79 100644 --- a/third_party/blink/renderer/core/layout/grid_lanes/grid_lanes_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/grid_lanes/grid_lanes_layout_algorithm.cc
@@ -502,8 +502,10 @@ LayoutUnit fragment_size = is_for_columns ? fragment.BlockSize() + margins.BlockSum() : fragment.InlineSize() + margins.InlineSum(); + const LayoutUnit visual_stacking_axis_size = + fragment_size + stacking_axis_gap; const LayoutUnit fragment_stacking_axis_contribution = - (fragment_size + stacking_axis_gap).ClampNegativeToZero(); + visual_stacking_axis_size.ClampNegativeToZero(); // If dense packing is set, we need to figure out if the item can possibly // fit into any previous track openings. If it can, then we need to adjust @@ -546,15 +548,48 @@ // align items within their grid areas. if (placement_phase == PlacementPhase::kFinalPlacement) { // `start_offset_in_stacking_axis` specifies where in the stacking axis - // the item should be placed, so we need to adjust the - // `containing_grid_area` in the stacking axis to accommodate the newly - // placed item. + // the item should be placed, so we need to adjust the `containing_rect` + // in the stacking axis to accommodate the newly placed item. + const LayoutUnit border_scrollbar_padding_start = + is_for_columns ? border_scrollbar_padding.block_start + : border_scrollbar_padding.inline_start; + + LayoutUnit final_start_offset_in_stacking_axis = + start_offset_in_stacking_axis + border_scrollbar_padding_start; + + // For fill-reverse, items stack from the end of the container instead + // of the start. We compute the base offset from the container's end so + // that alignment (which adds margins) works correctly without needing + // to mirror or swap margins after the fact. + // + // TODO(celestepan): Account for alignment with fill-reverse: + // justify/align-content, justify/align-items, and justify/align-self. + if (style.IsReverseGridLanesFillDirection()) { + // `ChildAvailableSize()` returns the content-box size of the container + // (i.e., the resolved size minus border, scrollbar, and padding). We + // use it here to determine the stacking-axis offset for fill-reverse. + // + // TODO(celestepan): Account for fill-reverse case with indefinite + // height (columns) and indefinite width (rows). + const LayoutUnit container_stacking_axis_size = + is_for_columns ? ChildAvailableSize().block_size + : ChildAvailableSize().inline_size; + + // Add back `stacking_axis_gap` when computing fill-reverse offsets; + // in fill-reverse, gaps appear before each item, so the item's offset + // must be increased to leave a visual gap in the stacking axis. + if (container_stacking_axis_size != kIndefiniteSize) { + final_start_offset_in_stacking_axis = + container_stacking_axis_size + border_scrollbar_padding_start + + stacking_axis_gap - start_offset_in_stacking_axis - + visual_stacking_axis_size; + } + } + is_for_columns ? containing_grid_area.offset.block_offset = - start_offset_in_stacking_axis + - border_scrollbar_padding.block_start + final_start_offset_in_stacking_axis : containing_grid_area.offset.inline_offset = - start_offset_in_stacking_axis + - border_scrollbar_padding.inline_start; + final_start_offset_in_stacking_axis; // TODO(celestepan): Account for extra margins from sub-grid items. //
diff --git a/third_party/blink/renderer/core/layout/grid_lanes/grid_lanes_layout_algorithm_test.cc b/third_party/blink/renderer/core/layout/grid_lanes/grid_lanes_layout_algorithm_test.cc index e3fefe5b..d44803cd 100644 --- a/third_party/blink/renderer/core/layout/grid_lanes/grid_lanes_layout_algorithm_test.cc +++ b/third_party/blink/renderer/core/layout/grid_lanes/grid_lanes_layout_algorithm_test.cc
@@ -1515,12 +1515,10 @@ EXPECT_FALSE(subgrid_item.must_consider_grid_items_for_column_sizing); EXPECT_FALSE(subgrid_item.must_consider_grid_items_for_row_sizing); - // TODO(almaher): Both should actually be false in this case. - EXPECT_TRUE(subgrid_item.has_subgridded_rows); + EXPECT_FALSE(subgrid_item.has_subgridded_rows); EXPECT_FALSE(subgrid_item.has_subgridded_columns); - // TODO(almaher): This should eventually be false. - EXPECT_TRUE(has_nested_subgrid); + EXPECT_FALSE(has_nested_subgrid); // Since `must_consider_grid_items_for_column_sizing` and // `must_consider_grid_items_for_row_sizing` are both false, @@ -1577,12 +1575,262 @@ EXPECT_FALSE(subgrid_item.must_consider_grid_items_for_column_sizing); EXPECT_FALSE(subgrid_item.must_consider_grid_items_for_row_sizing); - // TODO(almaher): Both should actually be false in this case. EXPECT_FALSE(subgrid_item.has_subgridded_rows); - EXPECT_TRUE(subgrid_item.has_subgridded_columns); + EXPECT_FALSE(subgrid_item.has_subgridded_columns); - // TODO(almaher): This should eventually be false. - EXPECT_TRUE(has_nested_subgrid); + EXPECT_FALSE(has_nested_subgrid); + + // Since `must_consider_grid_items_for_column_sizing` and + // `must_consider_grid_items_for_row_sizing` are both false, + // `AppendSubgriddedItems` should not add any extra items. + AppendSubgriddedItems(node.Style(), grid_items); + + wtf_size_t total_count = 0; + wtf_size_t subgridded_count = 0; + for (const auto& item : grid_items->IncludeSubgriddedItems()) { + if (item.is_subgridded_to_parent_grid) { + ++subgridded_count; + } + ++total_count; + } + EXPECT_EQ(total_count, 2u); + EXPECT_EQ(subgridded_count, 0u); +} + +TEST_F(GridLanesLayoutAlgorithmTest, OrthogonalAppendSubgriddedItemsColumns) { + SetBodyInnerHTML(R"HTML( + <style> + #grid-lanes { + display: grid-lanes; + grid-template-columns: 100px 100px 100px; + } + #subgrid { + display: grid; + writing-mode: vertical-rl; + grid-template-rows: subgrid; + grid-column: 2 / 4; + } + </style> + <div id="grid-lanes"> + <div id="subgrid"> + <div>A</div> + <div>B</div> + </div> + <div>C</div> + </div> + )HTML"); + + GridLanesNode node(GetLayoutBoxByElementId("grid-lanes")); + + const GridLineResolver line_resolver(node.Style(), /*auto_repetitions=*/0); + bool has_nested_subgrid = false; + auto* grid_items = node.ConstructGridItems( + line_resolver, /*must_invalidate_placement_cache=*/nullptr, + /*opt_oof_children=*/nullptr, &has_nested_subgrid); + + ASSERT_TRUE(has_nested_subgrid); + ASSERT_EQ(grid_items->Size(), 2u); + + // For an orthogonal subgrid, `grid-template-rows: subgrid` maps to the + // parent's column axis. The subgrid item should have `must_consider*` flags + // set for columns (the grid axis of this grid-lanes container). + const auto& subgrid_item = grid_items->At(0); + EXPECT_TRUE(subgrid_item.must_consider_grid_items_for_column_sizing); + EXPECT_FALSE(subgrid_item.must_consider_grid_items_for_row_sizing); + EXPECT_TRUE(subgrid_item.IsSubgrid()); + + const auto grid_axis_direction = node.Style().GridLanesTrackSizingDirection(); + for (auto& item : *grid_items) { + item.MaybeTranslateSpan(/*start_offset=*/0, grid_axis_direction); + } + + AppendSubgriddedItems(node.Style(), grid_items); + + // After appending, we should have the 2 original items + 2 subgridded items. + wtf_size_t total_count = 0; + wtf_size_t subgridded_count = 0; + for (const auto& item : grid_items->IncludeSubgriddedItems()) { + if (item.is_subgridded_to_parent_grid) { + ++subgridded_count; + } + ++total_count; + } + EXPECT_EQ(total_count, 4u); + EXPECT_EQ(subgridded_count, 2u); +} + +TEST_F(GridLanesLayoutAlgorithmTest, OrthogonalAppendSubgriddedItemsRows) { + SetBodyInnerHTML(R"HTML( + <style> + #grid-lanes { + display: grid-lanes; + grid-template-rows: 50px 50px 50px; + grid-lanes-direction: row; + } + #subgrid { + display: grid; + writing-mode: vertical-rl; + grid-template-columns: subgrid; + grid-row: 1 / 3; + } + </style> + <div id="grid-lanes"> + <div id="subgrid"> + <div>A</div> + <div>B</div> + </div> + <div>C</div> + </div> + )HTML"); + + GridLanesNode node(GetLayoutBoxByElementId("grid-lanes")); + + const GridLineResolver line_resolver(node.Style(), /*auto_repetitions=*/0); + bool has_nested_subgrid = false; + auto* grid_items = node.ConstructGridItems( + line_resolver, /*must_invalidate_placement_cache=*/nullptr, + /*opt_oof_children=*/nullptr, &has_nested_subgrid); + + ASSERT_TRUE(has_nested_subgrid); + ASSERT_EQ(grid_items->Size(), 2u); + + // For an orthogonal subgrid, `grid-template-columns: subgrid` maps to the + // parent's row axis. The subgrid item should have `must_consider*` flags set + // for rows (the grid axis of this row-direction grid-lanes container). + const auto& subgrid_item = grid_items->At(0); + EXPECT_FALSE(subgrid_item.must_consider_grid_items_for_column_sizing); + EXPECT_TRUE(subgrid_item.must_consider_grid_items_for_row_sizing); + EXPECT_TRUE(subgrid_item.IsSubgrid()); + + const auto grid_axis_direction = node.Style().GridLanesTrackSizingDirection(); + for (auto& item : *grid_items) { + item.MaybeTranslateSpan(/*start_offset=*/0, grid_axis_direction); + } + + AppendSubgriddedItems(node.Style(), grid_items); + + // After appending, we should have the 2 original items + 2 subgridded items. + wtf_size_t total_count = 0; + wtf_size_t subgridded_count = 0; + for (const auto& item : grid_items->IncludeSubgriddedItems()) { + if (item.is_subgridded_to_parent_grid) { + ++subgridded_count; + } + ++total_count; + } + EXPECT_EQ(total_count, 4u); + EXPECT_EQ(subgridded_count, 2u); +} + +TEST_F(GridLanesLayoutAlgorithmTest, + OrthogonalSubgridColumnsIgnoredInColumnGridLanes) { + SetBodyInnerHTML(R"HTML( + <style> + #grid-lanes { + display: grid-lanes; + grid-template-columns: 100px 100px 100px; + } + #subgrid { + display: grid; + writing-mode: vertical-rl; + grid-template-columns: subgrid; + grid-column: 1 / 3; + } + </style> + <div id="grid-lanes"> + <div id="subgrid"> + <div>A</div> + </div> + <div>C</div> + </div> + )HTML"); + + GridLanesNode node(GetLayoutBoxByElementId("grid-lanes")); + + const GridLineResolver line_resolver(node.Style(), /*auto_repetitions=*/0); + bool has_nested_subgrid = false; + auto* grid_items = node.ConstructGridItems( + line_resolver, /*must_invalidate_placement_cache=*/nullptr, + /*opt_oof_children=*/nullptr, &has_nested_subgrid); + + // An orthogonal child with `grid-template-columns: subgrid` maps to the + // parent's row axis after the writing-mode swap, not columns. Since the + // grid-lanes axis is columns, the subgridded axis doesn't match, so both + // `has_subgridded_*` flags should be false and the item is not a subgrid. + ASSERT_EQ(grid_items->Size(), 2u); + + const auto& subgrid_item = grid_items->At(0); + EXPECT_FALSE(subgrid_item.must_consider_grid_items_for_column_sizing); + EXPECT_FALSE(subgrid_item.must_consider_grid_items_for_row_sizing); + + EXPECT_FALSE(subgrid_item.has_subgridded_rows); + EXPECT_FALSE(subgrid_item.has_subgridded_columns); + EXPECT_FALSE(subgrid_item.IsSubgrid()); + EXPECT_FALSE(has_nested_subgrid); + + // Since `must_consider_grid_items_for_column_sizing` and + // `must_consider_grid_items_for_row_sizing` are both false, + // `AppendSubgriddedItems` should not add any extra items. + AppendSubgriddedItems(node.Style(), grid_items); + + wtf_size_t total_count = 0; + wtf_size_t subgridded_count = 0; + for (const auto& item : grid_items->IncludeSubgriddedItems()) { + if (item.is_subgridded_to_parent_grid) { + ++subgridded_count; + } + ++total_count; + } + EXPECT_EQ(total_count, 2u); + EXPECT_EQ(subgridded_count, 0u); +} + +TEST_F(GridLanesLayoutAlgorithmTest, + OrthogonalSubgridRowsIgnoredInRowGridLanes) { + SetBodyInnerHTML(R"HTML( + <style> + #grid-lanes { + display: grid-lanes; + grid-template-rows: 50px 50px 50px; + grid-lanes-direction: row; + } + #subgrid { + display: grid; + writing-mode: vertical-rl; + grid-template-rows: subgrid; + grid-row: 1 / 3; + } + </style> + <div id="grid-lanes"> + <div id="subgrid"> + <div>A</div> + </div> + <div>C</div> + </div> + )HTML"); + + GridLanesNode node(GetLayoutBoxByElementId("grid-lanes")); + + const GridLineResolver line_resolver(node.Style(), /*auto_repetitions=*/0); + bool has_nested_subgrid = false; + auto* grid_items = node.ConstructGridItems( + line_resolver, /*must_invalidate_placement_cache=*/nullptr, + /*opt_oof_children=*/nullptr, &has_nested_subgrid); + + // An orthogonal child with `grid-template-rows: subgrid` maps to the + // parent's column axis after the writing-mode swap, not rows. Since the + // grid-lanes axis is rows, the subgridded axis doesn't match, so both + // `has_subgridded_*` flags should be false and the item is not a subgrid. + ASSERT_EQ(grid_items->Size(), 2u); + + const auto& subgrid_item = grid_items->At(0); + EXPECT_FALSE(subgrid_item.must_consider_grid_items_for_column_sizing); + EXPECT_FALSE(subgrid_item.must_consider_grid_items_for_row_sizing); + + EXPECT_FALSE(subgrid_item.has_subgridded_columns); + EXPECT_FALSE(subgrid_item.has_subgridded_rows); + EXPECT_FALSE(subgrid_item.IsSubgrid()); + EXPECT_FALSE(has_nested_subgrid); // Since `must_consider_grid_items_for_column_sizing` and // `must_consider_grid_items_for_row_sizing` are both false,
diff --git a/third_party/blink/renderer/core/layout/layout_utils.cc b/third_party/blink/renderer/core/layout/layout_utils.cc index 717aa69..7dc92fe1 100644 --- a/third_party/blink/renderer/core/layout/layout_utils.cc +++ b/third_party/blink/renderer/core/layout/layout_utils.cc
@@ -301,10 +301,7 @@ // etc. if (is_old_initial_block_size_indefinite != is_initial_block_size_indefinite) { - const bool is_flexbox = - RuntimeEnabledFeatures::LayoutFlexCacheFixEnabled() && - node.IsFlexibleBox(); - if (is_flexbox || node.IsGrid() || node.IsGridLanes() || + if (node.IsFlexibleBox() || node.IsGrid() || node.IsGridLanes() || has_descendant_that_depends_on_percentage_block_size) { return LayoutCacheStatus::kNeedsLayout; }
diff --git a/third_party/blink/renderer/core/layout/physical_fragment.cc b/third_party/blink/renderer/core/layout/physical_fragment.cc index e9f3241..3beab4b 100644 --- a/third_party/blink/renderer/core/layout/physical_fragment.cc +++ b/third_party/blink/renderer/core/layout/physical_fragment.cc
@@ -762,24 +762,11 @@ // element if it has a percentage block-size however, but this will return // the correct result from below. - // There are two conditions where we need to know about an (arbitrary) - // descendant which depends on a %-block-size. - // - In quirks mode, the arbitrary descendant may depend the percentage - // resolution block-size given (to this node), and need to relayout if - // this size changes. - // - A flex-item may have its "definiteness" change, (e.g. if itself is a - // flex item which is being stretched). This definiteness change will - // affect any %-block-size children. - // - // NOTE(ikilpatrick): For the flex-item case this is potentially too general. - // We only need to know about if this flex-item has a %-block-size child if - // the "definiteness" changes, not if the percentage resolution size changes. + // In quirks mode, we may need to know about an (arbitrary) descendant which + // depends on a %-block-size, to relayout if this size changes. const BlockNode node = To<BlockNode>(builder.node_); - const bool is_flex_item = - !RuntimeEnabledFeatures::LayoutFlexCacheFixEnabled() && node.IsFlexItem(); if (builder.has_descendant_that_depends_on_percentage_block_size_ && - (node.UseParentPercentageResolutionBlockSizeForChildren() || - is_flex_item)) { + node.UseParentPercentageResolutionBlockSizeForChildren()) { return true; }
diff --git a/third_party/blink/renderer/core/layout/svg/svg_text_layout_algorithm.cc b/third_party/blink/renderer/core/layout/svg/svg_text_layout_algorithm.cc index 6e93451..3806b78 100644 --- a/third_party/blink/renderer/core/layout/svg/svg_text_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/svg/svg_text_layout_algorithm.cc
@@ -6,6 +6,7 @@ #include <algorithm> +#include "base/compiler_specific.h" #include "base/trace_event/trace_event.h" #include "third_party/blink/renderer/core/layout/svg/layout_svg_inline_text.h" #include "third_party/blink/renderer/core/layout/svg/layout_svg_text_path.h" @@ -176,7 +177,7 @@ // later character that corresponds to a typographic character. CodePointIterator iterator = item_string.begin(); const CodePointIterator end = item_string.end(); - for (++iterator; iterator != end; ++iterator) { + for (UNSAFE_TODO(++iterator); iterator != end; UNSAFE_TODO(++iterator)) { SvgPerCharacterInfo middle_info; middle_info.middle = true; middle_info.item_index = info.item_index;
diff --git a/third_party/blink/renderer/core/overscroll/overscroll_event.cc b/third_party/blink/renderer/core/overscroll/overscroll_event.cc index 392f998..10728d6 100644 --- a/third_party/blink/renderer/core/overscroll/overscroll_event.cc +++ b/third_party/blink/renderer/core/overscroll/overscroll_event.cc
@@ -12,8 +12,12 @@ OverscrollEvent::OverscrollEvent(const AtomicString& event_type, const OverscrollEventInit* init) - : Event(event_type, Bubbles::kNo, Cancelable::kNo), - overscroll_element_(init->overscrollElement()) {} + : Event(event_type, + init->bubbles() ? Bubbles::kYes : Bubbles::kNo, + Cancelable::kNo), + overscroll_target_(init->overscrollTarget()), + overscrolling_(init->hasOverscrolling() ? init->overscrolling() + : std::nullopt) {} OverscrollEvent::~OverscrollEvent() = default; @@ -23,11 +27,15 @@ void OverscrollEvent::Trace(Visitor* visitor) const { Event::Trace(visitor); - visitor->Trace(overscroll_element_); + visitor->Trace(overscroll_target_); } -Element* OverscrollEvent::overscrollElement() const { - return overscroll_element_; +Element* OverscrollEvent::overscrollTarget() const { + return overscroll_target_; +} + +std::optional<bool> OverscrollEvent::overscrolling() const { + return overscrolling_; } } // namespace blink
diff --git a/third_party/blink/renderer/core/overscroll/overscroll_event.h b/third_party/blink/renderer/core/overscroll/overscroll_event.h index 77c27a3..aa51696 100644 --- a/third_party/blink/renderer/core/overscroll/overscroll_event.h +++ b/third_party/blink/renderer/core/overscroll/overscroll_event.h
@@ -28,10 +28,13 @@ void Trace(Visitor*) const override; - Element* overscrollElement() const; + Element* overscrollTarget() const; + + std::optional<bool> overscrolling() const; private: - Member<Element> overscroll_element_; + Member<Element> overscroll_target_; + std::optional<bool> overscrolling_; }; } // namespace blink
diff --git a/third_party/blink/renderer/core/overscroll/overscroll_event.idl b/third_party/blink/renderer/core/overscroll/overscroll_event.idl index fb6821a..3688aef 100644 --- a/third_party/blink/renderer/core/overscroll/overscroll_event.idl +++ b/third_party/blink/renderer/core/overscroll/overscroll_event.idl
@@ -7,6 +7,7 @@ RuntimeEnabled=OverscrollGestures ] interface OverscrollEvent : Event { constructor(DOMString type, optional OverscrollEventInit eventInitDict = {}); - readonly attribute Element overscrollElement; + readonly attribute Element overscrollTarget; + readonly attribute boolean? overscrolling; };
diff --git a/third_party/blink/renderer/core/overscroll/overscroll_event_init.idl b/third_party/blink/renderer/core/overscroll/overscroll_event_init.idl index 78c0722..2b980b4 100644 --- a/third_party/blink/renderer/core/overscroll/overscroll_event_init.idl +++ b/third_party/blink/renderer/core/overscroll/overscroll_event_init.idl
@@ -3,5 +3,6 @@ // found in the LICENSE file. dictionary OverscrollEventInit : EventInit { - Element? overscrollElement = null; + Element? overscrollTarget = null; + boolean? overscrolling; };
diff --git a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc index c219f48..5e7b3ae 100644 --- a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc +++ b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
@@ -98,6 +98,7 @@ #include "third_party/blink/renderer/core/layout/layout_view.h" #include "third_party/blink/renderer/core/layout/physical_box_fragment.h" #include "third_party/blink/renderer/core/loader/document_loader.h" +#include "third_party/blink/renderer/core/overscroll/overscroll_area_tracker.h" #include "third_party/blink/renderer/core/page/autoscroll_controller.h" #include "third_party/blink/renderer/core/page/chrome_client.h" #include "third_party/blink/renderer/core/page/focus_controller.h" @@ -437,6 +438,10 @@ UpdateLastScrolled(scroll_offset_, new_offset, source_type); + // If this is the first scroll offsets on the overscroll area parent, we need + // to send an overscrollstart event. + EnqueueOverscrollStartEventIfNeeded(); + // The ScrollOffsetTranslation paint property depends on the scroll offset. // (see: PaintPropertyTreeBuilder::UpdateScrollAndScrollTranslation). GetLayoutBox()->SetNeedsPaintPropertyUpdate(); @@ -3460,6 +3465,7 @@ rare_data.snapped_query_target_ids_ = new_target_ids; EnqueueScrollSnapChangeEvent(); } + EnqueueOverscrollFinishedEventIfNeeded(scrollsnapchange); } void PaintLayerScrollableArea::SetScrollsnapchangingTargetIds( @@ -3470,7 +3476,8 @@ void PaintLayerScrollableArea:: UpdateScrollSnapChangingTargetsAndEnqueueScrollSnapChanging( const cc::TargetSnapAreaElementIds& new_target_ids) { - if (!RuntimeEnabledFeatures::CSSScrollSnapChangingEventEnabled()) { + if (!RuntimeEnabledFeatures::CSSScrollSnapChangingEventEnabled() && + !RuntimeEnabledFeatures::OverscrollGesturesEnabled()) { return; } const cc::SnapContainerData* container_data = GetSnapContainerData(); @@ -3482,14 +3489,29 @@ auto& rare_data = EnsureRareData(); bool scrollsnapchanging = - (rare_data.scrollsnapchanging_target_ids_ - ? (new_target_ids.x != rare_data.scrollsnapchanging_target_ids_->x || - new_target_ids.y != rare_data.scrollsnapchanging_target_ids_->y) - : true); + !rare_data.scrollsnapchanging_target_ids_ || + new_target_ids.x != rare_data.scrollsnapchanging_target_ids_->x || + new_target_ids.y != rare_data.scrollsnapchanging_target_ids_->y; + if (scrollsnapchanging) { rare_data.scrollsnapchanging_target_ids_ = new_target_ids; rare_data.snapped_query_target_ids_ = new_target_ids; - EnqueueScrollSnapChangingEvent(); + if (RuntimeEnabledFeatures::CSSScrollSnapChangingEventEnabled()) { + EnqueueScrollSnapChangingEvent(); + } + + // We potentially need to send overscrollstart, since this snap change could + // have happened before any scroll update. + EnqueueOverscrollStartEventIfNeeded(); + + if (GetLayoutBox()->IsOverscrollAreaParent()) { + CHECK_EQ(container_data->size(), 2u); + const auto& first_data = container_data->at(0); + + EnqueueOverscrollChangingEventIfNeeded( + new_target_ids.x != first_data.element_id || + new_target_ids.y != first_data.element_id); + } } } @@ -3658,4 +3680,54 @@ GetProgrammaticScrollAnimator().HasRunningAnimation(); } +void PaintLayerScrollableArea::EnqueueOverscrollStartEventIfNeeded() { + if (!GetLayoutBox()->IsOverscrollAreaParent() || + (RareData() && RareData()->in_active_overscroll_)) { + return; + } + + Element& overscroll_element = To<PseudoElement>(GetLayoutBox()->GetNode()) + ->UltimateOriginatingElement(); + Element* overscroll_container = overscroll_element.GetOverscrollContainer(); + + EnsureRareData().in_active_overscroll_ = true; + GetLayoutBox()->GetDocument().EnqueueOverscrollEvent( + event_type_names::kOverscrollstart, overscroll_container, + &overscroll_element); +} + +void PaintLayerScrollableArea::EnqueueOverscrollChangingEventIfNeeded( + bool overscrolling) { + if (!GetLayoutBox()->IsOverscrollAreaParent() || !RareData() || + !RareData()->in_active_overscroll_) { + return; + } + + Element& overscroll_element = To<PseudoElement>(GetLayoutBox()->GetNode()) + ->UltimateOriginatingElement(); + Element* overscroll_container = overscroll_element.GetOverscrollContainer(); + + GetLayoutBox()->GetDocument().EnqueueOverscrollEvent( + event_type_names::kOverscrollchanging, overscroll_container, + &overscroll_element, overscrolling); +} + +void PaintLayerScrollableArea::EnqueueOverscrollFinishedEventIfNeeded( + bool snap_changed) { + if (!GetLayoutBox()->IsOverscrollAreaParent() || !RareData() || + !RareData()->in_active_overscroll_) { + return; + } + + Element& overscroll_element = To<PseudoElement>(GetLayoutBox()->GetNode()) + ->UltimateOriginatingElement(); + Element* overscroll_container = overscroll_element.GetOverscrollContainer(); + + RareData()->in_active_overscroll_ = false; + GetLayoutBox()->GetDocument().EnqueueOverscrollEvent( + snap_changed ? event_type_names::kOverscrollend + : event_type_names::kOverscrollcancel, + overscroll_container, &overscroll_element); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h index 60fd004..c1d07784 100644 --- a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h +++ b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h
@@ -111,6 +111,9 @@ // PostLayoutSnapshotClient for keeping track of snapped targets in both // directions used for matching snapped @container queries. Member<SnappedQueryScrollSnapshot> snapped_query_snapshot_; + + // True if an overscroll gesture is currently in progress. + bool in_active_overscroll_ = false; }; // PaintLayerScrollableArea represents the scrollable area of a LayoutBox. @@ -826,6 +829,11 @@ void UpdateScrollMarkers() override; ScrollMarkerGroupPseudoElement* GetScrollMarkerGroup() const override; + // Overscroll events. + void EnqueueOverscrollStartEventIfNeeded(); + void EnqueueOverscrollChangingEventIfNeeded(bool overscrolling); + void EnqueueOverscrollFinishedEventIfNeeded(bool snap_changed); + // PaintLayer is destructed before PaintLayerScrollable area, during this // time before PaintLayerScrollableArea has been collected layer_ will // be set to nullptr by the Dispose method.
diff --git a/third_party/blink/renderer/modules/BUILD.gn b/third_party/blink/renderer/modules/BUILD.gn index 1a9fa0b..c9571ab 100644 --- a/third_party/blink/renderer/modules/BUILD.gn +++ b/third_party/blink/renderer/modules/BUILD.gn
@@ -412,6 +412,7 @@ "accessibility/testing/accessibility_test.cc", "accessibility/testing/accessibility_test.h", "ai/ai_utils_test.cc", + "ai/language_model_test.cc", "ai/language_model_tool_types_test.cc", "ai/model_execution_responder_test.cc", "ai/proofreader_test.cc",
diff --git a/third_party/blink/renderer/modules/ai/language_model.cc b/third_party/blink/renderer/modules/ai/language_model.cc index 3e028d6..870e957 100644 --- a/third_party/blink/renderer/modules/ai/language_model.cc +++ b/third_party/blink/renderer/modules/ai/language_model.cc
@@ -808,6 +808,7 @@ } // TODO(crbug.com/411470034): Aggregate other input type sizes for UMA. + CHECK(input); if (input->IsString()) { base::UmaHistogramCounts1M( AIMetrics::GetAISessionRequestSizeMetricName( @@ -847,6 +848,12 @@ MakeGarbageCollected<ScriptPromiseResolver<IDLUndefined>>(script_state); auto promise = resolver->Promise(); + if (input->IsLanguageModelMessageSequence() && + input->GetAsLanguageModelMessageSequence().empty()) { + resolver->Resolve(); + return promise; + } + ConvertPromptInputsToMojo( script_state, options->getSignalOr(nullptr), input, info_, /*json_schema=*/"",
diff --git a/third_party/blink/renderer/modules/ai/language_model.h b/third_party/blink/renderer/modules/ai/language_model.h index 2d242dc..86f3758 100644 --- a/third_party/blink/renderer/modules/ai/language_model.h +++ b/third_party/blink/renderer/modules/ai/language_model.h
@@ -26,13 +26,15 @@ #include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h" #include "third_party/blink/renderer/core/streams/readable_stream.h" #include "third_party/blink/renderer/modules/ai/language_model_params.h" +#include "third_party/blink/renderer/modules/modules_export.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h" #include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h" namespace blink { // The class that represents a `LanguageModel` object. -class LanguageModel final : public EventTarget, public ExecutionContextClient { +class MODULES_EXPORT LanguageModel final : public EventTarget, + public ExecutionContextClient { DEFINE_WRAPPERTYPEINFO(); public:
diff --git a/third_party/blink/renderer/modules/ai/language_model_prompt_builder.cc b/third_party/blink/renderer/modules/ai/language_model_prompt_builder.cc index ce81cc6..d3caddb9 100644 --- a/third_party/blink/renderer/modules/ai/language_model_prompt_builder.cc +++ b/third_party/blink/renderer/modules/ai/language_model_prompt_builder.cc
@@ -67,13 +67,18 @@ // Normalizes a prompt message into a list of canonical // LanguageModelMessageContent. Shorthand styles are converted into canonical -// formats. -HeapVector<Member<LanguageModelMessageContent>> NormalizePromptContent( +// formats. Adds an empty text content in place of empty sequences. +HeapVector<Member<LanguageModelMessageContent>> NormalizePrompt( const LanguageModelMessage* message) { V8UnionLanguageModelMessageContentSequenceOrString* content = message->content(); + CHECK(content); if (content->IsLanguageModelMessageContentSequence()) { - return content->GetAsLanguageModelMessageContentSequence(); + auto content_list = content->GetAsLanguageModelMessageContentSequence(); + if (content_list.empty()) { + content_list.push_back(MakeMessageTextContent(g_empty_string)); + } + return content_list; } CHECK(content->IsString()); HeapVector<Member<LanguageModelMessageContent>> content_list; @@ -82,16 +87,28 @@ } // Normalizes a prompt into a list of canonical LanguageModelMessage. Shorthand -// styles are converted into canonical formats. +// styles are converted into canonical formats. Yields empty user-role text +// content for empty message sequences. HeapVector<Member<LanguageModelMessage>> NormalizePrompt( const V8LanguageModelPrompt* prompt) { + CHECK(prompt); if (prompt->IsLanguageModelMessageSequence()) { - for (const auto& message : prompt->GetAsLanguageModelMessageSequence()) { + auto messages = prompt->GetAsLanguageModelMessageSequence(); + if (messages.empty()) { + auto* message = MakeGarbageCollected<LanguageModelMessage>(); + message->setRole( + V8LanguageModelMessageRole(V8LanguageModelMessageRole::Enum::kUser)); message->setContent(MakeGarbageCollected< V8UnionLanguageModelMessageContentSequenceOrString>( - NormalizePromptContent(message))); + g_empty_string)); + messages.push_back(std::move(message)); } - return prompt->GetAsLanguageModelMessageSequence(); + for (const auto& message : messages) { + message->setContent(MakeGarbageCollected< + V8UnionLanguageModelMessageContentSequenceOrString>( + NormalizePrompt(message))); + } + return messages; } CHECK(prompt->IsString()); HeapVector<Member<LanguageModelMessageContent>> content_list; @@ -338,10 +355,8 @@ void LanguageModelPromptBuilder::Build(const V8LanguageModelPrompt* input) { CHECK_EQ(processed_remaining_, 0); // Prevent parallel Build() calls. HeapVector<Member<LanguageModelMessage>> messages = NormalizePrompt(input); - if (messages.empty()) { - Resolve(); - return; - } + // NormalizePrompt ensures that the messages list is never empty. + CHECK(!messages.empty()); scoped_refptr<base::SequencedTaskRunner> task_runner = ExecutionContext::From(script_state_) ->GetTaskRunner(TaskType::kInternalDefault); @@ -354,6 +369,8 @@ HeapVector<Member<LanguageModelMessageContent>> content_sequence = message->content()->GetAsLanguageModelMessageContentSequence(); + // Normalization ensures every message has at least one content entry. + CHECK(!content_sequence.empty()); processed_remaining_ += content_sequence.size(); // Pre-allocate the mojo struct and content array. processed_prompts_.push_back(mojom::blink::AILanguageModelPrompt::New( @@ -411,9 +428,12 @@ size_t message_index = 0; for (const auto& message : messages) { + auto content_sequence = + message->content()->GetAsLanguageModelMessageContentSequence(); + CHECK(!content_sequence.empty()); size_t content_index = 0; - for (const auto& content : - message->content()->GetAsLanguageModelMessageContentSequence()) { + for (const auto& content : content_sequence) { + CHECK(content); // Track the pre-allocated message and content slot that the resulting // content will be written to. PendingEntry* pending_entry = MakeGarbageCollected<PendingEntry>( @@ -425,6 +445,9 @@ } message_index++; } + // As every message is guaranteed to have at least one content entry, + // processed_remaining_ will always be greater than 0 here. + CHECK_GT(processed_remaining_, 0); } void LanguageModelPromptBuilder::Trace(Visitor* visitor) const {
diff --git a/third_party/blink/renderer/modules/ai/language_model_test.cc b/third_party/blink/renderer/modules/ai/language_model_test.cc new file mode 100644 index 0000000..3e50e78 --- /dev/null +++ b/third_party/blink/renderer/modules/ai/language_model_test.cc
@@ -0,0 +1,189 @@ +#include "third_party/blink/renderer/modules/ai/language_model.h" + +#include "base/test/run_until.h" +#include "mojo/public/cpp/bindings/pending_remote.h" +#include "mojo/public/cpp/bindings/receiver.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/public/mojom/ai/ai_language_model.mojom-blink.h" +#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h" +#include "third_party/blink/renderer/bindings/modules/v8/v8_language_model_append_options.h" +#include "third_party/blink/renderer/bindings/modules/v8/v8_language_model_message.h" +#include "third_party/blink/renderer/bindings/modules/v8/v8_language_model_message_content.h" +#include "third_party/blink/renderer/bindings/modules/v8/v8_language_model_prompt_options.h" +#include "third_party/blink/renderer/bindings/modules/v8/v8_union_language_model_prompt.h" +#include "third_party/blink/renderer/bindings/modules/v8/v8_union_languagemodelmessagecontentsequence_string.h" +#include "third_party/blink/renderer/core/execution_context/execution_context.h" +#include "third_party/blink/renderer/platform/bindings/exception_state.h" +#include "third_party/blink/renderer/platform/testing/task_environment.h" + +namespace blink { + +class MockAILanguageModel : public mojom::blink::AILanguageModel { + public: + explicit MockAILanguageModel( + mojo::PendingReceiver<mojom::blink::AILanguageModel> receiver) + : receiver_(this, std::move(receiver)) {} + + void Prompt(Vector<mojom::blink::AILanguageModelPromptPtr> prompt, + on_device_model::mojom::blink::ResponseConstraintPtr constraint, + mojo::PendingRemote<mojom::blink::ModelStreamingResponder> + pending_responder) override { + last_prompts_ = std::move(prompt); + call_count_++; + } + void Append(Vector<mojom::blink::AILanguageModelPromptPtr> prompt, + mojo::PendingRemote<mojom::blink::ModelStreamingResponder> client) + override { + last_prompts_ = std::move(prompt); + call_count_++; + } + void MeasureInputUsage(Vector<mojom::blink::AILanguageModelPromptPtr> prompt, + MeasureInputUsageCallback callback) override { + std::move(callback).Run(0); + } + void Destroy() override {} + void Fork( + mojo::PendingRemote<mojom::blink::AIManagerCreateLanguageModelClient> + client) override {} + + Vector<mojom::blink::AILanguageModelPromptPtr> last_prompts_; + int call_count_ = 0; + mojo::Receiver<mojom::blink::AILanguageModel> receiver_; +}; + +class LanguageModelTest : public testing::Test { + public: + LanguageModel* CreateLanguageModel(ExecutionContext* context) { + mojo::PendingRemote<mojom::blink::AILanguageModel> pending_remote; + mock_remote_ = std::make_unique<MockAILanguageModel>( + pending_remote.InitWithNewPipeAndPassReceiver()); + + auto info = mojom::blink::AILanguageModelInstanceInfo::New(); + return MakeGarbageCollected<LanguageModel>( + context, std::move(pending_remote), + context->GetTaskRunner(TaskType::kInternalDefault), std::move(info)); + } + + V8LanguageModelPrompt* CreateEmptySequence() { + return MakeGarbageCollected<V8LanguageModelPrompt>( + HeapVector<Member<LanguageModelMessage>>()); + } + + V8LanguageModelPrompt* CreateStringPrompt(const String& prompt) { + return MakeGarbageCollected<V8LanguageModelPrompt>(prompt); + } + + protected: + test::TaskEnvironment task_environment_; + std::unique_ptr<MockAILanguageModel> mock_remote_; +}; + +TEST_F(LanguageModelTest, EmptyInputSucceeds) { + V8TestingScope scope; + LanguageModel* language_model = + CreateLanguageModel(scope.GetExecutionContext()); + V8LanguageModelPrompt* input = CreateEmptySequence(); + + { + DummyExceptionStateForTesting exception_state; + language_model->prompt(scope.GetScriptState(), input, + LanguageModelPromptOptions::Create(), + exception_state); + EXPECT_FALSE(exception_state.HadException()); + } + + { + DummyExceptionStateForTesting exception_state; + language_model->promptStreaming(scope.GetScriptState(), input, + LanguageModelPromptOptions::Create(), + exception_state); + EXPECT_FALSE(exception_state.HadException()); + } + + { + DummyExceptionStateForTesting exception_state; + language_model->append(scope.GetScriptState(), input, + LanguageModelAppendOptions::Create(), + exception_state); + EXPECT_FALSE(exception_state.HadException()); + } + + { + DummyExceptionStateForTesting exception_state; + language_model->measureContextUsage(scope.GetScriptState(), input, + LanguageModelPromptOptions::Create(), + exception_state); + EXPECT_FALSE(exception_state.HadException()); + } +} + +TEST_F(LanguageModelTest, VerifyMojoConversion) { + V8TestingScope scope; + LanguageModel* language_model = + CreateLanguageModel(scope.GetExecutionContext()); + + // Test empty string: prompt("") + // Should result in 1 message (user role) and 1 empty text content entry. + { + DummyExceptionStateForTesting exception_state; + language_model->prompt(scope.GetScriptState(), CreateStringPrompt(""), + LanguageModelPromptOptions::Create(), + exception_state); + EXPECT_TRUE( + base::test::RunUntil([&]() { return mock_remote_->call_count_ == 1; })); + ASSERT_EQ(mock_remote_->last_prompts_.size(), 1u); + EXPECT_EQ(mock_remote_->last_prompts_[0]->role, + mojom::blink::AILanguageModelPromptRole::kUser); + ASSERT_EQ(mock_remote_->last_prompts_[0]->content.size(), 1u); + EXPECT_EQ(mock_remote_->last_prompts_[0]->content[0]->get_text(), ""); + } + + // Test empty sequence: prompt([]) + // Should result in 1 message (user role) and 1 empty text content entry. + { + mock_remote_->last_prompts_.clear(); + DummyExceptionStateForTesting exception_state; + language_model->prompt(scope.GetScriptState(), CreateEmptySequence(), + LanguageModelPromptOptions::Create(), + exception_state); + EXPECT_TRUE( + base::test::RunUntil([&]() { return mock_remote_->call_count_ == 2; })); + ASSERT_EQ(mock_remote_->last_prompts_.size(), 1u); + EXPECT_EQ(mock_remote_->last_prompts_[0]->role, + mojom::blink::AILanguageModelPromptRole::kUser); + ASSERT_EQ(mock_remote_->last_prompts_[0]->content.size(), 1u); + EXPECT_EQ(mock_remote_->last_prompts_[0]->content[0]->get_text(), ""); + } + + // Test explicit empty content sequence: + // prompt([{role: 'user', content: []}]) + // Should result in 1 message (user role) and 1 empty text content entry. + { + mock_remote_->last_prompts_.clear(); + auto* message = MakeGarbageCollected<LanguageModelMessage>(); + message->setRole( + V8LanguageModelMessageRole(V8LanguageModelMessageRole::Enum::kUser)); + message->setContent(MakeGarbageCollected< + V8UnionLanguageModelMessageContentSequenceOrString>( + HeapVector<Member<LanguageModelMessageContent>>())); + + HeapVector<Member<LanguageModelMessage>> messages; + messages.push_back(message); + V8LanguageModelPrompt* input = + MakeGarbageCollected<V8LanguageModelPrompt>(messages); + + DummyExceptionStateForTesting exception_state; + language_model->prompt(scope.GetScriptState(), input, + LanguageModelPromptOptions::Create(), + exception_state); + EXPECT_TRUE( + base::test::RunUntil([&]() { return mock_remote_->call_count_ == 3; })); + ASSERT_EQ(mock_remote_->last_prompts_.size(), 1u); + EXPECT_EQ(mock_remote_->last_prompts_[0]->role, + mojom::blink::AILanguageModelPromptRole::kUser); + ASSERT_EQ(mock_remote_->last_prompts_[0]->content.size(), 1u); + EXPECT_EQ(mock_remote_->last_prompts_[0]->content[0]->get_text(), ""); + } +} + +} // namespace blink
diff --git a/third_party/blink/renderer/modules/media/audio/audio_renderer_mixer_input.cc b/third_party/blink/renderer/modules/media/audio/audio_renderer_mixer_input.cc index a3160d1..ce6b35e 100644 --- a/third_party/blink/renderer/modules/media/audio/audio_renderer_mixer_input.cc +++ b/third_party/blink/renderer/modules/media/audio/audio_renderer_mixer_input.cc
@@ -96,6 +96,17 @@ } void AudioRendererMixerInput::Stop() { + { + // Prevents race conditions when Stop() is called during a device change. + base::AutoLock auto_lock(device_change_lock_); + if (switch_output_device_in_progress_) { + switch_output_device_in_progress_ = false; + } + } + StopInternal(); +} + +void AudioRendererMixerInput::StopInternal() { // Stop() may be called at any time, if Pause() hasn't been called we need to // remove our mixer input before shutdown. Pause(); @@ -154,10 +165,13 @@ return; } - if (switch_output_device_in_progress_) { - DCHECK(!godia_in_progress_); - pending_device_info_cb_ = std::move(info_cb); - return; + { + base::AutoLock auto_lock(device_change_lock_); + if (switch_output_device_in_progress_) { + DCHECK(!godia_in_progress_); + pending_device_info_cb_ = std::move(info_cb); + return; + } } godia_in_progress_ = true; @@ -192,7 +206,10 @@ media::OutputDeviceStatusCB callback) { // If a GODIA() call is in progress, defer until it's complete. if (godia_in_progress_) { - DCHECK(!switch_output_device_in_progress_); + { + base::AutoLock auto_lock(device_change_lock_); + DCHECK(!switch_output_device_in_progress_); + } // Abort any previous device switch which may be pending. if (pending_switch_cb_) { @@ -214,7 +231,10 @@ return; } - switch_output_device_in_progress_ = true; + { + base::AutoLock auto_lock(device_change_lock_); + switch_output_device_in_progress_ = true; + } // Request a new sink using the new device id. This process may fail, so to // avoid interrupting working audio, don't set any class variables until we @@ -307,45 +327,48 @@ media::OutputDeviceStatusCB switch_cb, scoped_refptr<media::AudioRendererSink> sink, media::OutputDeviceInfo device_info) { - DCHECK(switch_output_device_in_progress_); - switch_output_device_in_progress_ = false; + auto return_status = device_info.device_status(); - if (device_info.device_status() != media::OUTPUT_DEVICE_STATUS_OK) { - sink->Stop(); - std::move(switch_cb).Run(device_info.device_status()); + { + base::AutoLock auto_lock(device_change_lock_); - // Start any pending device info request. - if (pending_device_info_cb_) { - GetOutputDeviceInfoAsync(std::move(pending_device_info_cb_)); + if (device_info.device_status() != media::OUTPUT_DEVICE_STATUS_OK) { + // Case: Device change failed. + sink->Stop(); + } else if (!switch_output_device_in_progress_) { + // Case: Stop() called during device change. + sink->Stop(); + return_status = media::OUTPUT_DEVICE_STATUS_ERROR_INTERNAL; + } else { + // Case: Device change succeeded, connect to new sink. + const bool has_mixer = !!mixer_; + const bool is_playing = playing_; + + // This may occur if Start() hasn't yet been called. + if (sink_) { + sink_->Stop(); + } + + sink_ = std::move(sink); + device_info_ = device_info; + device_id_ = device_info.device_id(); + + auto callback = callback_; + StopInternal(); + callback_ = callback; + + if (has_mixer) { + Start(); + if (is_playing) { + Play(); + } + } } - return; + switch_output_device_in_progress_ = false; } - const bool has_mixer = !!mixer_; - const bool is_playing = playing_; - - // This may occur if Start() hasn't yet been called. - if (sink_) { - sink_->Stop(); - } - - sink_ = std::move(sink); - device_info_ = device_info; - device_id_ = device_info.device_id(); - - auto callback = callback_; - Stop(); - callback_ = callback; - - if (has_mixer) { - Start(); - if (is_playing) { - Play(); - } - } - - std::move(switch_cb).Run(device_info.device_status()); + std::move(switch_cb).Run(return_status); // Start any pending device info request. if (pending_device_info_cb_) {
diff --git a/third_party/blink/renderer/modules/media/audio/audio_renderer_mixer_input.h b/third_party/blink/renderer/modules/media/audio/audio_renderer_mixer_input.h index e13df61..f511187b 100644 --- a/third_party/blink/renderer/modules/media/audio/audio_renderer_mixer_input.h +++ b/third_party/blink/renderer/modules/media/audio/audio_renderer_mixer_input.h
@@ -80,6 +80,7 @@ void OnRenderError(); private: + void StopInternal(); ~AudioRendererMixerInput() override; friend class AudioRendererMixerInputTest; @@ -118,6 +119,9 @@ scoped_refptr<media::AudioRendererSink> sink, media::OutputDeviceInfo device_info); + // Prevents race conditions when Stop() is called during a device change. + base::Lock device_change_lock_; + // AudioParameters received during Initialize(). media::AudioParameters params_; @@ -143,7 +147,8 @@ // exclusive when executing; these flags indicate whether one or the other is // in progress. Each method will use the other method's to defer its action. bool godia_in_progress_ = false; - bool switch_output_device_in_progress_ = false; + bool switch_output_device_in_progress_ GUARDED_BY(device_change_lock_) = + false; // Set by GetOutputDeviceInfoAsync() if a SwitchOutputDevice() call is in // progress. GetOutputDeviceInfoAsync() will be invoked again with this value
diff --git a/third_party/blink/renderer/modules/media/audio/audio_renderer_mixer_input_test.cc b/third_party/blink/renderer/modules/media/audio/audio_renderer_mixer_input_test.cc index 5c8c9be0..6231309b 100644 --- a/third_party/blink/renderer/modules/media/audio/audio_renderer_mixer_input_test.cc +++ b/third_party/blink/renderer/modules/media/audio/audio_renderer_mixer_input_test.cc
@@ -215,6 +215,21 @@ mixer_input_->Stop(); } +TEST_F(AudioRendererMixerInputTest, StopDuringSwitchOutputDevice) { + mixer_input_->Initialize(audio_parameters_, fake_callback_.get()); + mixer_input_->Start(); + const std::string kDeviceId("mock-device-id"); + EXPECT_CALL(*this, + SwitchCallbackCalled(media::OUTPUT_DEVICE_STATUS_ERROR_INTERNAL)); + base::RunLoop run_loop; + mixer_input_->SwitchOutputDevice( + kDeviceId, + blink::BindOnce(&AudioRendererMixerInputTest::SwitchCallback, + Unretained(this), blink::Unretained(&run_loop))); + mixer_input_->Stop(); + run_loop.Run(); +} + // Test SwitchOutputDevice() to the same device as the current (default) device TEST_F(AudioRendererMixerInputTest, SwitchOutputDeviceToSameDevice) { mixer_input_->Initialize(audio_parameters_, fake_callback_.get());
diff --git a/third_party/blink/renderer/modules/webaudio/audio_buffer_source_handler.cc b/third_party/blink/renderer/modules/webaudio/audio_buffer_source_handler.cc index cee0103..bd5a418 100644 --- a/third_party/blink/renderer/modules/webaudio/audio_buffer_source_handler.cc +++ b/third_party/blink/renderer/modules/webaudio/audio_buffer_source_handler.cc
@@ -6,7 +6,7 @@ #include <algorithm> -#include "base/compiler_specific.h" +#include "base/containers/span.h" #include "base/numerics/safe_conversions.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_audio_buffer_source_options.h" #include "third_party/blink/renderer/modules/webaudio/audio_graph_tracer.h" @@ -109,8 +109,7 @@ } for (unsigned i = 0; i < output_bus->NumberOfChannels(); ++i) { - UNSAFE_TODO(destination_channels_[i]) = - output_bus->Channel(i)->MutableData(); + destination_channels_[i] = output_bus->Channel(i)->MutableSpan(); } // Render by reading directly from the buffer. @@ -141,8 +140,8 @@ // still need to provide more output, so generate silence for the // remaining. for (unsigned i = 0; i < NumberOfChannels(); ++i) { - UNSAFE_TODO(memset(destination_channels_[i] + index, 0, - sizeof(float) * frames_to_process)); + std::ranges::fill( + destination_channels_[i].subspan(index, frames_to_process), 0.0f); } } @@ -182,8 +181,8 @@ // Potentially zero out initial frames leading up to the offset. if (destination_frame_offset) { for (unsigned i = 0; i < number_of_channels; ++i) { - UNSAFE_TODO(memset(destination_channels_[i], 0, - sizeof(float) * destination_frame_offset)); + std::ranges::fill( + destination_channels_[i].first(destination_frame_offset), 0.0f); } } @@ -257,8 +256,8 @@ // linear interpolation. int frames_to_process = number_of_frames; - const float** source_channels = source_channels_.get(); - float** destination_channels = destination_channels_.get(); + auto source_channels = source_channels_.as_span(); + auto destination_channels = destination_channels_.as_span(); DCHECK_GE(virtual_read_index, 0); DCHECK_GE(virtual_delta_frames, 0); @@ -278,27 +277,22 @@ int frames_to_end = end_frame - read_index; int frames_this_time = std::min(frames_to_process, frames_to_end); frames_this_time = std::max(0, frames_this_time); + size_t frames_this_time_size = + base::checked_cast<size_t>(frames_this_time); DCHECK_LE(write_index + frames_this_time, destination_length); DCHECK_LE(read_index + frames_this_time, buffer_length); for (unsigned i = 0; i < number_of_channels; ++i) { - DCHECK(UNSAFE_TODO(destination_channels[i])); + auto dest = + destination_channels[i].subspan(write_index, frames_this_time_size); - // Note: the buffer corresponding to source_channels[i] could have been - // transferred so need to check for that. If it was transferred, - // source_channels[i] is null. - UNSAFE_TODO({ - if (source_channels[i]) { - memcpy(destination_channels[i] + write_index, - source_channels[i] + read_index, - sizeof(float) * frames_this_time); - } else { - // Recall that a floating-point zero is represented by 4 bytes of 0. - memset(destination_channels[i] + write_index, 0, - sizeof(float) * frames_this_time); - } - }); + if (!source_channels[i].empty()) { + dest.copy_from( + source_channels[i].subspan(read_index, frames_this_time_size)); + } else { + std::ranges::fill(dest, 0.0f); + } } write_index += frames_this_time; @@ -345,33 +339,31 @@ } // Linear interpolation. - UNSAFE_TODO({ - for (unsigned i = 0; i < number_of_channels; ++i) { - float* destination = destination_channels[i]; - const float* source = source_channels[i]; + for (unsigned i = 0; i < number_of_channels; ++i) { + auto destination = destination_channels[i]; + auto source = source_channels[i]; - // The source channel may have been transferred so don't try to read - // from it if it was. Just set the destination to 0. - if (source) { - double sample; - if (read_index == read_index2 && read_index >= 1) { - // We're at the end of the buffer, so just linearly extrapolate - // from the last two samples. - double sample1 = source[read_index - 1]; - double sample2 = source[read_index]; - sample = sample2 + (sample2 - sample1) * interpolation_factor; - } else { - double sample1 = source[read_index]; - double sample2 = source[read_index2]; - sample = (1.0 - interpolation_factor) * sample1 + - interpolation_factor * sample2; - } - destination[write_index] = ClampTo<float>(sample); + // The source channel may have been transferred already, so don't try + // to read from it if it was. Just set the destination to 0. + if (!source.empty()) { + double sample; + if (read_index == read_index2 && read_index >= 1) { + // We're at the end of the buffer, so just linearly extrapolate + // from the last two samples. + double sample1 = source[read_index - 1]; + double sample2 = source[read_index]; + sample = sample2 + (sample2 - sample1) * interpolation_factor; } else { - destination[write_index] = 0; + double sample1 = source[read_index]; + double sample2 = source[read_index2]; + sample = (1.0 - interpolation_factor) * sample1 + + interpolation_factor * sample2; } + destination[write_index] = ClampTo<float>(sample); + } else { + destination[write_index] = 0; } - }); + } ++write_index; virtual_read_index += computed_playback_rate; @@ -440,12 +432,23 @@ Output(0).SetNumberOfChannels(number_of_channels); - source_channels_ = std::make_unique<const float*[]>(number_of_channels); - destination_channels_ = std::make_unique<float*[]>(number_of_channels); + source_channels_ = base::HeapArray<base::raw_span<const float>>::WithSize( + number_of_channels); + destination_channels_ = + base::HeapArray<base::raw_span<float>>::WithSize(number_of_channels); for (unsigned i = 0; i < number_of_channels; ++i) { - UNSAFE_TODO(source_channels_[i]) = - static_cast<float*>(shared_buffer_->channels()[i].Data()); + const auto& channel = shared_buffer_->channels()[i]; + if (!channel.IsValid()) { + source_channels_[i] = {}; + continue; + } + + DCHECK_EQ(channel.DataLength(), + static_cast<size_t>(shared_buffer_->length()) * sizeof(float)); + source_channels_[i] = base::raw_span<const float>( + base::subtle::reinterpret_span<const float>( + channel.ByteSpanMaybeShared())); } // If this is a grain (as set by a previous call to start()), validate the
diff --git a/third_party/blink/renderer/modules/webaudio/audio_buffer_source_handler.h b/third_party/blink/renderer/modules/webaudio/audio_buffer_source_handler.h index ea6ea41..675ffa7a 100644 --- a/third_party/blink/renderer/modules/webaudio/audio_buffer_source_handler.h +++ b/third_party/blink/renderer/modules/webaudio/audio_buffer_source_handler.h
@@ -8,6 +8,8 @@ #include <atomic> #include <memory> +#include "base/containers/heap_array.h" +#include "base/memory/raw_span.h" #include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" #include "third_party/blink/renderer/modules/webaudio/audio_buffer.h" @@ -125,9 +127,9 @@ // accessed from the audio thread. std::unique_ptr<SharedAudioBuffer> shared_buffer_; - // Pointers for the buffer and destination. - std::unique_ptr<const float*[]> source_channels_; - std::unique_ptr<float*[]> destination_channels_; + // Channel views for the source buffer and render destination. + base::HeapArray<base::raw_span<const float>> source_channels_; + base::HeapArray<base::raw_span<float>> destination_channels_; scoped_refptr<AudioParamHandler> playback_rate_; scoped_refptr<AudioParamHandler> detune_;
diff --git a/third_party/blink/renderer/modules/webaudio/cpu/arm/oscillator_kernel_neon.cc b/third_party/blink/renderer/modules/webaudio/cpu/arm/oscillator_kernel_neon.cc index 2ed2ac60..0f58574 100644 --- a/third_party/blink/renderer/modules/webaudio/cpu/arm/oscillator_kernel_neon.cc +++ b/third_party/blink/renderer/modules/webaudio/cpu/arm/oscillator_kernel_neon.cc
@@ -173,7 +173,8 @@ // Arm NEON doesn't have float64x2_t so we have to do this. (Aarch64 has // float64x2_t.) double virt_index[4]; - virt_index[0] = virtual_read_index; + virt_index[0] = WrapVirtualIndex(virtual_read_index, periodic_wave_size, + inv_periodic_wave_size); virt_index[1] = WrapVirtualIndex(virtual_read_index + incr_sum[0], periodic_wave_size, inv_periodic_wave_size); virt_index[2] = WrapVirtualIndex(virtual_read_index + incr_sum[1], @@ -181,11 +182,19 @@ virt_index[3] = WrapVirtualIndex(virtual_read_index + incr_sum[2], periodic_wave_size, inv_periodic_wave_size); + const float32x4_t v_wave_size = vdupq_n_f32(periodic_wave_size); + const float32x4_t v_inv_wave_size = vdupq_n_f32(inv_periodic_wave_size); + // The virtual indices we're working with now. - const float32x4_t v_virt_index = { + float32x4_t v_virt_index = { static_cast<float>(virt_index[0]), static_cast<float>(virt_index[1]), static_cast<float>(virt_index[2]), static_cast<float>(virt_index[3])}; + // It's possible that casting from double to float caused the index to + // be equal to periodic_wave_size, so wrap them if needed. + v_virt_index = + WrapVirtualIndexVector(v_virt_index, v_wave_size, v_inv_wave_size); + // Convert virtual index to actual index into wave data, wrap the index // around if needed. const uint32x4_t v_read0 =
diff --git a/third_party/blink/renderer/modules/webaudio/oscillator_handler.cc b/third_party/blink/renderer/modules/webaudio/oscillator_handler.cc index 69ba6e8..dc9ac1b 100644 --- a/third_party/blink/renderer/modules/webaudio/oscillator_handler.cc +++ b/third_party/blink/renderer/modules/webaudio/oscillator_handler.cc
@@ -648,12 +648,8 @@ base::span<float> phase_increments) const { int frames_processed = 0; -// TODO(crbug.com/489740366): OscillatorNode is producing incorrect -// results with NEON enabled. -#if !defined(CPU_ARM_NEON) std::tie(frames_processed, virtual_read_index) = ProcessARateVector(n, destination, virtual_read_index, phase_increments); -#endif // !defined(CPU_ARM_NEON) virtual_read_index = ProcessARateScalar(frames_processed, n, destination, virtual_read_index, phase_increments);
diff --git a/third_party/blink/renderer/platform/audio/audio_channel.h b/third_party/blink/renderer/platform/audio/audio_channel.h index bdcd443..c7e8f11e 100644 --- a/third_party/blink/renderer/platform/audio/audio_channel.h +++ b/third_party/blink/renderer/platform/audio/audio_channel.h
@@ -144,7 +144,7 @@ private: uint32_t length_; - raw_ptr<float, DanglingUntriaged> raw_pointer_; + raw_ptr<float> raw_pointer_; std::unique_ptr<AudioFloatArray> mem_buffer_; bool silent_; };
diff --git a/third_party/blink/renderer/platform/audio/audio_destination.cc b/third_party/blink/renderer/platform/audio/audio_destination.cc index 116d3fe1..0f6f3e2 100644 --- a/third_party/blink/renderer/platform/audio/audio_destination.cc +++ b/third_party/blink/renderer/platform/audio/audio_destination.cc
@@ -42,6 +42,7 @@ #include "media/audio/audio_features.h" #include "media/base/audio_bus.h" #include "media/base/audio_glitch_info.h" +#include "third_party/abseil-cpp/absl/cleanup/cleanup.h" #include "third_party/blink/public/common/features.h" #include "third_party/blink/public/platform/modules/webrtc/webrtc_logging.h" #include "third_party/blink/public/platform/platform.h" @@ -109,7 +110,7 @@ base::TimeTicks delay_timestamp, const media::AudioGlitchInfo& glitch_info, media::AudioBus* dest) { - base::TimeTicks start_timestamp = base::TimeTicks::Now(); + const base::TimeTicks start_timestamp = base::TimeTicks::Now(); const uint32_t number_of_frames = dest->frames(); TRACE_EVENT("webaudio", "AudioDestination::Render", "frames", @@ -149,6 +150,14 @@ output_bus_->SetChannelMemory(i, dest->channel(i).data(), number_of_frames); } + absl::Cleanup cleanup_and_report_metrics = [this, start_timestamp] { + uma_reporter_.AddRenderDuration(/*duration=*/base::TimeTicks::Now() - + start_timestamp); + for (unsigned i = 0; i < number_of_output_channels_; ++i) { + output_bus_->SetChannelMemory(i, nullptr, 0); + } + }; + if (is_output_buffer_bypassed_) { // Fill the FIFO if necessary. const uint32_t frames_available = fifo_->GetFramesAvailable(); @@ -201,67 +210,60 @@ CHECK(state_change_underrun_in_bypass_mode_); output_bus_->Zero(); fifo_->Pull(output_bus_.get(), frames_after_render); - uma_reporter_.AddRenderDuration(/*duration=*/base::TimeTicks::Now() - - start_timestamp); return frames_after_render; - } else { - fifo_->Pull(output_bus_.get(), number_of_frames); - uma_reporter_.AddRenderDuration(/*duration=*/base::TimeTicks::Now() - - start_timestamp); - return number_of_frames; } - } else { - // Fill the FIFO. - if (worklet_task_runner_) { - // Use the dual-thread rendering if the AudioWorklet is activated. - auto result = - fifo_->PullAndUpdateEarmark(output_bus_.get(), number_of_frames); - // The audio that we just pulled from the fifo will be played before the - // audio that we are about to request, so we add that duration to the - // delay of the audio we request. Note that it doesn't matter if there was - // a fifo underrun, the delay will be the same either way. - delay += audio_utilities::FramesToTime(number_of_frames, - web_audio_device_->SampleRate()); - - media::AudioGlitchInfo combined_glitch_info = glitch_info; - bool has_fifo_underrun_occurred = false; - if (result.frames_provided < number_of_frames) { - media::AudioGlitchInfo underrun{ - // FIFO contains audio at the output device sample rate. - .duration = audio_utilities::FramesToTime( - number_of_frames - result.frames_provided, - web_audio_device_->SampleRate()), - .count = 1}; - underrun.MaybeAddTraceEvent(); - combined_glitch_info += underrun; - has_fifo_underrun_occurred = true; - } - - PostCrossThreadTask( - *worklet_task_runner_, FROM_HERE, - CrossThreadBindOnce(IgnoreResult(&AudioDestination::RequestRender), - WrapRefCounted(this), number_of_frames, - result.frames_to_render, delay, delay_timestamp, - combined_glitch_info, - /*request_timestamp=*/base::TimeTicks::Now(), - has_fifo_underrun_occurred)); - } else { - // Otherwise use the single-thread rendering. - const size_t frames_to_render = - fifo_->Pull(output_bus_.get(), number_of_frames); - // The audio that we just pulled from the fifo will be played before the - // audio that we are about to request, so we add that duration to the - // delay of the audio we request. - delay += audio_utilities::FramesToTime(number_of_frames, - web_audio_device_->SampleRate()); - RequestRender(number_of_frames, frames_to_render, delay, delay_timestamp, - glitch_info, /*request_timestamp=*/base::TimeTicks::Now()); - } - uma_reporter_.AddRenderDuration(/*duration=*/base::TimeTicks::Now() - - start_timestamp); + fifo_->Pull(output_bus_.get(), number_of_frames); return number_of_frames; } + + // Fill the FIFO. + if (worklet_task_runner_) { + // Use the dual-thread rendering if the AudioWorklet is activated. + auto result = + fifo_->PullAndUpdateEarmark(output_bus_.get(), number_of_frames); + // The audio that we just pulled from the fifo will be played before the + // audio that we are about to request, so we add that duration to the + // delay of the audio we request. Note that it doesn't matter if there was + // a fifo underrun, the delay will be the same either way. + delay += audio_utilities::FramesToTime(number_of_frames, + web_audio_device_->SampleRate()); + + media::AudioGlitchInfo combined_glitch_info = glitch_info; + bool has_fifo_underrun_occurred = false; + if (result.frames_provided < number_of_frames) { + media::AudioGlitchInfo underrun{ + // FIFO contains audio at the output device sample rate. + .duration = audio_utilities::FramesToTime( + number_of_frames - result.frames_provided, + web_audio_device_->SampleRate()), + .count = 1}; + underrun.MaybeAddTraceEvent(); + combined_glitch_info += underrun; + has_fifo_underrun_occurred = true; + } + + PostCrossThreadTask( + *worklet_task_runner_, FROM_HERE, + CrossThreadBindOnce(IgnoreResult(&AudioDestination::RequestRender), + WrapRefCounted(this), number_of_frames, + result.frames_to_render, delay, delay_timestamp, + combined_glitch_info, + /*request_timestamp=*/base::TimeTicks::Now(), + has_fifo_underrun_occurred)); + } else { + // Otherwise use the single-thread rendering. + const size_t frames_to_render = + fifo_->Pull(output_bus_.get(), number_of_frames); + // The audio that we just pulled from the fifo will be played before the + // audio that we are about to request, so we add that duration to the + // delay of the audio we request. + delay += audio_utilities::FramesToTime(number_of_frames, + web_audio_device_->SampleRate()); + RequestRender(number_of_frames, frames_to_render, delay, delay_timestamp, + glitch_info, /*request_timestamp=*/base::TimeTicks::Now()); + } + return number_of_frames; } void AudioDestination::OnRenderError() {
diff --git a/third_party/blink/renderer/platform/audio/media_multi_channel_resampler.cc b/third_party/blink/renderer/platform/audio/media_multi_channel_resampler.cc index 4d26cf8e..72824b6 100644 --- a/third_party/blink/renderer/platform/audio/media_multi_channel_resampler.cc +++ b/third_party/blink/renderer/platform/audio/media_multi_channel_resampler.cc
@@ -59,6 +59,11 @@ resampler_output_bus->frames()); } read_cb_.Run(resampler_frame_delay, resampler_output_bus_wrapper_.get()); + + for (unsigned i = 0; i < resampler_output_bus_wrapper_->NumberOfChannels(); + ++i) { + resampler_output_bus_wrapper_->SetChannelMemory(i, nullptr, 0); + } } } // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc index 5bbf524..504223e 100644 --- a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc +++ b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
@@ -584,7 +584,74 @@ } std::unique_ptr<gpu::RasterScopedAccess> -CanvasResourceProviderSharedImage::WillDrawInternal() { +Canvas2DResourceProviderSharedImage::WillDrawInternal() { + DCHECK(resource_); + + // Since the resource will be updated, the cached snapshot is no longer + // valid. Note that it is important to release this reference here to not + // trigger copy-on-write below from the resource ref in the snapshot. + // Note that this is valid for single buffered mode also, since while the + // resource/mailbox remains the same, the snapshot needs an updated sync + // token for these writes. + cached_snapshot_.reset(); + + // Determine if a copy is needed for accelerated resources. This could be + // for one of two reasons: (1) copy-on-write is required, or (2) the + // SharedImage usages with which this provider should create resources has + // changed since this resource was created (this can occur, for example, + // when a client requests the backing ClientSharedImage with a specific + // required set of usages for an external write). Note that for + // unaccelerated resources, neither of these apply: writes to the + // SharedImage are deferred to ProduceCanvasResource and hence + // copy-on-write is never needed here, and the set of SharedImage usages + // doesn't change over the lifetime of the provider. + std::unique_ptr<gpu::RasterScopedAccess> dst_access; + if (is_accelerated_ && (ShouldReplaceTargetBuffer(cached_content_id_) || + !IsResourceUsable(resource_.get()))) { + cached_content_id_ = PaintImage::kInvalidContentId; + DCHECK(!current_resource_has_write_access_) + << "Write access must be released before sharing the resource"; + + auto old_resource = std::move(resource_); + auto* old_resource_shared_image = + static_cast<CanvasResourceSharedImage*>(old_resource.get()); + + if (!IsResourceUsable(old_resource.get())) { + // If this resource has become unusable, all cached resources have also + // become unusable. Drop them to ensure that a new usable resource gets + // created in the below call to NewOrRecycledResource(). + ClearUnusedResources(); + } + resource_ = NewOrRecycledResource(); + DCHECK(IsResourceUsable(resource_.get())); + dst_access = resource_->BeginAccess(/*readonly=*/false); + if (must_preserve_content_on_copy_on_write_) { + auto old_mailbox = + old_resource_shared_image->GetClientSharedImage()->mailbox(); + auto mailbox = resource()->GetClientSharedImage()->mailbox(); + auto src_access = old_resource->BeginAccess(/*readonly=*/true); + RasterInterface()->CopySharedImage(old_mailbox, mailbox, 0, 0, 0, 0, + Size().width(), Size().height()); + gpu::RasterScopedAccess::EndAccess(std::move(src_access)); + } else { + // If we're not copying over the previous contents, we need to ensure + // that the image is cleared on the next BeginRasterCHROMIUM. + is_cleared_ = false; + } + + UMA_HISTOGRAM_BOOLEAN("Blink.Canvas.ContentChangeMode", + must_preserve_content_on_copy_on_write_); + // By default, the contents of the new resource must be preserved on a + // subsequent CopyOnWrite. + must_preserve_content_on_copy_on_write_ = true; + } else { + dst_access = resource_->BeginAccess(/*readonly=*/false); + } + return dst_access; +} + +std::unique_ptr<gpu::RasterScopedAccess> +CanvasNon2DResourceProviderSharedImage::WillDrawInternal() { DCHECK(resource_); // Since the resource will be updated, the cached snapshot is no longer @@ -666,7 +733,7 @@ } } -bool CanvasResourceProviderSharedImage::WritePixels( +bool Canvas2DResourceProviderSharedImage::WritePixels( const SkImageInfo& orig_info, const void* pixels, size_t row_bytes, @@ -677,7 +744,50 @@ return UnacceleratedWritePixels(orig_info, pixels, row_bytes, x, y); } - TRACE_EVENT0("blink", "CanvasResourceProviderSharedImage::WritePixels"); + TRACE_EVENT0("blink", "Canvas2DResourceProviderSharedImage::WritePixels"); + if (IsGpuContextLost()) { + return false; + } + + auto access = WillDrawInternal(); + + // The below write to the resource's SharedImage will need to be preserved in + // the case of a subsequent CopyOnWrite. + // TODO(crbug.com/352263194): Logically this bool must already be true + // (see discussion here: + // https://chromium-review.googlesource.com/c/chromium/src/+/7557841/comment/bb38e497_ef1efdbc/). + // Verify that this is the case and update the code here. + must_preserve_content_on_copy_on_write_ = true; + + auto client_si = resource()->GetClientSharedImage(); + RasterInterface()->WritePixels(client_si->mailbox(), x, y, + client_si->GetTextureTarget(), + SkPixmap(orig_info, pixels, row_bytes)); + resource()->EndAccess(std::move(access)); + + // If the overdraw optimization kicked in, we need to indicate that the + // pixels do not need to be cleared, otherwise the subsequent + // rasterizations will clobber canvas contents. + if (x <= 0 && y <= 0 && orig_info.width() >= Size().width() && + orig_info.height() >= Size().height()) { + is_cleared_ = true; + } + + return true; +} + +bool CanvasNon2DResourceProviderSharedImage::WritePixels( + const SkImageInfo& orig_info, + const void* pixels, + size_t row_bytes, + int x, + int y) { + if (!is_accelerated_) { + WillDrawUnaccelerated(); + return UnacceleratedWritePixels(orig_info, pixels, row_bytes, x, y); + } + + TRACE_EVENT0("blink", "CanvasNon2DResourceProviderSharedImage::WritePixels"); if (IsGpuContextLost()) { return false; } @@ -1223,21 +1333,6 @@ } std::unique_ptr<CanvasNon2DResourceProviderSharedImage> -CanvasNon2DResourceProviderSharedImage::CreateWithClear( - gfx::Size size, - viz::SharedImageFormat format, - SkAlphaType alpha_type, - const gfx::ColorSpace& color_space, - base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper, - gpu::SharedImageUsageSet shared_image_usage_flags, - Delegate* delegate) { - return CreateSharedImageProviderBase<CanvasNon2DResourceProviderSharedImage>( - size, format, alpha_type, color_space, ShouldInitialize::kCallClear, - context_provider_wrapper, RasterMode::kGPU, shared_image_usage_flags, - delegate); -} - -std::unique_ptr<CanvasNon2DResourceProviderSharedImage> CanvasNon2DResourceProviderSharedImage::Create( gfx::Size size, const Canvas2DColorParams& color_params,
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h index 14511f3..f87058bc 100644 --- a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h +++ b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h
@@ -424,11 +424,6 @@ // rate. bool IsSingleBuffered() const; - bool WritePixels(const SkImageInfo& orig_info, - const void* pixels, - size_t row_bytes, - int x, - int y) override; // Notifies before any unaccelerated drawing will be done on the resource used // by this provider. void WillDrawUnaccelerated(); @@ -447,10 +442,17 @@ gpu::raster::RasterInterface* RasterInterface() const; void EnsureWriteAccess(); void EndWriteAccess(); - std::unique_ptr<gpu::RasterScopedAccess> WillDrawInternal(); CanvasImageProvider* GetOrCreateCanvasImageProvider(); + scoped_refptr<CanvasResourceSharedImage> NewOrRecycledResource(); + bool IsResourceUsable(CanvasResourceSharedImage* resource); + bool ShouldReplaceTargetBuffer( + PaintImage::ContentId content_id = PaintImage::kInvalidContentId); + + cc::PaintImage::ContentId cached_content_id_ = + cc::PaintImage::kInvalidContentId; + scoped_refptr<StaticBitmapImage> cached_snapshot_; bool resource_recycling_enabled_ = true; @@ -491,13 +493,9 @@ void RegisterUnusedResource( scoped_refptr<CanvasResourceSharedImage>&& resource); - scoped_refptr<CanvasResourceSharedImage> NewOrRecycledResource(); - bool IsResourceUsable(CanvasResourceSharedImage* resource); const CanvasResourceSharedImage* resource() const { return static_cast<const CanvasResourceSharedImage*>(resource_.get()); } - bool ShouldReplaceTargetBuffer( - PaintImage::ContentId content_id = PaintImage::kInvalidContentId); void RecycleResource(scoped_refptr<CanvasResourceSharedImage>&& resource); void MaybePostUnusedResourcesReclaimTask(); @@ -526,9 +524,6 @@ base::WeakPtr<WebGraphicsSharedImageInterfaceProvider> shared_image_interface_provider_; - cc::PaintImage::ContentId cached_content_id_ = - cc::PaintImage::kInvalidContentId; - bool notified_context_lost_ = false; base::WeakPtrFactory<CanvasResourceProviderSharedImage> weak_ptr_factory_{ this}; @@ -588,6 +583,11 @@ Canvas2DResourceProviderSharedImage* As2DSharedImageProvider() final { return this; } + bool WritePixels(const SkImageInfo& orig_info, + const void* pixels, + size_t row_bytes, + int x, + int y) override; // Returns the ClientSharedImage backing this CanvasResourceProvider, if one // exists, after flushing the resource and signaling that an external write @@ -609,6 +609,9 @@ // of this resource (whether via raster or the compositor) waits on this // token. void TransferBackFromWebGPU(const gpu::SyncToken& webgpu_write_sync_token); + + private: + std::unique_ptr<gpu::RasterScopedAccess> WillDrawInternal(); }; // * Subclass of CanvasResourceProviderSharedImage that is specialized for usage @@ -625,15 +628,6 @@ gpu::SharedImageUsageSet shared_image_usage_flags, Delegate* delegate = nullptr); - // The returned instance will have been cleared at creation. - static std::unique_ptr<CanvasNon2DResourceProviderSharedImage> - CreateWithClear(gfx::Size size, - viz::SharedImageFormat format, - SkAlphaType alpha_type, - const gfx::ColorSpace& color_space, - base::WeakPtr<WebGraphicsContext3DProviderWrapper>, - gpu::SharedImageUsageSet shared_image_usage_flags, - Delegate* delegate = nullptr); static std::unique_ptr<CanvasNon2DResourceProviderSharedImage> Create( gfx::Size size, const Canvas2DColorParams& color_params, @@ -692,6 +686,11 @@ // CanvasResourceProvider: void RasterRecord(cc::PaintRecord last_recording) override; + bool WritePixels(const SkImageInfo& orig_info, + const void* pixels, + size_t row_bytes, + int x, + int y) override; // Drops the cached snapshot (if any) and invokes `draw_callback` on this // instance's canvas. @@ -733,6 +732,9 @@ // write have completed. Ensures that the next read of this resource (whether // via raster or the compositor) waits on this token. void EndExternalWrite(const gpu::SyncToken& external_write_sync_token); + + private: + std::unique_ptr<gpu::RasterScopedAccess> WillDrawInternal(); }; } // namespace blink
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index 9e9c2cf0..cf33da9 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -3361,10 +3361,6 @@ public: true, }, { - name: "LayoutFlexCacheFix", - status: "stable", - }, - { name: "LayoutIgnoreMarginsForSticky", }, {
diff --git a/third_party/blink/renderer/platform/wtf/deque.h b/third_party/blink/renderer/platform/wtf/deque.h index 830b4dc..821678b3 100644 --- a/third_party/blink/renderer/platform/wtf/deque.h +++ b/third_party/blink/renderer/platform/wtf/deque.h
@@ -100,11 +100,11 @@ T& front() { DCHECK_NE(start_, end_); - return buffer_[start_]; + return UNSAFE_TODO(buffer_[start_]); } const T& front() const { DCHECK_NE(start_, end_); - return buffer_[start_]; + return UNSAFE_TODO(buffer_[start_]); } T TakeFirst(); @@ -121,12 +121,14 @@ T& at(wtf_size_t i) { CHECK_LT(i, size()); wtf_size_t right = buffer_.capacity() - start_; - return i < right ? buffer_[start_ + i] : buffer_[i - right]; + // SAFETY: `i` CHECKED above. + return UNSAFE_BUFFERS(i < right ? buffer_[start_ + i] : buffer_[i - right]); } const T& at(wtf_size_t i) const { CHECK_LT(i, size()); wtf_size_t right = buffer_.capacity() - start_; - return i < right ? buffer_[start_ + i] : buffer_[i - right]; + // SAFETY: `i` CHECKED above. + return UNSAFE_BUFFERS(i < right ? buffer_[start_ + i] : buffer_[i - right]); } T& operator[](wtf_size_t i) { return at(i); } @@ -173,13 +175,15 @@ BackingBuffer(const BackingBuffer&) = delete; BackingBuffer& operator=(const BackingBuffer&) = delete; + // PRECONDITIONS: Call sites must ensure `index` is valid. void SetSize(wtf_size_t size) { size_ = size; } - inline T& operator[](wtf_size_t index) { - // SAFETY: Call sites must ensure `index` is valid. + UNSAFE_BUFFER_USAGE inline T& operator[](wtf_size_t index) { + // SAFETY: required from caller, enforced by UNSAFE_BUFFER_USAGE. return UNSAFE_BUFFERS(Base::Buffer()[index]); } - inline const T& operator[](wtf_size_t index) const { - // SAFETY: Call sites must ensure `index` is valid. + // PRECONDITIONS: Call sites must ensure `index` is valid. + UNSAFE_BUFFER_USAGE inline const T& operator[](wtf_size_t index) const { + // SAFETY: required from caller, enforced by UNSAFE_BUFFER_USAGE. return UNSAFE_BUFFERS(Base::Buffer()[index]); } }; @@ -578,7 +582,7 @@ template <typename U> inline void Deque<T, InlineCapacity, Allocator>::push_back(U&& value) { ExpandCapacityIfNeeded(); - T* new_element = &buffer_[end_]; + T* new_element = UNSAFE_TODO(&buffer_[end_]); if (end_ == buffer_.capacity() - 1) end_ = 0; else @@ -596,14 +600,14 @@ else --start_; ConstructTraits<T, VectorTraits<T>, Allocator>::ConstructAndNotifyElement( - &buffer_[start_], std::forward<U>(value)); + UNSAFE_TODO(&buffer_[start_]), std::forward<U>(value)); } template <typename T, wtf_size_t InlineCapacity, typename Allocator> template <typename... Args> inline void Deque<T, InlineCapacity, Allocator>::emplace_back(Args&&... args) { ExpandCapacityIfNeeded(); - T* new_element = &buffer_[end_]; + T* new_element = UNSAFE_TODO(&buffer_[end_]); if (end_ == buffer_.capacity() - 1) end_ = 0; else @@ -621,13 +625,13 @@ else --start_; ConstructTraits<T, VectorTraits<T>, Allocator>::ConstructAndNotifyElement( - &buffer_[start_], std::forward<Args>(args)...); + UNSAFE_TODO(&buffer_[start_]), std::forward<Args>(args)...); } template <typename T, wtf_size_t InlineCapacity, typename Allocator> inline void Deque<T, InlineCapacity, Allocator>::pop_front() { DCHECK(!empty()); - T* begin = &buffer_[start_]; + T* begin = UNSAFE_TODO(&buffer_[start_]); T* end = UNSAFE_TODO(begin + 1); TypeOperations::Destruct(begin, end); UNSAFE_TODO(buffer_.ClearUnusedSlots(begin, end)); @@ -644,7 +648,7 @@ end_ = buffer_.capacity() - 1; else --end_; - T* begin = &buffer_[end_]; + T* begin = UNSAFE_TODO(&buffer_[end_]); T* end = UNSAFE_TODO(begin + 1); TypeOperations::Destruct(begin, end); UNSAFE_TODO(buffer_.ClearUnusedSlots(begin, end)); @@ -744,15 +748,18 @@ template <typename T, wtf_size_t InlineCapacity, typename Allocator> inline T* DequeIteratorBase<T, InlineCapacity, Allocator>::After() const { CHECK_NE(index_, deque_->end_); - return &deque_->buffer_[index_]; + // SAFETY: `index_` checked on previous line. + return UNSAFE_BUFFERS(&deque_->buffer_[index_]); } template <typename T, wtf_size_t InlineCapacity, typename Allocator> inline T* DequeIteratorBase<T, InlineCapacity, Allocator>::Before() const { CHECK_NE(index_, deque_->start_); - if (!index_) - return &deque_->buffer_[deque_->buffer_.capacity() - 1]; - return &deque_->buffer_[index_ - 1]; + // SAFETY: `index_` checked on previous line. + if (!index_) { + return UNSAFE_BUFFERS(&deque_->buffer_[deque_->buffer_.capacity() - 1]); + } + return UNSAFE_BUFFERS(&deque_->buffer_[index_ - 1]); } // This is only defined if the allocator is a HeapAllocator. It is used when
diff --git a/third_party/blink/renderer/platform/wtf/hash_map.h b/third_party/blink/renderer/platform/wtf/hash_map.h index f21991b..fbff742 100644 --- a/third_party/blink/renderer/platform/wtf/hash_map.h +++ b/third_party/blink/renderer/platform/wtf/hash_map.h
@@ -64,11 +64,11 @@ static void ClearValue(T& p) { using ValueType = typename T::ValueType; if (IsTraceableV<ValueType>) { - // SAFTEY: compiler-deduced size for ValueType. + // SAFETY: size of `p.value` determined by compiler. UNSAFE_BUFFERS( AtomicMemzero<sizeof(ValueType), alignof(ValueType)>(&p.value)); } else { - // SAFETY: compiler-deduced size for ValueType. + // SAFETY: size of `p.value` determined by compiler. UNSAFE_BUFFERS(memset(static_cast<void*>(&p.value), 0, sizeof(p.value))); } }
diff --git a/third_party/blink/renderer/platform/wtf/text/code_point_iterator.h b/third_party/blink/renderer/platform/wtf/text/code_point_iterator.h index 8f61cbd..562e83f 100644 --- a/third_party/blink/renderer/platform/wtf/text/code_point_iterator.h +++ b/third_party/blink/renderer/platform/wtf/text/code_point_iterator.h
@@ -104,14 +104,16 @@ } UChar32 operator*() const { return is_8bit_ ? *Data() : *utf16_; } - void operator++() { - is_8bit_ - ? static_cast<void>( - // SAFETY: safe to increment as we're not deref, caller - // should check the returned value is not equal to - // `CodePointIterator::End(<same string>)` before dereferencing. - UNSAFE_BUFFERS(++DataRef())) - : ++utf16_; + + // PRECONDITIONS: iterator is not equal to CodePointIterator::End(). + // POSTCONDITION: caller must check the returned value is not equal to + // `CodePointIterator::End(<same string>)` before dereferencing. + UNSAFE_BUFFER_USAGE void operator++() { + is_8bit_ ? static_cast<void>( + // SAFETY: safe to increment as we're not deref, required + // from caller via UNSAFE_BUFFER_USAGE. + UNSAFE_BUFFERS(++DataRef())) + : ++utf16_; } bool operator==(const CodePointIterator& other) const { @@ -157,7 +159,7 @@ inline void CodePointIterator::Utf16::operator++() { if (!code_point_length_) [[unlikely]] { // `code_point_length_` is cached by `operator*()`. If not, compute it. - // SAFETY: call into icu functions. + // SAFETY: call into icu functions which check `length_`. UNSAFE_BUFFERS(U16_FWD_1(data_, code_point_length_, length_);); } AdvanceByCodeUnits(code_point_length_);
diff --git a/third_party/blink/renderer/platform/wtf/text/code_point_iterator_test.cc b/third_party/blink/renderer/platform/wtf/text/code_point_iterator_test.cc index 55e2524..dd8a69a 100644 --- a/third_party/blink/renderer/platform/wtf/text/code_point_iterator_test.cc +++ b/third_party/blink/renderer/platform/wtf/text/code_point_iterator_test.cc
@@ -4,6 +4,7 @@ #include "third_party/blink/renderer/platform/wtf/text/code_point_iterator.h" +#include "base/compiler_specific.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/renderer/platform/wtf/text/string_view.h" @@ -63,14 +64,18 @@ const auto& test = GetParam(); const String string = test.ToString(); wtf_size_t count = 0; - for (auto iterator = string.begin(); iterator != string.end(); ++iterator) { + // SAFETY: required for test. + for (auto iterator = string.begin(); iterator != string.end(); + UNSAFE_BUFFERS(++iterator)) { ++count; } EXPECT_EQ(count, test.chars.size()); const StringView view(string); count = 0; - for (auto iterator = view.begin(); iterator != view.end(); ++iterator) { + // SAFETY: required for test. + for (auto iterator = view.begin(); iterator != view.end(); + UNSAFE_BUFFERS(++iterator)) { ++count; } EXPECT_EQ(count, test.chars.size());
diff --git a/third_party/blink/renderer/platform/wtf/text/string_builder.cc b/third_party/blink/renderer/platform/wtf/text/string_builder.cc index 64f6ae0..5dcd6f7 100644 --- a/third_party/blink/renderer/platform/wtf/text/string_builder.cc +++ b/third_party/blink/renderer/platform/wtf/text/string_builder.cc
@@ -301,9 +301,8 @@ Vector<char, kDefaultSize> buffer(kDefaultSize); va_start(args, format); - // SAFETY: The safety of this code depends on the content of `format`. Since - // unsafe usage is marked with UNSAFE_TODO or UNSAFE_BUFFERS at the call - // site, no action is required here. + // SAFETY: The safety of this code depends on the content of `format`. + // Required from caller, Enforced by UNSAFE_BUFFER_USAGE in header. int length = UNSAFE_BUFFERS(base::VSpanPrintf(buffer, format, args)); va_end(args); DCHECK_GE(length, 0);
diff --git a/third_party/blink/renderer/platform/wtf/text/string_impl.h b/third_party/blink/renderer/platform/wtf/text/string_impl.h index 3f8db239..2358303d 100644 --- a/third_party/blink/renderer/platform/wtf/text/string_impl.h +++ b/third_party/blink/renderer/platform/wtf/text/string_impl.h
@@ -752,7 +752,8 @@ const CharacterTypeB* b_data = b.data(); while (length--) { // Avoid base::span::operator[] for better performance. - // SAFETY: This function ensures a_data and b_data move inside their spans. + // SAFETY: This function ensures a_data and b_data move inside their spans, + // since CHECK() above ensures a and b have same size. if (UNSAFE_BUFFERS(ToAsciiLower(*a_data++) != ToAsciiLower(*b_data++))) { return false; }
diff --git a/third_party/blink/renderer/platform/wtf/text/text_codec_ascii_fast_path.h b/third_party/blink/renderer/platform/wtf/text/text_codec_ascii_fast_path.h index d34846f..c23e85e 100644 --- a/third_party/blink/renderer/platform/wtf/text/text_codec_ascii_fast_path.h +++ b/third_party/blink/renderer/platform/wtf/text/text_codec_ascii_fast_path.h
@@ -37,18 +37,18 @@ template <> struct UCharByteFiller<4> { - static void Copy(MachineWord word, LChar* destination) { - // SAFETY: This is only used in a few places, and only copies - // a MachineWord buffer, the caller guarantees that destination - // holds at least 4 elements. + // PRECONDITIONS: `destination` must hold at least 4 elements. + UNSAFE_BUFFER_USAGE static void Copy(MachineWord word, LChar* destination) { + // SAFETY: Required from caller, enforced by UNSAFE_BUFFER_USAGE. This is + // only used in a few places, and only copies a MachineWord buffer. UNSAFE_BUFFERS(memcpy(destination, &word, 4)); } - static void Copy(MachineWord word, UChar* destination) { + // PRECONDITIONS: `destination` must hold at least 4 elements. + UNSAFE_BUFFER_USAGE static void Copy(MachineWord word, UChar* destination) { auto source = base::byte_span_from_ref(word); - // SAFETY: This is only used in a few places, and only copies - // a MachineWord buffer, the caller guarantees that destination - // holds at least 4 elements. + // SAFETY: Required from caller, enforced by UNSAFE_BUFFER_USAGE. This is + // only used in a few places, and only copies a MachineWord buffer. UNSAFE_BUFFERS({ destination[0] = source[0]; destination[1] = source[1]; @@ -60,18 +60,18 @@ template <> struct UCharByteFiller<8> { - static void Copy(MachineWord word, LChar* destination) { - // SAFETY: This is only used in a few places, and only copies - // a MachineWord buffer, the caller guarantees that destination - // holds at least 8 elements. + // PRECONDITIONS: `destination` must hold at least 8 elements. + UNSAFE_BUFFER_USAGE static void Copy(MachineWord word, LChar* destination) { + // SAFETY: Required from caller, enforced by UNSAFE_BUFFER_USAGE. This is + // only used in a few places, and only copies a MachineWord buffer. UNSAFE_BUFFERS(memcpy(destination, &word, 8)); } - static void Copy(MachineWord word, UChar* destination) { + // PRECONDITIONS: `destination` must hold at least 8 elements. + UNSAFE_BUFFER_USAGE static void Copy(MachineWord word, UChar* destination) { auto source = base::byte_span_from_ref(word); - // SAFETY: This is only used in a few places, and only copies - // a MachineWord buffer, the caller guarantees that destination - // holds at least 8 elements. + // SAFETY: Required from caller, enforced by UNSAFE_BUFFER_USAGE. This is + // only used in a few places, and only copies a MachineWord buffer. UNSAFE_BUFFERS({ destination[0] = source[0]; destination[1] = source[1]; @@ -85,12 +85,17 @@ } }; +// PRECONDITIONS: `destination` must be valid for sizeof(MachineWord). inline void CopyAsciiMachineWord(MachineWord word, LChar* destination) { - UCharByteFiller<sizeof(MachineWord)>::Copy(word, destination); + // SAFETY: required from caller, enforced by UNSAFE_BUFFER_USAGE. + UNSAFE_BUFFERS(UCharByteFiller<sizeof(MachineWord)>::Copy(word, destination)); } -inline void CopyAsciiMachineWord(MachineWord word, UChar* destination) { - UCharByteFiller<sizeof(MachineWord)>::Copy(word, destination); +// PRECONDITIONS: `destination` must be valid for sizeof(MachineWord). +UNSAFE_BUFFER_USAGE inline void CopyAsciiMachineWord(MachineWord word, + UChar* destination) { + // SAFETY: required from caller, enforced by UNSAFE_BUFFER_USAGE. + UNSAFE_BUFFERS(UCharByteFiller<sizeof(MachineWord)>::Copy(word, destination)); } } // namespace blink
diff --git a/third_party/blink/renderer/platform/wtf/text/text_codec_latin1.cc b/third_party/blink/renderer/platform/wtf/text/text_codec_latin1.cc index 4a5d72c..1e60fb4 100644 --- a/third_party/blink/renderer/platform/wtf/text/text_codec_latin1.cc +++ b/third_party/blink/renderer/platform/wtf/text/text_codec_latin1.cc
@@ -29,6 +29,7 @@ #include <memory> +#include "base/compiler_specific.h" #include "base/types/to_address.h" #include "third_party/blink/renderer/platform/wtf/text/ascii_fast_path.h" #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h" @@ -197,8 +198,9 @@ } static constexpr size_t kMachineWordSize = sizeof(MachineWord); - CopyAsciiMachineWord( - chunk, destination16.take_first<kMachineWordSize>().data()); + // SAFTEY: `take_first<kMachineWordSize>()` ensures sufficient size. + UNSAFE_BUFFERS(CopyAsciiMachineWord( + chunk, destination16.take_first<kMachineWordSize>().data())); source.take_first<kMachineWordSize>(); }
diff --git a/third_party/blink/renderer/platform/wtf/text/text_codec_utf8.cc b/third_party/blink/renderer/platform/wtf/text/text_codec_utf8.cc index 072ca944..70e36135 100644 --- a/third_party/blink/renderer/platform/wtf/text/text_codec_utf8.cc +++ b/third_party/blink/renderer/platform/wtf/text/text_codec_utf8.cc
@@ -482,9 +482,10 @@ if (!IsAllAscii<LChar>(chunk)) { break; } - - CopyAsciiMachineWord( - chunk, destination16.take_first<sizeof(MachineWord)>().data()); + // SAFETY: `take_first<sizeof(MachineWord)>()` ensures sufficient + // size. + UNSAFE_BUFFERS(CopyAsciiMachineWord( + chunk, destination16.take_first<sizeof(MachineWord)>().data())); source.take_first<sizeof(MachineWord)>(); } if (source.empty()) {
diff --git a/third_party/blink/renderer/platform/wtf/text/wtf_string.h b/third_party/blink/renderer/platform/wtf/text/wtf_string.h index 032d2d6..483918a 100644 --- a/third_party/blink/renderer/platform/wtf/text/wtf_string.h +++ b/third_party/blink/renderer/platform/wtf/text/wtf_string.h
@@ -121,6 +121,9 @@ // Takes a printf format and args and prints into a String. // This function supports Latin-1 characters only. + // PRECONDITIONS: `format` must be compatible with subsequent args. + // Ideally, this would be UNSAFE_BUFFER_USAGE but there are too many + // callers at present to investigate. [[nodiscard]] PRINTF_FORMAT(1, 2) static String Format(const char* format, ...);
diff --git a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py index 9b7c220..3a0ffd5 100755 --- a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py +++ b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
@@ -163,6 +163,7 @@ 'base::span', 'base::span(_with_nul)?_from_cstring', 'base::Span(OrSize|Reader|Writer)', + 'base::subtle::reinterpret_span', 'base::StringPiece', 'base::StrongAlias', 'base::SubstringSetMatcher', @@ -181,6 +182,7 @@ 'base::ToString', 'base::TrackEvent', 'base::trace_event::.*', + 'base::unchecked', 'base::unexpected', 'base::UnguessableToken', 'base::UnguessableTokenHash',
diff --git a/third_party/blink/web_tests/AIExpectations b/third_party/blink/web_tests/AIExpectations index 4360071..08bae7e2 100644 --- a/third_party/blink/web_tests/AIExpectations +++ b/third_party/blink/web_tests/AIExpectations
@@ -32,10 +32,13 @@ # These tests frequently time out on Mac platforms. # Disables tests on all platforms, since disabling these tests on Mac only is not supported. -crbug.com/460555196 external/wpt/ai/language-model/language-model-prompt-multimodal.tentative.https.window.html [ Timeout Pass ] -crbug.com/460799715 external/wpt/ai/language-model/language-model-prompt.tentative.https.window.html [ Timeout Pass ] crbug.com/460799715 external/wpt/ai/language-model/language-model-clone.tentative.https.window.html [ Timeout Pass ] crbug.com/460799715 external/wpt/ai/language-model/language-model-iframe.tentative.https.html [ Timeout Pass ] +crbug.com/460799715 external/wpt/ai/language-model/language-model-prompt-empty-input.tentative.https.window.html [ Timeout Pass ] +crbug.com/459864801 external/wpt/ai/language-model/language-model-prompt-multimodal-image.tentative.https.window.html [ Timeout Pass ] +crbug.com/459864801 external/wpt/ai/language-model/language-model-prompt-multimodal-video.tentative.https.window.html [ Timeout Pass ] +crbug.com/460555196 external/wpt/ai/language-model/language-model-prompt-multimodal.tentative.https.window.html [ Timeout Pass ] +crbug.com/460799715 external/wpt/ai/language-model/language-model-prompt.tentative.https.window.html [ Timeout Pass ] crbug.com/460799715 external/wpt/ai/language-model/language-model-quota-exceeded.tentative.https.window.html [ Timeout Pass ] crbug.com/460799715 external/wpt/ai/language-model/language-model-response-json-schema.tentative.https.window.html [ Timeout Pass ] crbug.com/460799715 external/wpt/ai/rewriter/rewriter-abort.tentative.https.window.html [ Timeout Pass ] @@ -45,7 +48,5 @@ crbug.com/460799715 external/wpt/ai/writer/writer-abort.tentative.https.window.html [ Timeout Pass ] crbug.com/460799715 external/wpt/ai/writer/writer-create-available.tentative.https.window.html [ Timeout Pass ] crbug.com/460799715 external/wpt/ai/writer/writer-write-streaming.tentative.https.window.html [ Timeout Pass ] -crbug.com/459864801 external/wpt/ai/language-model/language-model-prompt-multimodal-image.tentative.https.window.html [ Timeout Pass ] -crbug.com/459864801 external/wpt/ai/language-model/language-model-prompt-multimodal-video.tentative.https.window.html [ Timeout Pass ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index 9c01dbaa..e93da371 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -2793,6 +2793,57 @@ crbug.com/492578951 virtual/unified-autoplay/external/wpt/permissions-policy/reporting/bluetooth-reporting.https.html [ Crash Failure Timeout ] # ====== New tests from wpt-importer added here ====== +crbug.com/493703183 external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-005.html [ Failure ] +crbug.com/493703183 external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-006.html [ Failure ] +crbug.com/493703183 external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-007.html [ Failure ] +crbug.com/493703183 external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-010.html [ Failure ] +crbug.com/493703182 external/wpt/permissions-policy/experimental-features/focus-without-user-activation-default-permissions-policy.https.sub.html [ Timeout ] +crbug.com/493703182 external/wpt/permissions-policy/permissions-policy-header-policy-allowed-for-all.https.sub.html [ Timeout ] +crbug.com/493703182 external/wpt/permissions-policy/permissions-policy-header-policy-allowed-for-malformed-wildcard.https.sub.html [ Timeout ] +crbug.com/493703182 external/wpt/permissions-policy/permissions-policy-header-policy-allowed-for-self.https.sub.html [ Timeout ] +crbug.com/493703182 external/wpt/permissions-policy/permissions-policy-header-policy-allowed-for-some.https.sub.html [ Timeout ] +crbug.com/493703182 external/wpt/permissions-policy/permissions-policy-header-policy-allowed-for-wildcard.https.sub.html [ Timeout ] +crbug.com/493703182 external/wpt/permissions-policy/permissions-policy-header-policy-declined.https.sub.html [ Timeout ] +crbug.com/493703182 external/wpt/permissions-policy/permissions-policy-header-policy-disallowed-for-all.https.sub.html [ Timeout ] +crbug.com/493703182 external/wpt/permissions-policy/permissions-policy-nested-header-policy-allowed-for-all.https.sub.html [ Skip Timeout ] +crbug.com/493703182 external/wpt/permissions-policy/permissions-policy-nested-header-policy-allowed-for-self.https.sub.html [ Skip Timeout ] +crbug.com/493703182 external/wpt/permissions-policy/permissions-policy-nested-header-policy-disallowed-for-all.https.sub.html [ Skip Timeout ] +crbug.com/493703182 external/wpt/permissions-policy/policy-extends-to-sandbox.html [ Timeout ] +crbug.com/493703183 virtual/css-line-clamp-lines-and-height/external/wpt/css/css-overflow/line-clamp/line-clamp-011.html [ Failure ] +crbug.com/493703183 virtual/css-line-clamp-lines-and-height/external/wpt/css/css-overflow/line-clamp/line-clamp-035.html [ Failure ] +crbug.com/493703183 virtual/css-line-clamp-lines-and-height/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-005.html [ Failure ] +crbug.com/493703183 virtual/css-line-clamp-lines-and-height/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-006.html [ Failure ] +crbug.com/493703183 virtual/css-line-clamp-lines-and-height/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-007.html [ Failure ] +crbug.com/493703183 virtual/css-line-clamp-lines-and-height/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-010.html [ Failure ] +crbug.com/493703183 virtual/css-line-clamp-lines-and-height/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-with-max-height.html [ Failure ] +crbug.com/493703183 virtual/disable-css-line-clamp-line-breaking-ellipsis/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-005.html [ Failure ] +crbug.com/493703183 virtual/disable-css-line-clamp-line-breaking-ellipsis/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-006.html [ Failure ] +crbug.com/493703183 virtual/disable-css-line-clamp-line-breaking-ellipsis/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-007.html [ Failure ] +crbug.com/493703183 virtual/disable-css-line-clamp-line-breaking-ellipsis/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-010.html [ Failure ] +crbug.com/493703183 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-011.html [ Failure ] +crbug.com/493703183 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-035.html [ Failure ] +crbug.com/493703183 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-001.html [ Failure ] +crbug.com/493703183 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-002.html [ Failure ] +crbug.com/493703183 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-003.html [ Failure ] +crbug.com/493703183 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-004.html [ Failure ] +crbug.com/493703183 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-005.html [ Failure ] +crbug.com/493703183 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-006.html [ Failure ] +crbug.com/493703183 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-007.html [ Failure ] +crbug.com/493703183 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-010.html [ Failure ] +crbug.com/493703183 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-with-max-height.html [ Failure ] +crbug.com/493703182 virtual/threaded/external/wpt/permissions-policy/experimental-features/focus-without-user-activation-default-permissions-policy.https.sub.html [ Timeout ] +crbug.com/493703182 virtual/unified-autoplay/external/wpt/permissions-policy/experimental-features/focus-without-user-activation-default-permissions-policy.https.sub.html [ Timeout ] +crbug.com/493703182 virtual/unified-autoplay/external/wpt/permissions-policy/permissions-policy-header-policy-allowed-for-all.https.sub.html [ Timeout ] +crbug.com/493703182 virtual/unified-autoplay/external/wpt/permissions-policy/permissions-policy-header-policy-allowed-for-malformed-wildcard.https.sub.html [ Timeout ] +crbug.com/493703182 virtual/unified-autoplay/external/wpt/permissions-policy/permissions-policy-header-policy-allowed-for-self.https.sub.html [ Timeout ] +crbug.com/493703182 virtual/unified-autoplay/external/wpt/permissions-policy/permissions-policy-header-policy-allowed-for-some.https.sub.html [ Timeout ] +crbug.com/493703182 virtual/unified-autoplay/external/wpt/permissions-policy/permissions-policy-header-policy-allowed-for-wildcard.https.sub.html [ Timeout ] +crbug.com/493703182 virtual/unified-autoplay/external/wpt/permissions-policy/permissions-policy-header-policy-declined.https.sub.html [ Timeout ] +crbug.com/493703182 virtual/unified-autoplay/external/wpt/permissions-policy/permissions-policy-header-policy-disallowed-for-all.https.sub.html [ Timeout ] +crbug.com/493703182 virtual/unified-autoplay/external/wpt/permissions-policy/permissions-policy-nested-header-policy-allowed-for-all.https.sub.html [ Skip Timeout ] +crbug.com/493703182 virtual/unified-autoplay/external/wpt/permissions-policy/permissions-policy-nested-header-policy-allowed-for-self.https.sub.html [ Skip Timeout ] +crbug.com/493703182 virtual/unified-autoplay/external/wpt/permissions-policy/permissions-policy-nested-header-policy-disallowed-for-all.https.sub.html [ Skip Timeout ] +crbug.com/493703182 virtual/unified-autoplay/external/wpt/permissions-policy/policy-extends-to-sandbox.html [ Timeout ] crbug.com/492610942 [ Win ] external/wpt/accelerometer/Accelerometer-disabled-by-feature-policy.https.html [ Pass Timeout ] crbug.com/492610943 external/wpt/css/css-tables/collapsed-border-background-inset.html [ Failure ] crbug.com/492633089 external/wpt/dom/events/scrolling/scrollend-event-fires-on-visual-viewport.html [ Timeout ] @@ -4072,6 +4123,8 @@ crbug.com/356955226 virtual/fedcm-accounts-push/external/wpt/fedcm/fedcm-accounts-push/fedcm-identity-discovery.tentative.sub.https.html [ Timeout ] crbug.com/356428750 external/wpt/css/css-backgrounds/background-clip/clip-text-animated-text.html [ Failure ] crbug.com/356428750 virtual/threaded/external/wpt/css/css-backgrounds/background-clip/clip-text-animated-text.html [ Failure ] +crbug.com/41385122 external/wpt/css/css-backgrounds/background-clip/clip-text-relative-child.html [ Failure ] +crbug.com/41385122 external/wpt/css/css-backgrounds/background-clip/clip-text-stacking-context-child.html [ Failure ] crbug.com/356436618 [ Mac12 ] virtual/threaded/external/wpt/css/css-backgrounds/border-image-slice-005.htm [ Failure ] crbug.com/355683658 external/wpt/css/css-align/self-alignment/block-justify-self.html [ Failure ] crbug.com/353583104 [ Win11-arm64 ] external/wpt/html/semantics/embedded-content/media-elements/preserves-pitch.html [ Timeout ] @@ -5443,8 +5496,6 @@ crbug.com/757165 [ Win ] paint/invalidation/filters/filter-repaint-accelerated-child-with-filter-child.html [ Crash Failure Pass Timeout ] crbug.com/757165 [ Win ] paint/invalidation/filters/filter-repaint-on-accelerated-layer.html [ Crash Failure Pass Timeout ] -crbug.com/769347 [ Mac ] fast/dom/inert/inert-node-is-uneditable.html [ Failure ] - crbug.com/769056 virtual/text-antialias/emoji-web-font.html [ Failure ] crbug.com/1159689 [ Mac12 ] virtual/text-antialias/emoticons.html [ Failure Pass ] crbug.com/1159689 [ Mac12-arm64 Release ] virtual/text-antialias/emoticons.html [ Failure Pass ]
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 26ba5d2..a4e8324f 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
@@ -6549,6 +6549,13 @@ {} ] ], + "chrome-bug-492735384.html": [ + "21f46c19c55c18d9f5e8f26271d6bdc02aecb0b6", + [ + null, + {} + ] + ], "viewport-unit-inline-style-crash.html": [ "4c38e18781bfdbcddce02c1cc5cd3336a7529e85", [ @@ -9649,6 +9656,13 @@ }, "scripting-1": { "the-template-element": { + "template-construction-in-inactive-document-crash.html": [ + "0e991231f5230e749d50d5c25333d584de9680fa", + [ + null, + {} + ] + ], "template-element": { "template-construction-in-inactive-document-crash.html": [ "496a47b2c58b5bde93f41d923e7117f646187442", @@ -23121,7 +23135,7 @@ ] ], "vertical-scroll-main-frame-manual.tentative.html": [ - "cda6c49abb6df5007ff83b122a5a5788fa51c60c", + "eacf69fb932002751a44ea9ee5925048b0cf0182", [ null, {} @@ -112144,6 +112158,19 @@ {} ] ], + "color-scheme-iframe-background-mismatch-opaque-cross-origin-003.sub.html": [ + "a2799215ffa847463299a823f8cf024b4785ec92", + [ + null, + [ + [ + "/css/css-color-adjust/rendering/dark-color-scheme/color-scheme-iframe-background-mismatch-opaque-cross-origin-003-ref.html", + "==" + ] + ], + {} + ] + ], "color-scheme-iframe-background-mismatch-opaque.html": [ "d984fdd245f8da340eaee3aa87bbcdef1f15e2e2", [ @@ -137495,6 +137522,19 @@ {} ] ], + "fontface-from-arraybuffer.html": [ + "24195a2a26a8f160a6e3793b8458cf820521466f", + [ + null, + [ + [ + "/css/css-font-loading/fontface-from-arraybuffer-ref.html", + "==" + ] + ], + {} + ] + ], "fontface-override-descriptors.html": [ "34506b154793caac0ca3091fa6c1a250f99e7b3c", [ @@ -154876,6 +154916,19 @@ {} ] ], + "column-fill-reverse-dense-packing-definite-size-001.html": [ + "0124ec362b02d7674047eb29cf3541a613e8ed64", + [ + null, + [ + [ + "/css/css-grid/grid-lanes/item-placement/dense-packing/column-fill-reverse-dense-packing-definite-size-001-ref.html", + "==" + ] + ], + {} + ] + ], "row-dense-packing-001.html": [ "5eb87432564c7be3058861441d3d759e9eaedec7", [ @@ -154992,6 +155045,19 @@ ], {} ] + ], + "row-fill-reverse-dense-packing-definite-size-001.html": [ + "c30f6d0c927558e8d6d65161744e18016f3742a8", + [ + null, + [ + [ + "/css/css-grid/grid-lanes/item-placement/dense-packing/row-fill-reverse-dense-packing-definite-size-001-ref.html", + "==" + ] + ], + {} + ] ] }, "flow-tolerance": { @@ -156274,6 +156340,45 @@ ] }, "item-placement": { + "column-fill-reverse-definite-size-001.html": [ + "a3a98e7b7a76716b74fa68508d072cb4b2817115", + [ + null, + [ + [ + "/css/css-grid/grid-lanes/tentative/item-placement/column-fill-reverse-definite-size-001-ref.html", + "==" + ] + ], + {} + ] + ], + "column-fill-reverse-definite-size-002.html": [ + "dedef6cc53e631991882a6a43bcebeb639abc926", + [ + null, + [ + [ + "/css/css-grid/grid-lanes/tentative/item-placement/column-fill-reverse-definite-size-002-ref.html", + "==" + ] + ], + {} + ] + ], + "column-fill-reverse-track-reverse-definite-size-001.html": [ + "dc3d27818f7abca64efea89538631d9429109d27", + [ + null, + [ + [ + "/css/css-grid/grid-lanes/tentative/item-placement/column-fill-reverse-track-reverse-definite-size-001-ref.html", + "==" + ] + ], + {} + ] + ], "column-reverse-001.html": [ "4b945b933fc4501d82537fa8b59e0edbfa42a28c", [ @@ -156404,6 +156509,45 @@ {} ] ], + "row-fill-reverse-definite-size-001.html": [ + "9070fa6fcdde37526ca21f38f8366d90b3d5914d", + [ + null, + [ + [ + "/css/css-grid/grid-lanes/tentative/item-placement/row-fill-reverse-definite-size-001-ref.html", + "==" + ] + ], + {} + ] + ], + "row-fill-reverse-definite-size-002.html": [ + "f50d93fedf45750127f332989b853ce2dc3e2ebe", + [ + null, + [ + [ + "/css/css-grid/grid-lanes/tentative/item-placement/row-fill-reverse-definite-size-002-ref.html", + "==" + ] + ], + {} + ] + ], + "row-fill-reverse-track-reverse-definite-size-001.html": [ + "75d695ad7309119fee4a09e24bc0d9e889529ebe", + [ + null, + [ + [ + "/css/css-grid/grid-lanes/tentative/item-placement/row-fill-reverse-track-reverse-definite-size-001-ref.html", + "==" + ] + ], + {} + ] + ], "row-reverse-001.html": [ "04e9743e30c8700730ffd682d06aed56e826b9b3", [ @@ -176702,6 +176846,19 @@ {} ] ], + "outside-marker-covered-by-relpos-block-link.html": [ + "25c35fd99edc449ab7c734610269e61d4401b418", + [ + null, + [ + [ + "/css/css-lists/outside-marker-covered-by-relpos-block-link-ref.html", + "==" + ] + ], + {} + ] + ], "pseudo-element-remove-update.html": [ "dea7d99662b57179d5dedcef081346f9a7fe9101", [ @@ -192079,8 +192236,8 @@ {} ] ], - "line-clamp-011.tentative.html": [ - "69effbcca17061a7519316ef097b9903fbe7968e", + "line-clamp-011.html": [ + "a409ea1970172f51dc41df7c1a4ebd4d5a20e18a", [ null, [ @@ -192391,13 +192548,13 @@ {} ] ], - "line-clamp-035.tentative.html": [ - "feb4aac618a21851ad1fb1fe8aa7a3ce80c8e045", + "line-clamp-035.html": [ + "90513d7832924707dd5d3fa61843af9c5abeda80", [ null, [ [ - "/css/css-overflow/line-clamp/reference/webkit-line-clamp-005-ref.html", + "/css/css-overflow/line-clamp/reference/line-clamp-011-ref.html", "==" ] ], @@ -193795,7 +193952,7 @@ {} ] ], - "line-clamp-with-floats-001.tentative.html": [ + "line-clamp-with-floats-001.html": [ "98bbdcb9040224c9c9df1a535ffdeb426040a3c7", [ null, @@ -193808,7 +193965,7 @@ {} ] ], - "line-clamp-with-floats-002.tentative.html": [ + "line-clamp-with-floats-002.html": [ "15379a3de3e5518505c24ed9722c0ac4541331a2", [ null, @@ -193821,7 +193978,7 @@ {} ] ], - "line-clamp-with-floats-003.tentative.html": [ + "line-clamp-with-floats-003.html": [ "c203758235130cd8e4a0c4838b6b99f8c284cd20", [ null, @@ -193834,7 +193991,7 @@ {} ] ], - "line-clamp-with-floats-004.tentative.html": [ + "line-clamp-with-floats-004.html": [ "6213130174768418c078ffc792c30b2774c5d9c6", [ null, @@ -193847,8 +194004,8 @@ {} ] ], - "line-clamp-with-floats-005.tentative.html": [ - "9689a83fa7f9e5976c2d5b71f6adc7fd0397e2cc", + "line-clamp-with-floats-005.html": [ + "81831a5e393d45dc8f535a63facbc552f12dbdba", [ null, [ @@ -193860,21 +194017,21 @@ {} ] ], - "line-clamp-with-floats-006.tentative.html": [ - "0a709bff198f3f4c35072559ab67f9892a1bf668", + "line-clamp-with-floats-006.html": [ + "c5608159f6f40880d8bcd5a1109f7844fe165c9d", [ null, [ [ - "/css/css-overflow/line-clamp/reference/line-clamp-with-floats-006-ref.html", + "/css/css-overflow/line-clamp/reference/line-clamp-with-floats-005-ref.html", "==" ] ], {} ] ], - "line-clamp-with-floats-007.tentative.html": [ - "7ee286fbf43b3d961d8a26dc0063b38523e49ad5", + "line-clamp-with-floats-007.html": [ + "b6b7e1c03a180e96646d477af142cec5a56d1832", [ null, [ @@ -193886,34 +194043,8 @@ {} ] ], - "line-clamp-with-floats-008.html": [ - "9ee8a05396d710e16b631416296a1e331c61ff72", - [ - null, - [ - [ - "/css/css-overflow/line-clamp/reference/line-clamp-with-floats-008-ref.html", - "==" - ] - ], - {} - ] - ], - "line-clamp-with-floats-009.tentative.html": [ - "f25ac381c09d8766f1fd8efe9ec8b677a55b2988", - [ - null, - [ - [ - "/css/css-overflow/line-clamp/reference/webkit-line-clamp-005-ref.html", - "==" - ] - ], - {} - ] - ], - "line-clamp-with-floats-010.tentative.html": [ - "a00ff60171258aee2aba3ac98847e5756fbc26eb", + "line-clamp-with-floats-010.html": [ + "c74f75d9e66c892af5cf5659cb41339e1ac0ce3d", [ null, [ @@ -194484,19 +194615,6 @@ {} ] ], - "webkit-line-clamp-044.html": [ - "981e09b466c766d0466f7ba072157d44c19afaaf", - [ - null, - [ - [ - "/css/css-overflow/line-clamp/reference/webkit-line-clamp-044-ref.html", - "==" - ] - ], - {} - ] - ], "webkit-line-clamp-045.html": [ "0b5a1734a0bdebcaf661ea850530564ea1c0991d", [ @@ -194523,19 +194641,6 @@ {} ] ], - "webkit-line-clamp-047.html": [ - "cb66eb714c510579f16b101010188ca6b22a32ba", - [ - null, - [ - [ - "/css/css-overflow/line-clamp/reference/webkit-line-clamp-047-ref.html", - "==" - ] - ], - {} - ] - ], "webkit-line-clamp-048.html": [ "e4a01af252782a5506c4345e84aa8e7bc235bbda", [ @@ -194666,13 +194771,13 @@ {} ] ], - "webkit-line-clamp-with-max-height.tentative.html": [ - "410fbef9c751582f8a05bae70b898c30ab9c68ee", + "webkit-line-clamp-with-max-height.html": [ + "e6be3293f3f1a28a04e1fb6f463ae137998fb21e", [ null, [ [ - "/css/css-overflow/line-clamp/reference/webkit-line-clamp-005-ref.html", + "/css/css-overflow/line-clamp/reference/line-clamp-011-ref.html", "==" ] ], @@ -201498,6 +201603,19 @@ {} ] ], + "position-sticky-on-minimum-scale.html": [ + "5fca1734373b489ae99ebda54fa81100fa8ec502", + [ + null, + [ + [ + "/css/css-position/sticky/position-sticky-on-minimum-scale-ref.html", + "==" + ] + ], + {} + ] + ], "position-sticky-overflow-clip-container.html": [ "63356349afecd3f2b25e080186ba509eb3980cab", [ @@ -328031,7 +328149,7 @@ ] ], "select-picker-pseudo-target-text.html": [ - "02159e7e76fd65e0682d22a91773bab782756423", + "8e008fc45063dcb76ff069d4c24cb6d72e6a27b3", [ null, [ @@ -352145,9 +352263,15 @@ [] ], "WEB_FEATURES.yml": [ - "dfbb455e6b6bd7fbe6bf21cdcc08ff0c9cc87de0", + "65294d5d2dc5a870a1c292245cb10891fb915002", [] ], + "crashtests": { + "WEB_FEATURES.yml": [ + "dfbb455e6b6bd7fbe6bf21cdcc08ff0c9cc87de0", + [] + ] + }, "resources": { "cross-origin-helper-frame.html": [ "997c5a2b72bafcad3421ccb48e48e323de6ef6f0", @@ -352250,7 +352374,7 @@ ], "derive_bits_keys": { "argon2.js": [ - "f1609403d623fa28b4b9adfe37f0ab7a750d127e", + "de3b4b5920df273c383b8909cce4f1c56bfac6fa", [] ], "argon2.tentative.https.any-expected.txt": [ @@ -352262,11 +352386,11 @@ [] ], "argon2_vectors.js": [ - "9b9acda5f42d3ac859993febcafd96ee0fbf1377", + "93d26b5eb969808caee163eec76b4ac93d10bf41", [] ], "cfrg_curves_bits.js": [ - "8ab9db7bf71318b6b030f32ab7b8bd2554efa3e1", + "1406e8bf0a19289a47aa9d80b8a147fa67cc5e4e", [] ], "cfrg_curves_bits_curve448.tentative.https.any-expected.txt": [ @@ -352282,7 +352406,7 @@ [] ], "cfrg_curves_keys.js": [ - "62f9e00aa338468f1a33a5fe91931378a4a72cad", + "cefc45ac6929033beae7c9c6edaefb98d4babf38", [] ], "cfrg_curves_keys_curve448.tentative.https.any-expected.txt": [ @@ -352310,11 +352434,11 @@ [] ], "ecdh_bits.js": [ - "36b29c20a282abb13aaf5ab3308db81fe7a48c89", + "8e79909020d398c6c04c2f4497c59e5f2e60180b", [] ], "ecdh_keys.js": [ - "fce76f185530ac481caa2eadde9e273a0bcd3be4", + "8c3d2aeb5a497680a81f7b242531cedfdec88613", [] ], "hkdf.https.any.worker_1-1000-expected.txt": [ @@ -352350,7 +352474,7 @@ [] ], "hkdf.js": [ - "0384f88ec73e4394ed52f7743947061d87cf3495", + "08e8c0c8974617ffa03ac33f8c3bed73806b632f", [] ], "hkdf_vectors.js": [ @@ -352430,7 +352554,7 @@ [] ], "pbkdf2.js": [ - "38cf3b1bfe952c37ca08477bc115c89de5a9a660", + "4d5b0137a387c856cbcb3786ea59b43a62d2cfe8", [] ], "pbkdf2_vectors.js": [ @@ -352455,6 +352579,14 @@ "7ef9d00ebaf6d9a8b30ea71cd55ab948836f10f3", [] ], + "kangarootwelve.tentative.https.any-expected.txt": [ + "10db00ec4b8e4bf229392a2ffd061d644a0a00c1", + [] + ], + "kangarootwelve.tentative.https.any.worker-expected.txt": [ + "10db00ec4b8e4bf229392a2ffd061d644a0a00c1", + [] + ], "sha3.tentative.https.any-expected.txt": [ "92f825b25b81dd1dee80afba8425814e0c1e24f1", [] @@ -352462,27 +352594,31 @@ "sha3.tentative.https.any.worker-expected.txt": [ "92f825b25b81dd1dee80afba8425814e0c1e24f1", [] + ], + "turboshake.tentative.https.any-expected.txt": [ + "7fe54c9c617b52cfb56579cd5511ae1342a22138", + [] + ], + "turboshake.tentative.https.any.worker-expected.txt": [ + "7fe54c9c617b52cfb56579cd5511ae1342a22138", + [] ] }, "encap_decap": { "encap_decap_bits.tentative.https.any-expected.txt": [ - "a7484b80c54af803836228f9ed1bae821da916a0", + "77354c5255fe3cfc8e112cc6cdaeb2271206d215", [] ], "encap_decap_bits.tentative.https.any.worker-expected.txt": [ - "a7484b80c54af803836228f9ed1bae821da916a0", + "77354c5255fe3cfc8e112cc6cdaeb2271206d215", [] ], "encap_decap_keys.tentative.https.any-expected.txt": [ - "35d7bed6f907cbf036580f87e078fe413082cdea", + "737aa0c13803a3e72d50509166fd43af1928bfe0", [] ], "encap_decap_keys.tentative.https.any.worker-expected.txt": [ - "35d7bed6f907cbf036580f87e078fe413082cdea", - [] - ], - "ml_kem_encap_decap.js": [ - "9167efa63f0ca3f349c781fb55d70e80ef9eeb98", + "737aa0c13803a3e72d50509166fd43af1928bfe0", [] ], "ml_kem_vectors.js": [ @@ -352492,7 +352628,7 @@ }, "encrypt_decrypt": { "aes.js": [ - "456f66423419c879a470f78afd9f6ec2a92b0b32", + "879a6efe257e496acb3f1c4af3ffda925a382e16", [] ], "aes_cbc.https.any-expected.txt": [ @@ -352544,7 +352680,7 @@ [] ], "aes_gcm_vectors.js": [ - "965fe9564d461925df00ffc465f161e03436f817", + "f0d88a93620f0f9d1fc4b4b6d4c49367782c91c2", [] ], "aes_ocb.tentative.https.any-expected.txt": [ @@ -352572,7 +352708,7 @@ [] ], "rsa.js": [ - "6f585cbe1ffcef1218425570bde86f785a06e9b3", + "071c086b3c4dfaeb1af21cd07e7831f2253324ab", [] ], "rsa_oaep.https.any-expected.txt": [ @@ -352816,7 +352952,7 @@ [] ], "ML-DSA_importKey.js": [ - "3723b321e542d52ffacb6042d3fd7e7788aa11d8", + "d9257ac698250529a0475800ffac9045e3d84c82", [] ], "ML-DSA_importKey.tentative.https.any-expected.txt": [ @@ -352832,7 +352968,7 @@ [] ], "ML-KEM_importKey.js": [ - "c264a163148438275d3d7f9ac4554dc0d7a679e4", + "ad2f75048556e4e3f0e1618d5a1afda642b411c7", [] ], "ML-KEM_importKey.tentative.https.any-expected.txt": [ @@ -352856,7 +352992,7 @@ [] ], "okp_importKey.js": [ - "8627f85e466199453efb59109e2ba1d7eb025ff8", + "665c9c1d9a3c4f387db18d136c99ab8c0feb9224", [] ], "okp_importKey_Ed448.tentative.https.any-expected.txt": [ @@ -352908,7 +353044,7 @@ [] ], "symmetric_importKey.js": [ - "07f367cab0133372a29ec8859ee912ee05e69fa6", + "8633af5279caa19eebdf57cae2f4f83bb5ff7efd", [] ] }, @@ -352922,7 +353058,7 @@ [] ], "ecdsa.js": [ - "b2e0bf606b5feecd29f985fcfb801f4eb560c3e0", + "cc13b1bd9c3cae79afb1b170726ea541752e44ba", [] ], "ecdsa_vectors.js": [ @@ -352930,7 +353066,7 @@ [] ], "eddsa.js": [ - "5ff6f21150c2723b452dff968db075809834b170", + "77961566d9a60202cadbd66b1d5e21973cedfdc6", [] ], "eddsa_curve25519.https.any-expected.txt": [ @@ -352974,7 +353110,7 @@ [] ], "hmac.js": [ - "8a099f4ce9377aa8a630d26bfe6df4d59a0ce835", + "929d9464e171cbaa37f24fa8ccefa0a0d79d7920", [] ], "hmac_vectors.js": [ @@ -352982,7 +353118,7 @@ [] ], "kmac.js": [ - "f3cc9b4cd1dbfdb68ffd398d863873eb08f718e8", + "d9d82d150b39335c5f1428549c652626176a6e4c", [] ], "kmac.tentative.https.any-expected.txt": [ @@ -352994,11 +353130,11 @@ [] ], "kmac_vectors.js": [ - "39d0efe71ba3e28d1ddc1bfd66683b9392c3f101", + "6b35cab168c9c674dbdaf3155c4dfb828c82e758", [] ], "mldsa.js": [ - "9c654685c74f310b1d68b7a4910ee298c6ab0830", + "10879273c1c3f4e16faa576686f55ff8717ae9a4", [] ], "mldsa.tentative.https.any-expected.txt": [ @@ -353014,7 +353150,7 @@ [] ], "rsa.js": [ - "09c7ceb767510790199a468824937a7ea01fd2ea", + "667f5d2793e48c07fa423113fa4f49ef6ae8fc61", [] ], "rsa_pkcs.https.any-expected.txt": [ @@ -353058,7 +353194,7 @@ }, "util": { "helpers.js": [ - "dbcc5053b1313aa35ea40c7601ec391841e60f9f", + "3d44b7a7550e86eff62155406b62114d1c60b3ca", [] ], "worker-report-crypto-subtle-presence.js": [ @@ -353074,46 +353210,14 @@ } }, "accelerometer": { - "Accelerometer-disabled-by-feature-policy.https-expected.txt": [ - "2cd00b44472acb5c6abaf55cab51afc0b1dc2418", - [] - ], - "Accelerometer-disabled-by-feature-policy.https.html.headers": [ - "beea0422d925567f8e9cab38ea56d17315d3b2fd", - [] - ], "Accelerometer-disabled-by-permissions-policy.https.html.headers": [ "93893d8130f2535fe32976f6ccbf3e29e892a444", [] ], - "Accelerometer-enabled-by-feature-policy-attribute-redirect-on-load.https-expected.txt": [ - "324f766804f2a64635191645416edbffd45e653b", - [] - ], - "Accelerometer-enabled-by-feature-policy-attribute.https-expected.txt": [ - "afe7b978ecc9c43f54b117e147864c261687b70d", - [] - ], - "Accelerometer-enabled-by-feature-policy.https-expected.txt": [ - "27737bd903d8d69b7c92c2945609d0b6b669ff2f", - [] - ], - "Accelerometer-enabled-by-feature-policy.https.html.headers": [ - "5df2754abf5d4119175074fd8e6334eb069c4e97", - [] - ], "Accelerometer-enabled-by-permissions-policy.https.html.headers": [ "76bdd805109bbdc744b2263689e79831246d7d80", [] ], - "Accelerometer-enabled-on-self-origin-by-feature-policy.https-expected.txt": [ - "9114c3ac59f65c3db3c9e51164c6f465725ff0a7", - [] - ], - "Accelerometer-enabled-on-self-origin-by-feature-policy.https.html.headers": [ - "cdefed843e31b2accdb425e42fe051dcae790e96", - [] - ], "Accelerometer-enabled-on-self-origin-by-permissions-policy.https.html.headers": [ "6d837e98bb8edd5734522ac10b401bb140e59f07", [] @@ -353140,7 +353244,7 @@ ], "resources": { "sensor-data.js": [ - "6f56cfdbeb6dfff65ccdbf9b6b49474c021c6ba7", + "ca47d69169b50443f8d6625987b7942b1945abad", [] ] } @@ -353416,7 +353520,7 @@ ], "resources": { "sensor-data.js": [ - "c1f7bd5ca0f7fb2722c17433b0dd1b0810223324", + "ef91018d80b873478c0984d61836e2a4174384e5", [] ] } @@ -354969,18 +355073,30 @@ "4d4739028d3d243db6d302fa7e56e25b6c155c89", [] ], - "feature-policy-navigation": { + "feature-policy.sub.https.html.headers": [ + "6e6b89e923040e68b39011017eb46036afc72dd4", + [] + ], + "permissions-policy-navigation": { "__dir__.headers": [ "4d4739028d3d243db6d302fa7e56e25b6c155c89", [] ], - "feature-policy.https.html.headers": [ + "no-permissions-policy.https-expected.txt": [ + "7d1ab53399191d31adcb7711ec652052a4c9b55f", + [] + ], + "permissions-policy.https-expected.txt": [ + "7d1ab53399191d31adcb7711ec652052a4c9b55f", + [] + ], + "permissions-policy.https.html.headers": [ "11bbceff0acba6f14a04c10f2da30a2122c7b311", [] ] }, - "feature-policy.sub.https.html.headers": [ - "6e6b89e923040e68b39011017eb46036afc72dd4", + "permissions-policy.sub.https-expected.txt": [ + "b323165e0ed062418011cf956b0ba758e8aea451", [] ] }, @@ -355070,14 +355186,6 @@ "876f025f3eabd51759aed081a8fd3cce505004e9", [] ], - "feature-policy-with-cross-origin-subresource.html": [ - "f7e1a767b46c435e61d43609e39c0f1fd4a99bae", - [] - ], - "feature-policy-with-cross-origin-subresource.html.headers": [ - "4738714fb493374d67789c87bbaa0d8cd99286e8", - [] - ], "http-equiv-accept-ch.html": [ "561cae49cabd3add8f6c9953e213f80a6cedf5d6", [] @@ -355101,6 +355209,14 @@ "no-accept-ch.html.headers": [ "cb762eff806849df46dc758ef7b98b63f27f54c9", [] + ], + "permissions-policy-with-cross-origin-subresource.html": [ + "f7e1a767b46c435e61d43609e39c0f1fd4a99bae", + [] + ], + "permissions-policy-with-cross-origin-subresource.html.headers": [ + "4738714fb493374d67789c87bbaa0d8cd99286e8", + [] ] }, "same-origin-subresource-redirect-opted-in.https.html.headers": [ @@ -355204,6 +355320,10 @@ ] } }, + "http-equiv-accept-ch-iframe.https-expected.txt": [ + "7d1ab53399191d31adcb7711ec652052a4c9b55f", + [] + ], "http-equiv-accept-ch-merge.https.html.headers": [ "34edb7b82b9657e0beaf9b1669d0854d365770ed", [] @@ -355284,6 +355404,10 @@ ] } }, + "meta-equiv-delegate-ch-iframe.https-expected.txt": [ + "7d1ab53399191d31adcb7711ec652052a4c9b55f", + [] + ], "meta-equiv-delegate-ch-merge.https.html.headers": [ "34edb7b82b9657e0beaf9b1669d0854d365770ed", [] @@ -356552,6 +356676,10 @@ "compute-pressure-disabled-by-permissions-policy.https.html.headers": [ "2e9f2ecce0e640217b68409ba18a7d4af822d287", [] + ], + "compute-pressure-supported-by-permissions-policy-expected.txt": [ + "a9f22b3b30d9a4d1a95f00c6cc2d8a157b85e6df", + [] ] }, "resources": { @@ -359796,10 +359924,6 @@ "7a3e72a90a14f14fea560cc72be9ab6aafb7b039", [] ], - "idlharness.https.window-expected.txt": [ - "7bf9206f3170c1caac15a30fe7dc6d4067a7ce57", - [] - ], "passwordcredential-framed-get.sub.https-expected.txt": [ "7a3e72a90a14f14fea560cc72be9ab6aafb7b039", [] @@ -371872,6 +371996,10 @@ "2ed0d9b960034469c02bf30d4800b75e955b47b3", [] ], + "color-computed-color-mix-function-expected.txt": [ + "74d9c244a2c1b8e2f4ffbae743a617d26c196bcd", + [] + ], "color-valid-color-function-expected.txt": [ "907bbd37c01420d5354b1e9e90cd93050887ed11", [] @@ -371880,6 +372008,10 @@ "56579feafbf4a7d9cdfc62cbc86954ffaf051f2e", [] ], + "color-valid-color-mix-function-expected.txt": [ + "5064781d0beb9e6048d0235107df53148ad456db", + [] + ], "opacity-valid-expected.txt": [ "37db89c021da9c993e2e4322d296e38bb10f90d4", [] @@ -372229,6 +372361,10 @@ "79c882fbda82906c1446a14f6eef2ac54cdb2912", [] ], + "color-scheme-iframe-background-mismatch-opaque-cross-origin-003-ref.html": [ + "38463211e9788849c561d345360130d34cd44b6b", + [] + ], "color-scheme-iframe-background-mismatch-used-preferred-ref.html": [ "4eb06f35fd269617d9789f85be8e6420dcbfce53", [] @@ -372282,6 +372418,10 @@ "11f88db4a0b3e94d620b5a92314c88040210cfae", [] ], + "light-frame-empty.html": [ + "7f4da1e30af93712be4cd22f479c6c8cc2c3f1d5", + [] + ], "light-frame.html": [ "c8c587f787c671dc1262bd089d6c00a9d9ef9149", [] @@ -377351,6 +377491,10 @@ "513867b3503042886e51312bcfec20967f7384d4", [] ], + "fontface-from-arraybuffer-ref.html": [ + "bd1289e785d2d3ccffc53a48fb7e86254e4ea667", + [] + ], "fontface-override-descriptors-ref.html": [ "a08e7e97e02467a38062419a002013ebfa9c9e39", [] @@ -387772,6 +387916,10 @@ "024b1fa997b2e50e0bf90312922d957d2066764d", [] ], + "column-fill-reverse-dense-packing-definite-size-001-ref.html": [ + "d791d90653b680f0b3f642e0b7b69585dff9d47d", + [] + ], "row-dense-packing-001-ref.html": [ "eab73ed8e4857063f526e1b877a90e68f96d3c47", [] @@ -387807,6 +387955,10 @@ "row-dense-packing-multi-span-005-ref.html": [ "6d3592b9d07385c0420e83d19a456e2219f3dd0d", [] + ], + "row-fill-reverse-dense-packing-definite-size-001-ref.html": [ + "1dde7d215ca34e6644c1e6cbcec497646b4779b2", + [] ] }, "flow-tolerance": { @@ -388220,6 +388372,18 @@ ] }, "item-placement": { + "column-fill-reverse-definite-size-001-ref.html": [ + "42d87e4d361aa0fd72d2774f23c9bb8480f70e36", + [] + ], + "column-fill-reverse-definite-size-002-ref.html": [ + "29a0bc1dccaded0b82732895fee0e7c630f36526", + [] + ], + "column-fill-reverse-track-reverse-definite-size-001-ref.html": [ + "f4ef0ecf8095cc2702bc59bd84cf1328686edb3f", + [] + ], "column-reverse-001-ref.html": [ "e62f5a991edbc2770cad1560228fecef9b53f1d4", [] @@ -388260,6 +388424,18 @@ "301bfff6b58de1b25835b61919ab2607a722ddb8", [] ], + "row-fill-reverse-definite-size-001-ref.html": [ + "1de6dad16210cd8a5ddb37345a7f674d4be209ea", + [] + ], + "row-fill-reverse-definite-size-002-ref.html": [ + "b5a2df9f41816ba4d832ac552b7670a0de0645f3", + [] + ], + "row-fill-reverse-track-reverse-definite-size-001-ref.html": [ + "ed9080bb1af4cfdda0b22901d634b13cc0237e0d", + [] + ], "row-reverse-001-ref.html": [ "809aa4d551b247f5bd546cd8c176eef34420a70b", [] @@ -389250,9 +389426,15 @@ [] ], "WEB_FEATURES.yml": [ - "0ce5201312974300d33d2c95171640f60b1bbc0e", + "3f486ebbf9eba210abd956022f56bed2ee759b89", [] ], + "crashtests": { + "WEB_FEATURES.yml": [ + "0ce5201312974300d33d2c95171640f60b1bbc0e", + [] + ] + }, "highlight-image-notref.html": [ "0f4e21fc3d679c197b2f51ce8ba96c3eec3addcf", [] @@ -389286,6 +389468,10 @@ [] ], "painting": { + "WEB_FEATURES.yml": [ + "0ce5201312974300d33d2c95171640f60b1bbc0e", + [] + ], "css-highlight-painting-underline-offset-001-ref.html": [ "3d01bccf55dd9c20e361551bc924d5c9353c503e", [] @@ -392251,6 +392437,10 @@ "a10bc17899f9cfaa938d04d198598c4fc82fe3ca", [] ], + "outside-marker-covered-by-relpos-block-link-ref.html": [ + "d22d01852e2e1562456d472f1ccde38818366cbb", + [] + ], "parsing": { "WEB_FEATURES.yml": [ "3f10988471056ffe09f780431c26053d8e53d9d7", @@ -393498,7 +393688,7 @@ [] ], "WEB_FEATURES.yml": [ - "9f4475fa7b8492cd89af4b44bdcb1b2a3fbe1480", + "c0158be949b0ee8394ce368e9fc86fb814162ccb", [] ], "abspos-containing-block-outside-spanner-ref.html": [ @@ -394890,7 +395080,7 @@ [] ], "line-clamp-011-ref.html": [ - "02ef71d56193c97f8662f1ddd81633181deaf7b5", + "d318a3e662f8476d13065bb44b765019a6b13a7a", [] ], "line-clamp-012-ref.html": [ @@ -395130,23 +395320,15 @@ [] ], "line-clamp-with-floats-005-ref.html": [ - "d20d6c53ddee3de2fe12ea1927eb3182a0f55201", - [] - ], - "line-clamp-with-floats-006-ref.html": [ - "9288c4e36f924c4ab80bb9ad368b87a3a2d01720", + "e3ebd7baac6de1d93aac6d4dc5852fbcb6b924b2", [] ], "line-clamp-with-floats-007-ref.html": [ - "6d5390246b4d28365a4e8f238bd02f4fe6be9c21", - [] - ], - "line-clamp-with-floats-008-ref.html": [ - "50b3d53900e21d7bf031fd25d69c80f174bca7c2", + "56a74d9349277f63b6beb88f7e80ad78f643b705", [] ], "line-clamp-with-floats-010-ref.html": [ - "12b8cdc441a64fb4e1a6249ee8aea640c66b82b5", + "d4fbf4b4dbf2f54e348dd93dbc947e14167b4c4c", [] ], "line-clamp-with-text-overflow-string-003-ref.html": [ @@ -397600,6 +397782,10 @@ "36fabc384514f3e2f2d7a8d7c60bb00044d24f2f", [] ], + "position-sticky-on-minimum-scale-ref.html": [ + "0a030b0f77f14ff89e2951ed205e77712193cbbe", + [] + ], "position-sticky-overflow-clip-container-ref.html": [ "2a29b435a7ee5e53b5294bac40314847aec903ca", [] @@ -397787,6 +397973,10 @@ [] ] }, + "register-property-syntax-parsing-expected.txt": [ + "e29a1423db9809a7859048adf73cc1fbb2171032", + [] + ], "registered-property-change-style-002-ref.html": [ "758e769d7821fa55b82e339883f1f9c4d4f0d5e7", [] @@ -409243,7 +409433,7 @@ [] ], "helper.js": [ - "0ccfe2648ea297fb55360bfa4e47e371a34a7168", + "d8a13f09fae42164de63247a8901f399be5035fc", [] ], "import-green.css": [ @@ -409538,7 +409728,7 @@ [] ], "container-name-expected.txt": [ - "c272ee2f0649e3de02444927fdbf92b8f0f74428", + "054c55386dfa71755ca643286df97fd70cb40031", [] ], "dominant-baseline-expected.txt": [ @@ -413377,7 +413567,7 @@ ] }, "svg-computed-style-expected.txt": [ - "80eabe24bee6421b99f6ae0010c5b0029e14f4dc", + "84efd27f126c8d7d45c5ca7c4633207dc616d9f8", [] ], "svg-font-relative-units-ref.html": [ @@ -416532,7 +416722,11 @@ [] ], "scrollParent-expected.txt": [ - "a2a49a337d18b7bc94d2bd297c4c3c4f69e21cad", + "e3dd709b2ff0bc13607eb9b7a995b10f3efdbfb6", + [] + ], + "scrollParent-quirks-mode-expected.txt": [ + "5103768eec6972a778ec44b3fb730902c173f642", [] ], "scrollParent-shadow-tree-expected.txt": [ @@ -418979,7 +419173,7 @@ }, "parsing": { "WEB_FEATURES.yml": [ - "a9f7cca7bb0ca9191398e221f29dc7db36db58ba", + "dc908b1ffad5a4846d68cd5904fa7a2f49935103", [] ], "invalid-pseudos-expected.txt": [ @@ -419838,10 +420032,6 @@ "4591eb078b58e9394b9fc277f767dd93586afed6", [] ], - "digital-credentials-static-methods.tentative.https-expected.txt": [ - "aeab0380048a500c11353983a09973938c019b38", - [] - ], "get-enabled-on-self-origin-by-permissions-policy.https.sub.html.headers": [ "1207d9e29a111a46b920d27dd3188bae1e6cf8f4", [] @@ -420780,7 +420970,7 @@ [] ], "Document-createEvent.https-expected.txt": [ - "89d17b058114998bcb4ee6572fdf3754cf21bb1c", + "fc72377c2ed8254e0027d9e62c5ecfaed9508ae4", [] ], "Document-createEvent.js": [ @@ -424571,22 +424761,6 @@ "e8298197cbedc4c41bcde849e478cbe175b6cec6", [] ], - "client-hints-meta-iframe-inner.sub.https.html": [ - "a195b2827e4c297911bed31e813624d2cb7f8a08", - [] - ], - "client-hints-meta-iframe-inner.sub.https.html.headers": [ - "b7952e5d05993668ac3260f562a56eaa16776c55", - [] - ], - "client-hints-meta-inner.sub.https.html": [ - "6f215d04a8c6b96750294abc91038f7bd7318a5e", - [] - ], - "client-hints-meta-inner.sub.https.html.headers": [ - "afe7b4f317dfacad8c25661dbe4dd2bf07b5b86e", - [] - ], "close.html": [ "7fd946d6ff9c23dbb0243b60ef59cd0d6df78467", [] @@ -428112,6 +428286,10 @@ "local-fonts-disabled-by-permissions-policy.https.sub.html.headers": [ "f52d4e0d72161c09f53b1a4593716350eede97ce", [] + ], + "local-fonts-supported-by-permissions-policy-expected.txt": [ + "1a120ef24f9ad66f6245fdafca1ccbda1757109e", + [] ] }, "resources": { @@ -429526,10 +429704,6 @@ "7fba254227aa442428deb11c684eb2112c98e86a", [] ], - "feature-policy-gamepad.html": [ - "2747a04b34f427b4a27a536dcfcdeae800d652b0", - [] - ], "gamepad-supported-by-permissions-policy-expected.txt": [ "b8a985f84c95bfd3e40e912c02c9fdef63c5e0e5", [] @@ -429545,6 +429719,10 @@ "not-fully-active-expected.txt": [ "684e54b28a52ab03586fe2f24213b64b26f3db43", [] + ], + "permissions-policy-gamepad.html": [ + "2747a04b34f427b4a27a536dcfcdeae800d652b0", + [] ] }, "generic-sensor": { @@ -429564,21 +429742,21 @@ "232c8a7cf0375ac777146464dd7d99087e7611e6", [] ], - "generic-sensor-feature-policy-test.sub.js": [ - "b4958a3e8d40cce141c6e00a197d14ddb32917ff", - [] - ], "generic-sensor-iframe-tests.sub.js": [ "540a99da7befa3438efef3c503bc87eb119663b4", [] ], + "generic-sensor-permissions-policy-test.sub.js": [ + "b4958a3e8d40cce141c6e00a197d14ddb32917ff", + [] + ], "generic-sensor-tests.js": [ - "894fc7d2ed0b94985ef74d172d11c8b2e6c18f3e", + "555896fe50af2121cdb5e2514c9742c6ff3c33de", [] ], "resources": { "generic-sensor-helpers.js": [ - "146f4292ade4bf8fd965991c237a766b16cad84b", + "c135ea54c2e26a28e214865e55c0d377aa943047", [] ], "iframe_sensor_handler.html": [ @@ -429728,46 +429906,14 @@ "22cfa46b2f5ffb1fa3db78d07e69585ff3c48e8d", [] ], - "Gyroscope-disabled-by-feature-policy.https-expected.txt": [ - "61adf8f30cda78df83be4d21b48da7428de2317b", - [] - ], - "Gyroscope-disabled-by-feature-policy.https.html.headers": [ - "3d91d5840be655ce477c46b3456b2fbe9cd3a3a2", - [] - ], "Gyroscope-disabled-by-permissions-policy.https.html.headers": [ "2986400daee2738d735c4a3a323122538d4496d7", [] ], - "Gyroscope-enabled-by-feature-policy-attribute-redirect-on-load.https-expected.txt": [ - "2a100349c0f9ee4e5eb4942102ff8cad811f8e08", - [] - ], - "Gyroscope-enabled-by-feature-policy-attribute.https-expected.txt": [ - "83e406dc2b44c416d3d3b61abe60c167e1a49474", - [] - ], - "Gyroscope-enabled-by-feature-policy.https-expected.txt": [ - "390cd8e7850f79d9c285d3e19ff5016ab5d3e18f", - [] - ], - "Gyroscope-enabled-by-feature-policy.https.html.headers": [ - "0fd938b4aa9d7597f5c41c5d5b9ebbca7017b2f3", - [] - ], "Gyroscope-enabled-by-permissions-policy.https.html.headers": [ "49adf0a775465b5f6258c7070891f1b31b3ba14c", [] ], - "Gyroscope-enabled-on-self-origin-by-feature-policy.https-expected.txt": [ - "4c5275757e994c1e87443c95f663acfe7e769837", - [] - ], - "Gyroscope-enabled-on-self-origin-by-feature-policy.https.html.headers": [ - "7cf4fd8f6bd8a3bdb62a198f9802cf4f76b85ddc", - [] - ], "Gyroscope-enabled-on-self-origin-by-permissions-policy.https.html.headers": [ "68b8641d864184486d394250f1146f79b05bb4b2", [] @@ -429790,7 +429936,7 @@ ], "resources": { "sensor-data.js": [ - "409ffef9a1750c4b058bafae9898e72bd9d59624", + "9b25665f006eb194d5864d03938679c2aebe7cdd", [] ] } @@ -430676,7 +430822,13 @@ "navigate-helpers.js": [ "7a9adeb3d2e6a0f6c75a37624579a594c6286cf6", [] - ] + ], + "resources": { + "scroll-restore-on-reload-non-ascii-fragment-target.html": [ + "94f39233acc9fdf6a4ce8e0b5e2f9af11de08849", + [] + ] + } }, "unloading-documents": { "004-expected.txt": [ @@ -431157,10 +431309,6 @@ "a3ffdd005afadb784b1b64a12caa190a66271018", [] ], - "location-ancestor-origins-new-object-expected.txt": [ - "8a76abdaf3dd89309c27ae097ed190b058caa01b", - [] - ], "location-ancestor-origins-referrerpolicy-snapshot-expected.txt": [ "0953c0381bf0066b6ab31d6ef54d7b61d062bd24", [] @@ -435468,7 +435616,7 @@ [] ], "text.yaml": [ - "d4e4d5c47eba07c08e558a95340661666086fac7", + "4282c3db14537d5903c0f5d022415e93c42d07af", [] ], "the-canvas-state.yaml": [ @@ -436874,7 +437022,7 @@ [] ], "elements-embedded.js": [ - "747422a540a736a63a4d7e8518742314a5000f4d", + "255cf2b46598974a26ca07005372c9557c106e95", [] ], "elements-forms-weekmonth.js": [ @@ -436967,10 +437115,6 @@ } } }, - "reflection-embedded-expected.txt": [ - "a4d8a278d476af861d8964a610239c6b0288ff7d", - [] - ], "reflection-forms-expected.txt": [ "a22f7c0a0f10b6a4c38fce4b67629930b835ec65", [] @@ -442552,10 +442696,6 @@ "WEB_FEATURES.yml": [ "fe6d907b2d3200323eecb6ae86e6dda52334eef5", [] - ], - "createEvent-expected.txt": [ - "a7bf319bae3392ec5392a2cd560360214c9c37d5", - [] ] } }, @@ -443160,7 +443300,7 @@ [] ], "WEB_FEATURES.yml": [ - "7cae7ee081d34abe09cbb144ce404cc758b6a907", + "ec2f814c5b3b893d040bfd207c80f825b4018499", [] ], "change_child.html": [ @@ -443530,7 +443670,7 @@ [] ], "WEB_FEATURES.yml": [ - "c87bd96a4cc7816171ba73824ffe662d66974f82", + "837d82637fcbd974ad112147c9869ee6e7a878f3", [] ], "animated-image-update-ref.tentative.html": [ @@ -445762,10 +445902,6 @@ "9ca5322ced711000beda8dd7cf834a15418dc16c", [] ], - "148-expected.txt": [ - "ba5676d67aa69e871229275fac8498b122fde96a", - [] - ], "WEB_FEATURES.yml": [ "fff8d90a20c7d2639d4f3d7c2b073ca89080e1b1", [] @@ -447614,26 +447750,6 @@ "e88aae9e4db26e467cde9bd734f5ce4a81d48395", [] ], - "html5lib_innerHTML_adoption01-expected.txt": [ - "88d5d8c50a7d61a81dc17472c057f17203fd4399", - [] - ], - "html5lib_innerHTML_webkit02-expected.txt": [ - "df9f317c256129c22732f3cf18801226f1fa17cf", - [] - ], - "html5lib_webkit02_run_type=uri-expected.txt": [ - "683a5d4b347b517051ed247a9794e88d70de18e7", - [] - ], - "html5lib_webkit02_run_type=write-expected.txt": [ - "683a5d4b347b517051ed247a9794e88d70de18e7", - [] - ], - "html5lib_webkit02_run_type=write_single-expected.txt": [ - "683a5d4b347b517051ed247a9794e88d70de18e7", - [] - ], "inhead-noscript-head-expected.txt": [ "9b05679a190f8260ad0dc6870f41e0ee10813fb6", [] @@ -450138,7 +450254,7 @@ ], "resources": { "idle-detection-allowed-by-permissions-policy-worker.js": [ - "1fe410ed114ac09df4873ea661a038a7b3faec87", + "1c45c30c13a150d733417ede3707abd9d381282c", [] ], "idle-detection-disabled-by-permissions-policy-worker.js": [ @@ -453412,6 +453528,10 @@ "fbd4cc58df949323199f8832a72592f6e00d8b5f", [] ], + "broken-image-icon-expected.txt": [ + "177669c10aeab479014e191202d3fc86659da984", + [] + ], "resources": { "iframe-stores-entry.html": [ "cd600254805570deab8447ea843657d7f268b7c5", @@ -453484,7 +453604,7 @@ } }, "lint.ignore": [ - "a7c03c52572fefc264bb0d141633172c0b462bc9", + "4620815743ae3313f5af0a04075b79c481ecb002", [] ], "loading": { @@ -453860,46 +453980,14 @@ "9193c0d4590c36fe0c5efc3d7eeca8205c434ed5", [] ], - "Magnetometer-disabled-by-feature-policy.https-expected.txt": [ - "1f265cdc180ec0c4a0a53d319611b345bbf660a4", - [] - ], - "Magnetometer-disabled-by-feature-policy.https.html.headers": [ - "afbd45465cff26698dd7ad50ce667129cce6d5a1", - [] - ], "Magnetometer-disabled-by-permissions-policy.https.html.headers": [ "e972987f13bce9491b6833c2ba3d85757c2891b6", [] ], - "Magnetometer-enabled-by-feature-policy-attribute-redirect-on-load.https-expected.txt": [ - "6ae2ba94024f6a40e817fc4b93dcb5601a854593", - [] - ], - "Magnetometer-enabled-by-feature-policy-attribute.https-expected.txt": [ - "4749b53db74892b4ebf046d1bfe15bcc1a37654d", - [] - ], - "Magnetometer-enabled-by-feature-policy.https-expected.txt": [ - "ac7f332fc1c9b55df0a4c9c65705b611f450da27", - [] - ], - "Magnetometer-enabled-by-feature-policy.https.html.headers": [ - "64ec55e3e40a03d042ee79ba653096e8c9a6b6d5", - [] - ], "Magnetometer-enabled-by-permissions-policy.https.html.headers": [ "78363e0ece721ebf18af9b45c8fa2214fe143b0a", [] ], - "Magnetometer-enabled-on-self-origin-by-feature-policy.https-expected.txt": [ - "68c1f7453e7641cd96e53a6e8a6275fbfdab57d7", - [] - ], - "Magnetometer-enabled-on-self-origin-by-feature-policy.https.html.headers": [ - "4223f53ffa3d2cd8ff4497e7018bdc9750d17a99", - [] - ], "Magnetometer-enabled-on-self-origin-by-permissions-policy.https.html.headers": [ "07941dad58faa108ff50b53afd6b095d5a055a8f", [] @@ -453926,7 +454014,7 @@ ], "resources": { "sensor-data.js": [ - "32c2b1e2895b4883ee7bfb1d3042c77c12ac08c2", + "7024c708f7b8142d3d0d8c4a153f8eda1bd8b518", [] ] } @@ -457430,7 +457518,7 @@ ], "resources": { "sensor-data.js": [ - "a2886e7553bd0e59689a30bb0e5b5a68ed387d37", + "3b7ee8d705a339eb3c9404e2aa85606ce33ab57c", [] ] } @@ -457548,6 +457636,16 @@ "3fce7e2b1298042116a80ce8ccf6d47185866f1f", [] ], + "first-paint-only": { + "first-paint-bg-color-expected.txt": [ + "bde35b6b923bf50d0e892af9e0a8dfdebc8cee66", + [] + ], + "first-paint-only-expected.txt": [ + "754a4f858adcb20f721235e31a117714f0bd2496", + [] + ] + }, "resources": { "circle.svg": [ "6b5fdbe8e0653728125331b598f56cd55458a94d", @@ -457570,7 +457668,7 @@ [] ], "utils.js": [ - "cfb4ef885100106c0922d27da98f4d10da48be83", + "12ec53dbd4c2a01a47bd2832fe4d7d2360878f2b", [] ] } @@ -457876,7 +457974,7 @@ "88abef94b7b5f85f1312797df50041277fa32e3b", [] ], - "feature-policy-permissions-query.html": [ + "permissions-policy-permissions-query.html": [ "bd152e973e8fd520460a325d47beab8c25f45d31", [] ], @@ -457921,18 +458019,34 @@ "8793caf0b7e30ffa59ee258f7b65147a6e38eb19", [] ], + "permissions-policy-header-host-wildcard.https.sub-expected.txt": [ + "192eccbdb0b2c82796eb367daae6ab7644bfae1d", + [] + ], "permissions-policy-header-host-wildcard.https.sub.html.sub.headers": [ "81d0de836ea28cd372247a678ebda74455af352b", [] ], + "permissions-policy-header-port-wildcard.https.sub-expected.txt": [ + "990d06af7e2d55d6082a6e8c4cfefacd2d8c0081", + [] + ], "permissions-policy-header-port-wildcard.https.sub.html.sub.headers": [ "b813167ee62e520952d295854538687157fb3cec", [] ], + "permissions-policy-header-scheme-only.https.sub-expected.txt": [ + "034e99a5b3f014606b4b6f89486d0af5dfffa5c2", + [] + ], "permissions-policy-header-scheme-only.https.sub.html.sub.headers": [ "14d0868f2bb15fd71bdd1f81a880fc16cde522fa", [] ], + "private-state-token-redemption-supported-by-permissions-policy.tentative-expected.txt": [ + "b174ced8c4c98287527340baf460f2423d3c2fa7", + [] + ], "resources": { "common.js": [ "308f787da63d147b00356cf4817f8c33b162c6cb", @@ -457955,7 +458069,7 @@ [] ], "permissions-policy-focus-without-user-activation.html": [ - "c802d6f06999e58e927fa52c08cfb4d81423e768", + "d8a7e1e888ea05579dc2aa4d6aeb6c00402b88c5", [] ], "permissions-policy-private-state-token-redemption.html": [ @@ -457963,7 +458077,7 @@ [] ], "unload-helper.js": [ - "d1bf0105ce5d6fb8f1afe02a3cea8ac4ab2bbfce", + "5b11a212757247946b89f78621e7de1c582a57c8", [] ], "vertical-scroll-scrollable-content.html": [ @@ -457996,7 +458110,71 @@ ] }, "unload-allowed-by-default.tentative.window-expected.txt": [ - "756a0f553d4355fd16bacf966084e8961f4c0598", + "3ebb4a3e0c7a7a0555958de1ec946c9132149efa", + [] + ], + "unload-allowed-embed.tentative.window-expected.txt": [ + "88753dfcf63464cca46191292e4533c9869e8575", + [] + ], + "unload-allowed-frameset.tentative.window-expected.txt": [ + "88753dfcf63464cca46191292e4533c9869e8575", + [] + ], + "unload-allowed-headerless.tentative.window_urlType=blank-expected.txt": [ + "c6395f254b238cbb7b23b9b01e21d4e29e51113f", + [] + ], + "unload-allowed-headerless.tentative.window_urlType=blob-expected.txt": [ + "c6395f254b238cbb7b23b9b01e21d4e29e51113f", + [] + ], + "unload-allowed-headerless.tentative.window_urlType=data-expected.txt": [ + "c6395f254b238cbb7b23b9b01e21d4e29e51113f", + [] + ], + "unload-allowed-headerless.tentative.window_urlType=srcdoc-expected.txt": [ + "c6395f254b238cbb7b23b9b01e21d4e29e51113f", + [] + ], + "unload-allowed-object.tentative.window-expected.txt": [ + "88753dfcf63464cca46191292e4533c9869e8575", + [] + ], + "unload-disallowed-embed.tentative.window-expected.txt": [ + "8594516ab80396b9ad4169f919b4645ae5996801", + [] + ], + "unload-disallowed-frameset.tentative.window-expected.txt": [ + "8594516ab80396b9ad4169f919b4645ae5996801", + [] + ], + "unload-disallowed-headerless.tentative.window_urlType=blank-expected.txt": [ + "221146ad2394faed4b77e6264903728054e67729", + [] + ], + "unload-disallowed-headerless.tentative.window_urlType=blob-expected.txt": [ + "221146ad2394faed4b77e6264903728054e67729", + [] + ], + "unload-disallowed-headerless.tentative.window_urlType=data-expected.txt": [ + "221146ad2394faed4b77e6264903728054e67729", + [] + ], + "unload-disallowed-headerless.tentative.window_urlType=srcdoc-expected.txt": [ + "221146ad2394faed4b77e6264903728054e67729", + [] + ], + "unload-disallowed-object.tentative.window-expected.txt": [ + "8594516ab80396b9ad4169f919b4645ae5996801", + [] + ], + "unload-disallowed-subframe.tentative.window-expected.txt": [ + "afd37aabf439ad1297dd0863d811c41ee7e3eb5d", + [] + ], + "unload-disallowed.tentative.window-expected.txt": [ + "8183b76c305c0ab75056b6d6a422391a70b4e758", [] ], "vertical-scroll-main-frame-manual.tentative.html.headers": [ @@ -458036,22 +458214,46 @@ "aa72d3e74de59863fd9160b5aa9049a232e9cf63", [] ], + "payment-supported-by-permissions-policy.tentative-expected.txt": [ + "6ebab19612cdc108ca35f315aa3f4a7fab43c465", + [] + ], + "permissions-policy-frame-policy-allowed-for-all.https.sub-expected.txt": [ + "017813f3ff2a9c5c14eacca2b25713036494d45e", + [] + ], "permissions-policy-frame-policy-allowed-for-all.https.sub.html.sub.headers": [ "2cbb8a82c62040e24f809c816d6d35204de396df", [] ], + "permissions-policy-frame-policy-allowed-for-self.https.sub-expected.txt": [ + "de2567d93336a3a3a9da53ebc120aa728a7795ad", + [] + ], "permissions-policy-frame-policy-allowed-for-self.https.sub.html.sub.headers": [ "ff7ae4135338e3e525f6f5e0bfe38865c16b30e1", [] ], + "permissions-policy-frame-policy-allowed-for-some-override.https.sub-expected.txt": [ + "0e9ca01f55d41b147a115b7eaa361f8617172b08", + [] + ], "permissions-policy-frame-policy-allowed-for-some-override.https.sub.html.sub.headers": [ "d3aa9ff66a51312de8cb413d0976fd2eccead58a", [] ], + "permissions-policy-frame-policy-allowed-for-some.https.sub-expected.txt": [ + "85cdbf5b097f7705f8330139e8c60716a833de80", + [] + ], "permissions-policy-frame-policy-allowed-for-some.https.sub.html.sub.headers": [ "af08d49c2ed6ab950039c391f1b8a7af4f505830", [] ], + "permissions-policy-frame-policy-disallowed-for-all.https.sub-expected.txt": [ + "56d1320ed28d0586ba4269d3d42100b7fe7645ab", + [] + ], "permissions-policy-frame-policy-disallowed-for-all.https.sub.html.sub.headers": [ "a65abd6e45e8d0300c4a0b96931bc1318ead6075", [] @@ -458112,6 +458314,10 @@ "12fc99b50b2e4c875c0b31d0d81d3a3f33e0eea3", [] ], + "picture-in-picture-supported-by-permissions-policy-expected.txt": [ + "d62181786b459ee325a5f28ea4d6951cbd46b7de", + [] + ], "private-state-token-issue-disabled-by-permissions-policy.tentative.https.sub.html.headers": [ "18cbd50fca143221d8bf65aa91a4e062c59a85b3", [] @@ -458120,6 +458326,10 @@ "cef93ce872fce7fc39a742ce475087b131b46ec5", [] ], + "private-state-token-issue-supported-by-permissions-policy.tentative-expected.txt": [ + "e49d223abdc424f27e69d771ba0ef718d8cbf531", + [] + ], "reporting": { "bluetooth-report-only.https.html.headers": [ "dfa8cf0090dac0a092c5fb0db3bd46992a74175a", @@ -458288,7 +458498,7 @@ [] ], "nested-sandbox.html": [ - "4ba512140dae5d9df8d1b1bd19178a34ff5b40c0", + "c987e6f08538535bf217d159406a7b8a48514939", [] ], "opaque-origin-history1.sub.https.html": [ @@ -458308,7 +458518,7 @@ [] ], "permissions-policy-allowedfeatures.html": [ - "f4b020273fd394fb8691b6eeb406c7b3773cbcb3", + "48d02a6051416f9cf05e5512d2dfea2f5a98e662", [] ], "permissions-policy-autoplay.html": [ @@ -458428,7 +458638,7 @@ [] ], "permissions-policy.js": [ - "a8ce97f0b9d48232b2664a4372496ad54321f5fe", + "cfc6d3caab103427f5de5ab8ebb4949bbc2ef334", [] ], "picture-in-picture.js": [ @@ -458440,7 +458650,7 @@ [] ], "sandbox-self.html": [ - "8240de99c6560d80069e78557e2f803028ad1189", + "ba7a41f1081975e8b764e0e9f5705d0254b88c6d", [] ], "sandbox-self.html.headers": [ @@ -462201,7 +462411,7 @@ [] ], "sethtml-tree-construction.sub.dat": [ - "2826f3fa557bf301e6c8da3bf6b7311093eb45cd", + "dffaf660ad2cdffd537238253a814d8eae631060", [] ], "sethtml-unsafety.sub.dat": [ @@ -462389,6 +462599,10 @@ "wakelock-enabled-on-self-origin-by-permissions-policy.https.html.headers": [ "9849d6b89b34583b77b073b5867a642ff05c5079", [] + ], + "wakelock-supported-by-permissions-policy-expected.txt": [ + "86523c0b02555106a0647e449c66afb93f4a9ac5", + [] ] }, "scroll-animations": { @@ -462922,6 +463136,14 @@ "23ac4054d051b51309327a6c985dc67c458a93d5", [] ], + "onselectstart-on-key-in-contenteditable_preventDefault=no-expected.txt": [ + "484dd4e47980c228fc78bd45f9af821dc22c79ca", + [] + ], + "onselectstart-on-key-in-contenteditable_preventDefault=yes-expected.txt": [ + "6b6c3f4c94b985ee984e3fd633cf188a8f70fa4c", + [] + ], "script-and-style-elements-expected.txt": [ "bfb7c0c8a38c389d0642166907c14f5b269e96ac", [] @@ -466033,7 +466255,7 @@ [] ], "WEB_FEATURES.yml": [ - "ca2e78f49bcc703661680bfee33ad6b5fceb6a25", + "82f6a0b1f425dfc3f0d578a8abd2106f231e152a", [] ], "crashtests": { @@ -479474,6 +479696,10 @@ "ff22d62f104a3cf8cf4a659498f682dc1e83d34d", [] ], + "usb-supported-by-permissions-policy-expected.txt": [ + "878ff89920db44ffcb3c4234a99aaaf4e26496be", + [] + ], "usb.serviceworker.js": [ "c509adfef0d4c0cd3e68cc84467ac7db1140d643", [] @@ -502711,7 +502937,7 @@ ], "derive_bits_keys": { "argon2.tentative.https.any.js": [ - "55fb11c995653ea726c3ef9a3603ab6e83130323", + "9422c39c958a06339561799877c52033195f39ef", [ "WebCryptoAPI/derive_bits_keys/argon2.tentative.https.any.html", { @@ -502726,6 +502952,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "/common/subset-tests.js" ], [ @@ -502754,6 +502984,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "/common/subset-tests.js" ], [ @@ -502770,7 +503004,7 @@ ] ], "cfrg_curves_bits_curve25519.https.any.js": [ - "866192e0193bc18953c224647ac51f2bb373746f", + "5684d7624076c70a769099d39a1ad68886cb4fa8", [ "WebCryptoAPI/derive_bits_keys/cfrg_curves_bits_curve25519.https.any.html", { @@ -502781,6 +503015,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "cfrg_curves_bits_fixtures.js" ], [ @@ -502800,6 +503038,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "cfrg_curves_bits_fixtures.js" ], [ @@ -502811,7 +503053,7 @@ ] ], "cfrg_curves_bits_curve448.tentative.https.any.js": [ - "32485c68107e5c0aa94264caf1a097909723d173", + "5e482ef0b9d8041f0200301ff215bfa111a964df", [ "WebCryptoAPI/derive_bits_keys/cfrg_curves_bits_curve448.tentative.https.any.html", { @@ -502822,6 +503064,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "cfrg_curves_bits_fixtures.js" ], [ @@ -502841,6 +503087,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "cfrg_curves_bits_fixtures.js" ], [ @@ -502852,7 +503102,7 @@ ] ], "cfrg_curves_keys_curve25519.https.any.js": [ - "91390ba5c2a17a3ecd523b132153d5d965e543aa", + "8bcc201d4e95ec15bcf6218ac37c5b2dd966a4f1", [ "WebCryptoAPI/derive_bits_keys/cfrg_curves_keys_curve25519.https.any.html", { @@ -502863,6 +503113,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "cfrg_curves_bits_fixtures.js" ], [ @@ -502882,6 +503136,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "cfrg_curves_bits_fixtures.js" ], [ @@ -502893,7 +503151,7 @@ ] ], "cfrg_curves_keys_curve448.tentative.https.any.js": [ - "b34e366376a70f6bf7628d9fa62c42e5201a053f", + "0ed3954ac200b53464ca1213c96341e0877dca8d", [ "WebCryptoAPI/derive_bits_keys/cfrg_curves_keys_curve448.tentative.https.any.html", { @@ -502904,6 +503162,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "cfrg_curves_bits_fixtures.js" ], [ @@ -502923,6 +503185,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "cfrg_curves_bits_fixtures.js" ], [ @@ -502975,7 +503241,7 @@ ] ], "derived_bits_length.https.any.js": [ - "0aee2e3c172d30ab177fe89a8d75f964a2c9b703", + "862945c6a316c696deebe602e2856991800b788f", [ "WebCryptoAPI/derive_bits_keys/derived_bits_length.https.any.html", { @@ -502986,6 +503252,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "derived_bits_length.js" ], [ @@ -503009,6 +503279,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "derived_bits_length.js" ], [ @@ -503024,7 +503298,7 @@ ] ], "ecdh_bits.https.any.js": [ - "37e3eb4324200c85cb65ee9f077ea7433bff7783", + "58a0cecd5efed686be5d0792e8c16f4eb6acb51d", [ "WebCryptoAPI/derive_bits_keys/ecdh_bits.https.any.html", { @@ -503035,6 +503309,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "ecdh_bits.js" ] ] @@ -503050,6 +503328,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "ecdh_bits.js" ] ] @@ -503057,7 +503339,7 @@ ] ], "ecdh_keys.https.any.js": [ - "d8235fce5a74122591ee8b9462a1a66ac5da097c", + "6464dacfe3aa81463f3fa623460bd09179969efa", [ "WebCryptoAPI/derive_bits_keys/ecdh_keys.https.any.html", { @@ -503068,6 +503350,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "ecdh_keys.js" ] ] @@ -503083,6 +503369,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "ecdh_keys.js" ] ] @@ -503090,7 +503380,7 @@ ] ], "hkdf.https.any.js": [ - "02492c3741c7d1bb6f300bba51e08b911a1295bd", + "3879ddb14b903aa7ef95416de3f8f4c3bc940f6e", [ "WebCryptoAPI/derive_bits_keys/hkdf.https.any.html?1-1000", { @@ -503117,6 +503407,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "/common/subset-tests.js" ], [ @@ -503156,6 +503450,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "/common/subset-tests.js" ], [ @@ -503195,6 +503493,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "/common/subset-tests.js" ], [ @@ -503234,6 +503536,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "/common/subset-tests.js" ], [ @@ -503273,6 +503579,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "/common/subset-tests.js" ], [ @@ -503312,6 +503622,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "/common/subset-tests.js" ], [ @@ -503351,6 +503665,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "/common/subset-tests.js" ], [ @@ -503390,6 +503708,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "/common/subset-tests.js" ], [ @@ -503405,7 +503727,7 @@ ] ], "pbkdf2.https.any.js": [ - "2efbe523f8cd7d5daeb4dce42b893369467f9bfe", + "cc2ed9b9cef8721dd7523387c29c899981fce049", [ "WebCryptoAPI/derive_bits_keys/pbkdf2.https.any.html?1-1000", { @@ -503456,6 +503778,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "/common/subset-tests.js" ], [ @@ -503520,6 +503846,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "/common/subset-tests.js" ], [ @@ -503584,6 +503914,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "/common/subset-tests.js" ], [ @@ -503648,6 +503982,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "/common/subset-tests.js" ], [ @@ -503712,6 +504050,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "/common/subset-tests.js" ], [ @@ -503776,6 +504118,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "/common/subset-tests.js" ], [ @@ -503840,6 +504186,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "/common/subset-tests.js" ], [ @@ -503904,6 +504254,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "/common/subset-tests.js" ], [ @@ -503968,6 +504322,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "/common/subset-tests.js" ], [ @@ -504032,6 +504390,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "/common/subset-tests.js" ], [ @@ -504096,6 +504458,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "/common/subset-tests.js" ], [ @@ -504160,6 +504526,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "/common/subset-tests.js" ], [ @@ -504224,6 +504594,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "/common/subset-tests.js" ], [ @@ -504288,6 +504662,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "/common/subset-tests.js" ], [ @@ -504352,6 +504730,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "/common/subset-tests.js" ], [ @@ -504416,6 +504798,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "/common/subset-tests.js" ], [ @@ -504480,6 +504866,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "/common/subset-tests.js" ], [ @@ -504544,6 +504934,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "/common/subset-tests.js" ], [ @@ -504562,7 +504956,7 @@ }, "digest": { "cshake.tentative.https.any.js": [ - "d0c23c09ada4a9018b704c0964318558027ee650", + "81793666294c2320cf5e1861cfa5e6fbe637960e", [ "WebCryptoAPI/digest/cshake.tentative.https.any.html", { @@ -504572,6 +504966,10 @@ "WebCryptoAPI: digest() cSHAKE algorithms" ], [ + "script", + "../util/helpers.js" + ], + [ "timeout", "long" ] @@ -504588,6 +504986,10 @@ "WebCryptoAPI: digest() cSHAKE algorithms" ], [ + "script", + "../util/helpers.js" + ], + [ "timeout", "long" ] @@ -504597,7 +504999,7 @@ ] ], "digest.https.any.js": [ - "47bc220d44fb7068ea404a7b77aa40e6e6bc0c44", + "38ce85ec06cfc3231821802bc27c620d8005d617", [ "WebCryptoAPI/digest/digest.https.any.html", { @@ -504607,6 +505009,10 @@ "WebCryptoAPI: digest()" ], [ + "script", + "../util/helpers.js" + ], + [ "timeout", "long" ] @@ -504623,6 +505029,53 @@ "WebCryptoAPI: digest()" ], [ + "script", + "../util/helpers.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "kangarootwelve.tentative.https.any.js": [ + "9f800b7937876aee8dcff02c051be0159b247c4b", + [ + "WebCryptoAPI/digest/kangarootwelve.tentative.https.any.html", + { + "script_metadata": [ + [ + "title", + "WebCryptoAPI: digest() KangarooTwelve algorithms" + ], + [ + "script", + "../util/helpers.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ], + [ + "WebCryptoAPI/digest/kangarootwelve.tentative.https.any.worker.html", + { + "script_metadata": [ + [ + "title", + "WebCryptoAPI: digest() KangarooTwelve algorithms" + ], + [ + "script", + "../util/helpers.js" + ], + [ "timeout", "long" ] @@ -504632,7 +505085,7 @@ ] ], "sha3.tentative.https.any.js": [ - "4ae99791b8c95fd3db5a83d867bf8ad95f48998b", + "f9f38eadc2c39a04f01ad90176e5fc34ff78777b", [ "WebCryptoAPI/digest/sha3.tentative.https.any.html", { @@ -504642,6 +505095,10 @@ "WebCryptoAPI: digest() SHA-3 algorithms" ], [ + "script", + "../util/helpers.js" + ], + [ "timeout", "long" ] @@ -504658,6 +505115,53 @@ "WebCryptoAPI: digest() SHA-3 algorithms" ], [ + "script", + "../util/helpers.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "turboshake.tentative.https.any.js": [ + "243931cd119802e5ec0afdabb6e47a1af7cd6bb3", + [ + "WebCryptoAPI/digest/turboshake.tentative.https.any.html", + { + "script_metadata": [ + [ + "title", + "WebCryptoAPI: digest() TurboSHAKE algorithms" + ], + [ + "script", + "../util/helpers.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ], + [ + "WebCryptoAPI/digest/turboshake.tentative.https.any.worker.html", + { + "script_metadata": [ + [ + "title", + "WebCryptoAPI: digest() TurboSHAKE algorithms" + ], + [ + "script", + "../util/helpers.js" + ], + [ "timeout", "long" ] @@ -504669,7 +505173,7 @@ }, "encap_decap": { "encap_decap_bits.tentative.https.any.js": [ - "ab112e4d49767690804dc8deb2aa54df3e65c3ab", + "5a669753cd2701bdc355eb2dfa2ce557c0ffd774", [ "WebCryptoAPI/encap_decap/encap_decap_bits.tentative.https.any.html", { @@ -504720,7 +505224,7 @@ ] ], "encap_decap_keys.tentative.https.any.js": [ - "4ccb0585b84f875eef66e7c2be759a15156bf592", + "0a45c1fc4e9f6fd1582577db152af9a094d30cba", [ "WebCryptoAPI/encap_decap/encap_decap_keys.tentative.https.any.html", { @@ -504773,7 +505277,7 @@ }, "encrypt_decrypt": { "aes_cbc.https.any.js": [ - "35637a46affc05938098d3cf769583c22fb66547", + "ec09aae5a954a730aff9c0f80f983834de04c81e", [ "WebCryptoAPI/encrypt_decrypt/aes_cbc.https.any.html", { @@ -504784,6 +505288,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "aes_cbc_vectors.js" ], [ @@ -504808,6 +505316,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "aes_cbc_vectors.js" ], [ @@ -504824,7 +505336,7 @@ ] ], "aes_ctr.https.any.js": [ - "9f0c66900e9f3dace2e48ee7e106f81a6d40588a", + "f9d85bb6c93b7763e8726473814652fafbff1aa7", [ "WebCryptoAPI/encrypt_decrypt/aes_ctr.https.any.html", { @@ -504835,6 +505347,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "aes_ctr_vectors.js" ], [ @@ -504859,6 +505375,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "aes_ctr_vectors.js" ], [ @@ -504875,7 +505395,7 @@ ] ], "aes_gcm.https.any.js": [ - "6e3a6efb12d7b8170c204d91dc5812846b44f574", + "b3e6b5f0d2c1ff1b643319b1beaf1ea6b7aeafea", [ "WebCryptoAPI/encrypt_decrypt/aes_gcm.https.any.html", { @@ -504886,6 +505406,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "aes_gcm_96_iv_fixtures.js" ], [ @@ -504914,6 +505438,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "aes_gcm_96_iv_fixtures.js" ], [ @@ -504934,7 +505462,7 @@ ] ], "aes_gcm_256_iv.https.any.js": [ - "92900fb13ae2ecb928652d37b6d67e6b1a74d708", + "196a8ea94fb1c4ffcf6073902d741c617a3834ff", [ "WebCryptoAPI/encrypt_decrypt/aes_gcm_256_iv.https.any.html", { @@ -504945,6 +505473,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "aes_gcm_256_iv_fixtures.js" ], [ @@ -504973,6 +505505,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "aes_gcm_256_iv_fixtures.js" ], [ @@ -504993,7 +505529,7 @@ ] ], "aes_ocb.tentative.https.any.js": [ - "1d321fcfe8a5a3cae60ff4497724d66764d2d073", + "cca34e9e54e70af21de2be9a567b5b2250a8d28a", [ "WebCryptoAPI/encrypt_decrypt/aes_ocb.tentative.https.any.html", { @@ -505004,6 +505540,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "aes_ocb_fixtures.js" ], [ @@ -505032,6 +505572,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "aes_ocb_fixtures.js" ], [ @@ -505052,7 +505596,7 @@ ] ], "chacha20_poly1305.tentative.https.any.js": [ - "ed21fb5d7260e34972bc0ff14481160da9780c4d", + "d03f7c03099919a2a1f6ef1a56f4950995001240", [ "WebCryptoAPI/encrypt_decrypt/chacha20_poly1305.tentative.https.any.html", { @@ -505064,6 +505608,10 @@ [ "timeout", "long" + ], + [ + "script", + "../util/helpers.js" ] ], "timeout": "long" @@ -505080,6 +505628,10 @@ [ "timeout", "long" + ], + [ + "script", + "../util/helpers.js" ] ], "timeout": "long" @@ -505087,7 +505639,7 @@ ] ], "rsa_oaep.https.any.js": [ - "20fd17c5710b49400e8390315db00d10218b180d", + "3550f5eec287934dac9ef69bc175f11345d914b2", [ "WebCryptoAPI/encrypt_decrypt/rsa_oaep.https.any.html", { @@ -505098,6 +505650,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "rsa_vectors.js" ], [ @@ -505122,6 +505678,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "rsa_vectors.js" ], [ @@ -510711,7 +511271,7 @@ ] }, "getPublicKey.tentative.https.any.js": [ - "5c610752d96dff14e132a9818fcd87d96fe1ba20", + "1b151345c3416d6c5a7daa7686db689a18c0d7ae", [ "WebCryptoAPI/getPublicKey.tentative.https.any.html", { @@ -511212,7 +511772,7 @@ ] }, "ec_importKey.https.any.js": [ - "6a5cc8d4724b574b075d85c9a1709ffbc43a8b62", + "3b78bab4e74132580fed81f7acebd245dc29bac1", [ "WebCryptoAPI/import_export/ec_importKey.https.any.html", { @@ -511845,7 +512405,7 @@ ] ], "rsa_importKey.https.any.js": [ - "c0917cab683caaa5d2ed9a3b5d03bf49518d651f", + "049f50cebbb7b2b9a238d4bcc4a0fa2fc47e5e20", [ "WebCryptoAPI/import_export/rsa_importKey.https.any.html", { @@ -511986,7 +512546,7 @@ }, "sign_verify": { "ecdsa.https.any.js": [ - "9764cc33540c08768bbf06ead24d399f90e1b7d6", + "3f1e2e5ea9d8a7ae6954c993a08ea927ea13c4fb", [ "WebCryptoAPI/sign_verify/ecdsa.https.any.html", { @@ -511997,6 +512557,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "ecdsa_vectors.js" ], [ @@ -512021,6 +512585,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "ecdsa_vectors.js" ], [ @@ -512037,7 +512605,7 @@ ] ], "eddsa_curve25519.https.any.js": [ - "3be9eef41a9a0f390d06a60485f9364dbceb7a9a", + "b012b64733ef9d9319a1158cd2cbf99586ef4367", [ "WebCryptoAPI/sign_verify/eddsa_curve25519.https.any.html", { @@ -512048,6 +512616,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "eddsa_vectors.js" ], [ @@ -512072,6 +512644,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "eddsa_vectors.js" ], [ @@ -512088,7 +512664,7 @@ ] ], "eddsa_curve448.tentative.https.any.js": [ - "6960c296bae6afd67878cbac0bec69dc7de77c71", + "281bb63ad659f7eaa489e8db37c9e1ca0c923988", [ "WebCryptoAPI/sign_verify/eddsa_curve448.tentative.https.any.html", { @@ -512099,6 +512675,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "eddsa_vectors.js" ], [ @@ -512123,6 +512703,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "eddsa_vectors.js" ], [ @@ -512139,7 +512723,7 @@ ] ], "eddsa_small_order_points.https.any.js": [ - "be025557fc20aba4fe0fbc718ef81105402b8c95", + "5192b562706c619b4ca415016ea11557841838e5", [ "WebCryptoAPI/sign_verify/eddsa_small_order_points.https.any.html", { @@ -512150,6 +512734,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "eddsa_vectors.js" ], [ @@ -512174,6 +512762,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "eddsa_vectors.js" ], [ @@ -512190,7 +512782,7 @@ ] ], "hmac.https.any.js": [ - "419bab0506995e0d26d20b5b14c13e6b944a0574", + "a6c88f80ed99ee20495bdd3dcf0189ef002ffa38", [ "WebCryptoAPI/sign_verify/hmac.https.any.html", { @@ -512201,6 +512793,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "hmac_vectors.js" ], [ @@ -512225,6 +512821,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "hmac_vectors.js" ], [ @@ -512241,7 +512841,7 @@ ] ], "kmac.tentative.https.any.js": [ - "a2b5203f196e8ffc9927be571704d0145e4b30f6", + "3d34c5752137a8c910e178d298f8038aeb0508f0", [ "WebCryptoAPI/sign_verify/kmac.tentative.https.any.html", { @@ -512252,6 +512852,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "kmac_vectors.js" ], [ @@ -512276,6 +512880,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "kmac_vectors.js" ], [ @@ -512292,7 +512900,7 @@ ] ], "mldsa.tentative.https.any.js": [ - "364e1d39e8eb27f7b7f157ed3d3e56aad4e0d6cd", + "be336b3498462c66daf2b66646394d94440351ac", [ "WebCryptoAPI/sign_verify/mldsa.tentative.https.any.html", { @@ -512303,6 +512911,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "mldsa_vectors.js" ], [ @@ -512327,6 +512939,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "mldsa_vectors.js" ], [ @@ -512343,7 +512959,7 @@ ] ], "rsa_pkcs.https.any.js": [ - "d930a715ac6babe017ffdfb11c39c6f93572e372", + "3e3a8c23bf53cf87608b5a7299c013e9e4a78457", [ "WebCryptoAPI/sign_verify/rsa_pkcs.https.any.html", { @@ -512354,6 +512970,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "rsa_pkcs_vectors.js" ], [ @@ -512378,6 +512998,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "rsa_pkcs_vectors.js" ], [ @@ -512394,7 +513018,7 @@ ] ], "rsa_pss.https.any.js": [ - "f02ba2096b710ec9f5f36f2178a6a43f59226bff", + "399baba784687d921aeccf4e22cbd15122a72aee", [ "WebCryptoAPI/sign_verify/rsa_pss.https.any.html", { @@ -512405,6 +513029,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "rsa_pss_vectors.js" ], [ @@ -512429,6 +513057,10 @@ ], [ "script", + "../util/helpers.js" + ], + [ + "script", "rsa_pss_vectors.js" ], [ @@ -512480,7 +513112,7 @@ ], "wrapKey_unwrapKey": { "wrapKey_unwrapKey.https.any.js": [ - "880f7d650964aea69174b19bb8554279809bccea", + "9fa3bb775d4243b75779f8a8be663567dddc79a6", [ "WebCryptoAPI/wrapKey_unwrapKey/wrapKey_unwrapKey.https.any.html", { @@ -512533,78 +513165,43 @@ } }, "accelerometer": { - "Accelerometer-disabled-by-feature-policy.https.html": [ - "c41635175e515064fe49769987d4868b4563bcbd", - [ - null, - {} - ] - ], "Accelerometer-disabled-by-permissions-policy.https.html": [ - "a30391b07f00d11402450b5f14eb5d18d7126333", - [ - null, - {} - ] - ], - "Accelerometer-enabled-by-feature-policy-attribute-redirect-on-load.https.html": [ - "84baf7772dc02fff23b4cbf0765d11fbab22afd9", - [ - null, - {} - ] - ], - "Accelerometer-enabled-by-feature-policy-attribute.https.html": [ - "ba7d64ab0ead1685ccedd9dd02b100350cdc3a38", - [ - null, - {} - ] - ], - "Accelerometer-enabled-by-feature-policy.https.html": [ - "10d2c25380a2e9745cc2e14d9b96ab4d31eb2bba", + "12ef675f7b37093113538ec8c25b0fc5c8cdfa0a", [ null, {} ] ], "Accelerometer-enabled-by-permissions-policy-attribute-redirect-on-load.https.html": [ - "1cffdd6013dd16f3b43fbbcd07160b4bf20c818d", + "54762a115e1848adcbbccf360be5b674d7586d8d", [ null, {} ] ], "Accelerometer-enabled-by-permissions-policy-attribute.https.html": [ - "8dae3b742d3d64957c0bfc440c1dfea923fec795", + "93b6f95f7a3cc5b0c5207047eae207cdeaea98f9", [ null, {} ] ], "Accelerometer-enabled-by-permissions-policy.https.html": [ - "9c6c22177e736b895144453921b91e0c6d9823e7", - [ - null, - {} - ] - ], - "Accelerometer-enabled-on-self-origin-by-feature-policy.https.html": [ - "592f1f0750026a528dbba3065b567e7f5ac30f1a", + "9ef257c6a7b80a155d85708a0d0ee9a174ccf248", [ null, {} ] ], "Accelerometer-enabled-on-self-origin-by-permissions-policy.https.html": [ - "ef9545fefc8e780084c0289f6ef051b3f25762f8", + "1d4fc38de032c921378ef249d612c6fac82394c8", [ null, {} ] ], "Accelerometer-iframe-access.https.html": [ - "887c6139061f3823331a50f47fd111c46ed01f72", + "d5aa381c6fe1f0ac00a037bb61b8d8074c66b2bd", [ null, { @@ -512616,13 +513213,6 @@ } ] ], - "Accelerometer-supported-by-feature-policy.html": [ - "8e09c7acdfba7d77ce2a17c8a41ace0ee3a32cdc", - [ - null, - {} - ] - ], "Accelerometer-supported-by-permissions-policy.html": [ "3daec58b010910e7b312230345f206fea69a2bf4", [ @@ -513685,7 +514275,7 @@ ] ], "language-model-response-json-schema.tentative.https.window.js": [ - "5187850c853da82386f6c63ab638191e5084f68b", + "146fcaf8636d565145d8ce4ca4615541eea21c09", [ "ai/language-model/language-model-response-json-schema.tentative.https.window.html", { @@ -513715,6 +514305,37 @@ } ] ], + "language-model-response-regex.tentative.https.window.js": [ + "96dc0536b0420c271aa359207ede2abc7b760440", + [ + "ai/language-model/language-model-response-regex.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Response Regex" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], "language-model-tool-use.tentative.https.window.js": [ "ed82bcc67021b0025ac4921606fbbcebcfb98da9", [ @@ -513901,7 +514522,7 @@ ] ], "proofreader-proofread.tentative.https.window.js": [ - "35aca92fcc55d27d3922badc2f3047d2979fb4a6", + "4febc4446c7b146eafb4e4f10ac06e581283c994", [ "ai/proofreader/proofreader-proofread.tentative.https.window.html", { @@ -514911,42 +515532,42 @@ }, "ambient-light": { "AmbientLightSensor-disabled-by-permissions-policy.https.html": [ - "6e27c5902ae4dc95c0f8fc0a590362ea185dc2bd", + "71af5aa614b7f978498028dea774fb206ea640f1", [ null, {} ] ], "AmbientLightSensor-enabled-by-permissions-policy-attribute-redirect-on-load.https.html": [ - "ca259ac05668bb1b05a043a4d51422191b759442", + "d6fc32526ee610d0376971a13f951a3ec948b0a9", [ null, {} ] ], "AmbientLightSensor-enabled-by-permissions-policy-attribute.https.html": [ - "4ecbe4cae57a80c6c11eb09e6aad2287d75468a4", + "19be7aa27b1745b76bdf4f38c25cb93afb331037", [ null, {} ] ], "AmbientLightSensor-enabled-by-permissions-policy.https.html": [ - "d7539e53b7e607ad9a63627b1565c555f0f16302", + "2314be2c2c503494fe233a22f7fe8f1d958725be", [ null, {} ] ], "AmbientLightSensor-enabled-on-self-origin-by-permissions-policy.https.html": [ - "bcaeb564cd08bf5b24c0637da987a66a94b56c83", + "8982076f0f2b6915009d72a891ddc7cec04864f4", [ null, {} ] ], "AmbientLightSensor-iframe-access.https.html": [ - "c45804a51f757af0aa2a09d76497786f9e2ff8df", + "21970281e8bcb22fd29c9527edec9ff782f9f32c", [ null, { @@ -521995,29 +522616,6 @@ {} ] ], - "feature-policy-navigation": { - "feature-policy.https.html": [ - "90a27280c19a5c249fe53587a7f04aed13c28d83", - [ - null, - {} - ] - ], - "no-feature-policy.https.html": [ - "02458f3116aca876c4f05a92100cb35a90ad74b9", - [ - null, - {} - ] - ] - }, - "feature-policy.sub.https.html": [ - "8f9be9fde43eedd74120441f3f7e11bf5e8c315d", - [ - null, - {} - ] - ], "meta": { "resource-in-markup-accept-ch.https.html": [ "c9b98daccf84f1253b3f4c6deb3c65b57d3db162", @@ -522047,6 +522645,29 @@ null, {} ] + ], + "permissions-policy-navigation": { + "no-permissions-policy.https.html": [ + "333b25603b00c5711e6484be9360db95fa45089c", + [ + null, + {} + ] + ], + "permissions-policy.https.html": [ + "41510b699a6f6e523c8fda1401e1bdb570d00fa7", + [ + null, + {} + ] + ] + }, + "permissions-policy.sub.https.html": [ + "1597b19c6e9c90cae22647ca965c15469585e76f", + [ + null, + {} + ] ] }, "accept-ch-change.https.html": [ @@ -522127,8 +522748,8 @@ } ] ], - "cross-origin-subresource-with-feature-policy.https.html": [ - "3108c23faabfa254e3ebd0c12122e8e44e39e38b", + "cross-origin-subresource-with-permissions-policy.https.html": [ + "4e1ab9e44f4270e54bc805e1ef1ff5c6a350dadb", [ null, { @@ -522850,7 +523471,7 @@ ] }, "http-equiv-accept-ch-iframe.https.html": [ - "4bde8ebc2d6635cfb009efa26569837010c3af7d", + "bcd1c2b2f150059dd6149bc670ec2248656080ed", [ null, {} @@ -522915,7 +523536,7 @@ ] }, "meta-equiv-delegate-ch-iframe.https.html": [ - "2ce9c63c18a6a9455e31bf96dba82097056ccbd2", + "994d638536ffa41aa8b1d96318ea4bdecef5e07b", [ null, {} @@ -528610,7 +529231,7 @@ ] ], "compute-pressure-supported-by-permissions-policy.html": [ - "35f09b7b07ec593fd8f14eeb0cc4a7839f7f3c8c", + "034b0931f507d8cec2d09fb96d1279f2abd70ee5", [ null, {} @@ -546727,7 +547348,7 @@ ] ], "color-computed-color-mix-function.html": [ - "7ded5de5377d4544144cf1d3709eaf1f1ae7b5c1", + "91f226f144b46198d27043271705469671cb0f74", [ null, {} @@ -546811,7 +547432,7 @@ ] ], "color-invalid-color-mix-function.html": [ - "3d6fd06c92be2f3404da21ad70cb2b1596f082b0", + "8aae9fb736ab6b1084b41253da710038b27dcc47", [ null, {} @@ -546902,7 +547523,7 @@ ] ], "color-valid-color-mix-function.html": [ - "17a6b0c5e7dbd4e26a0424b49dff1686038d5892", + "6819a07bf71c9f1726279c7820edf7293cd9e3f1", [ null, {} @@ -547092,13 +547713,20 @@ }, "rendering": { "dark-color-scheme": { - "color-scheme-color-property.html": [ + "color-scheme-color-initial-affected-by-color-scheme-property.html": [ "4cb02d950b665cdbf22f3003c5c5b9908015bc13", [ null, {} ] ], + "color-scheme-color-initial-affected-by-meta-color-scheme-dynamic.html": [ + "91a4bd4d561f50475275e556e068079063b3fe33", + [ + null, + {} + ] + ], "color-scheme-iframe-dynamic.html": [ "46d05d63cb75ffd03f9f6f08b23743184e73d2ab", [ @@ -548593,7 +549221,7 @@ ] ], "supports-at-rule.html": [ - "31a10b9a33281837dbf1244b1cd467d0e8d634f0", + "00a35f74a7c519d3eeba61e0777ada5dd8a2f59d", [ null, {} @@ -552346,6 +552974,13 @@ {} ] ], + "fontface-invalid-arraybuffer.html": [ + "458a3a282f7846b189d016dbe86dc14da6ee9cdd", + [ + null, + {} + ] + ], "fontface-invalid-family.tentative.html": [ "893e459e7805e8fe68d8fb8439670ec1d0487c67", [ @@ -552859,7 +553494,7 @@ ], "parsing": { "font-computed.html": [ - "ab2694d211468b62b7d82d8ec353005d058b4f24", + "b4f7168d4c40e38c75e74bd1895562fa91dd990a", [ null, {} @@ -552901,7 +553536,7 @@ ] ], "font-family-computed.html": [ - "2f5f7dd91cd22d1f161cd4b5b4c72b1c62b725d7", + "85c4954ace64677f1675486017ec87a0d6f10cda", [ null, {} @@ -552915,7 +553550,7 @@ ] ], "font-family-valid.html": [ - "ceaa9a0d14446e8ffd12a5926590b40ec62a4ca8", + "6028c4c1072a90a1a45bc5936d5c7bb2d25a2476", [ null, {} @@ -553202,7 +553837,7 @@ ] ], "font-valid.html": [ - "896be89741bd14acd961398791f62db3ec876c8d", + "9b9f360e7bf8d25100b978193ffe8efed6fe7279", [ null, {} @@ -562176,6 +562811,15 @@ } ] ], + "scroll-marker-group-hover-from-marker.html": [ + "7ad3ee10f31546dcc53bde828dbc9c6478923db1", + [ + null, + { + "testdriver": true + } + ] + ], "scroll-marker-group-hover.html": [ "9b8097105bbc2cd10b32b0d139e90592aa3cced2", [ @@ -562320,7 +562964,7 @@ ] ], "scroll-button-display-none.html": [ - "8b3068be6dad6d1ccbe1134b9833ecc1c8b0f594", + "35e87c5556c1129d826290e68f8d74c2396cd689", [ null, { @@ -564100,21 +564744,21 @@ ] ], "position-sticky-single-axis-basic.html": [ - "b432af8ba53a7c10edf9b10bae76fd7b0b5bba47", + "e1db401e2c0a70e67d04ba2938b50edeb4ebe71d", [ null, {} ] ], "position-sticky-single-axis-dynamic.html": [ - "b8f753c5aee546f3d9e3bbe69d9b91adad25a58a", + "ee94cb9a5a28d11637c90e32070e9b5d39b02ed3", [ null, {} ] ], "position-sticky-single-axis-nested.html": [ - "2c66bcfed88be5cd1ccc22de995533dfdbc7f247", + "9a71aed2fa8e99ce9315ee5e556ebafec17823c2", [ null, {} @@ -564793,7 +565437,7 @@ ] ], "register-property-syntax-parsing.html": [ - "1f9f1325c3c8370608461815c1cf1f965e7bc0b8", + "9043fcdf6151a3140b6a8e9ec049db874c958b1d", [ null, {} @@ -569974,6 +570618,13 @@ {} ] ], + "grid-item-height-001.html": [ + "246687f01fef56195c286e9298df5db40e89c292", + [ + null, + {} + ] + ], "indefinite-1.html": [ "e69689c939f42b330f68eaa2ae07885557f65657", [ @@ -575253,7 +575904,7 @@ ] ], "custom-property-and-allow-discrete.html": [ - "6ba315676fc0ea992ced3eeb9cc8792d4f6ac309", + "33a971f17db8355b7b1291cbd4fd27ac074995f6", [ null, {} @@ -575840,6 +576491,13 @@ {} ] ], + "unregistered-custom-property-transition.html": [ + "57464405563db9d9ebf5fc97d7d3bd880e3e7d64", + [ + null, + {} + ] + ], "zero-duration-multiple-transition.html": [ "7b85702092a988aaced7070198252dda1891e40d", [ @@ -577067,7 +577725,7 @@ ] ], "container-name.html": [ - "45d9cbcb8ca879bae2c7910b8bc3cfceda764cba", + "420a8301aaad88a5ba348203166b7b5911cd3d9e", [ null, {} @@ -583613,7 +584271,7 @@ ] ], "font-family-serialization-001.html": [ - "436ce7f5c138d824013964c6d88e227e009e1772", + "669ce4e2b66eda6765f7e4b5d78c63532cbfeece", [ null, {} @@ -584070,7 +584728,7 @@ ] ], "serialize-values.html": [ - "87d0f348f1e0149dca8b109528c45fb10f780341", + "f1a49565e7e35909c58da3fac1a8e4a9a89a6a41", [ null, {} @@ -585377,6 +586035,13 @@ {} ] ], + "scrollParent-quirks-mode.html": [ + "f9bebdce6cbaf38894175e14de35addfd6ce7c8e", + [ + null, + {} + ] + ], "scrollParent-shadow-tree.html": [ "936d0b40fbbab78792def6e14ee7654163ea43d4", [ @@ -585385,7 +586050,7 @@ ] ], "scrollParent.html": [ - "51507b97e4329f91bce2b36c057454fac083196d", + "183517712d8735e24cd68271d1286651355837ee", [ null, {} @@ -595204,6 +595869,13 @@ {} ] ], + "remove-next-sibling-during-replace-with.html": [ + "46481c0e40e8d725fcb04e68a819737439d945ea", + [ + null, + {} + ] + ], "remove-unscopable.html": [ "0238b0fa97a40dd9e5058d4153d1483553552033", [ @@ -617139,6 +617811,15 @@ } ] ], + "fedcm-resolve-side-effects.https.html": [ + "6a464e658cfa9c77a46124883924032129582918", + [ + null, + { + "testdriver": true + } + ] + ], "fedcm-userinfo-after-resolve.https.html": [ "5492abd48a6594589b758541cfd88d90b3aa306a", [ @@ -618018,15 +618699,6 @@ {} ] ], - "client-hints-meta.https.html": [ - "7a370f452c4aa2660b86e33253db2c2ed2ff79de", - [ - null, - { - "testdriver": true - } - ] - ], "client-hints.https.html": [ "10ba6225b34ab2dfe053687164d9058ad92e9f3e", [ @@ -647703,7 +648375,7 @@ ] ], "local-fonts-supported-by-permissions-policy.html": [ - "671c0fa5392b566a076d1f1b3f8ffa986c0dacd8", + "f6541d2ab4d26c899c4ea30151664c6b17ba4203", [ null, {} @@ -649906,7 +650578,7 @@ }, "gamepad": { "gamepad-default-permissions-policy.https.sub.html": [ - "062b741a704a088c15d016168a9d744baf927589", + "9ad3d4d52a1e7600b78ccdb0f3c6f0018d7c4834", [ null, {} @@ -650370,78 +651042,43 @@ ] }, "gyroscope": { - "Gyroscope-disabled-by-feature-policy.https.html": [ - "d8dd8dcdd2d0f2c547dc969fdd72ca3092300847", - [ - null, - {} - ] - ], "Gyroscope-disabled-by-permissions-policy.https.html": [ - "1aa666ba769df269be57f96bc89b05b92109f926", - [ - null, - {} - ] - ], - "Gyroscope-enabled-by-feature-policy-attribute-redirect-on-load.https.html": [ - "34e5700ce589aa31f070c4d0f936f58225778d9e", - [ - null, - {} - ] - ], - "Gyroscope-enabled-by-feature-policy-attribute.https.html": [ - "dfe318d5792309f1c98d11927b62333aa8803816", - [ - null, - {} - ] - ], - "Gyroscope-enabled-by-feature-policy.https.html": [ - "2c36d417f6b06e70a8285ab5cc81cd67f37b0af6", + "69292999c6d541d33cc13e0ceaef0e54030709ed", [ null, {} ] ], "Gyroscope-enabled-by-permissions-policy-attribute-redirect-on-load.https.html": [ - "54193e058f6e6f484adb03f630a3c7776228cd36", + "a94f1152bf17f29a2885249372ea5357205d64cd", [ null, {} ] ], "Gyroscope-enabled-by-permissions-policy-attribute.https.html": [ - "cfaae595961c690bab08afb91715763f371c3c57", + "8712b21d338770922b7dfd9f3c12e776a438d7cf", [ null, {} ] ], "Gyroscope-enabled-by-permissions-policy.https.html": [ - "ec35eaba548354206e1c2c8fa129aef29f3867c9", - [ - null, - {} - ] - ], - "Gyroscope-enabled-on-self-origin-by-feature-policy.https.html": [ - "8e789c184e627b25b14af583851b55e17bd377dc", + "d501ad8a1072dfa165333570b316be006e45e4e6", [ null, {} ] ], "Gyroscope-enabled-on-self-origin-by-permissions-policy.https.html": [ - "f0e33660dea23647542ccbb621fc1616e62ad4cc", + "6984ef586594c788f48987549f7928551a54b3f8", [ null, {} ] ], "Gyroscope-iframe-access.https.html": [ - "9856006dc0e28193a27fc11891cd71f076257569", + "6c458422e7838466625d0c71273ea1eaca750e1a", [ null, { @@ -650453,13 +651090,6 @@ } ] ], - "Gyroscope-supported-by-feature-policy.html": [ - "06a4137f17dae94eb3b80edd625a0a382d693bb8", - [ - null, - {} - ] - ], "Gyroscope-supported-by-permissions-policy.html": [ "08ade20d4fa261aa0661fb7a30c8d158c0556e68", [ @@ -655997,6 +656627,15 @@ {} ] ], + "scroll-restore-on-reload-non-ascii-fragment.html": [ + "8aa726cd1af7e26d07ca6919b248ca3d2d79e656", + [ + null, + { + "timeout": "long" + } + ] + ], "scroll-to-anchor-name.html": [ "060aed11e264dca0867df7e126935110eaea2e8c", [ @@ -667889,7 +668528,7 @@ ] ], "2d.text.measure.actualBoundingBox.small-font.html": [ - "4e95712839aa62b6edb4c433b04f2add1267360f", + "60e37c5a9533909c56e99836f754aba1391f6b43", [ null, {} @@ -681918,6 +682557,20 @@ {} ] ], + "2d.text.measure.actualBoundingBox.small-font.html": [ + "44a27e637670a900b9caff707d3d04d999651747", + [ + null, + {} + ] + ], + "2d.text.measure.actualBoundingBox.small-font.worker.js": [ + "0f329b197baa14e43052490521448cd877dfee89", + [ + "html/canvas/offscreen/text/2d.text.measure.actualBoundingBox.small-font.worker.html", + {} + ] + ], "2d.text.measure.actualBoundingBox.whitespace.html": [ "5895e6360a0725c61c9f5611342cbb90df630581", [ @@ -688941,7 +689594,7 @@ ] ], "processing-instruction-attributes.html": [ - "f3c82fb99b98b12676a96191f9f93ac8e487ff6a", + "142980b14198cc2459e28066432905247a89ad76", [ null, {} @@ -696067,7 +696720,7 @@ ] ], "autoplay-allowed-by-permissions-policy-attribute-redirect-on-load.https.sub.html": [ - "417fc50344e72b593086289e615ce781dbc0b0e9", + "ef064ad2194ece167be294e97d71d2b3d760abb3", [ null, { @@ -696085,7 +696738,7 @@ ] ], "autoplay-allowed-by-permissions-policy.https.sub.html": [ - "5d3d252ba8a493ca1dfb8cb3b48cef9d367b1221", + "ae810b1495b25187bd699ac4e5b93425d4fd194f", [ null, { @@ -696103,7 +696756,7 @@ ] ], "autoplay-disabled-by-permissions-policy.https.sub.html": [ - "3f5f530d8707cd061cd8c6cae70b2964887469d7", + "a668849cfb347916557ca34fa4786621b7f6fae7", [ null, { @@ -699373,6 +700026,13 @@ {} ] ], + "same-origin-contextual-fragment.html": [ + "9ac407b4fb4f7d09c2397d8b09ec6357fe74dfc9", + [ + null, + {} + ] + ], "same_origin_parentage.html": [ "a163eb8eec30f21552cd985ebcebdd90b91d8642", [ @@ -704373,7 +705033,7 @@ ] ], "wrapping-transformation.window.js": [ - "cc879e6c9d01edeeeacc693a2880c2c970180232", + "d6efe89ced3d46aac53c777c3aec95432a8289f8", [ "html/semantics/forms/the-textarea-element/wrapping-transformation.window.html", {} @@ -704537,6 +705197,13 @@ } ] ], + "details-name-exclusivity-fragment-insertion.html": [ + "25584585c95f1d08a8d38e6772c04721553b491e", + [ + null, + {} + ] + ], "details-toggle-source-commandfor.tentative.html": [ "0fe696bcbc99243ed82135fba62709eff1e17671", [ @@ -705462,6 +706129,15 @@ } ] ], + "interestfor-input-invalid.tentative.html": [ + "e883a21f2bbe7fe7591ab41948cc410083f25f0a", + [ + null, + { + "testdriver": true + } + ] + ], "interestfor-invoker-descendants.tentative.html": [ "cd9185a0108c14ad66e75c1501a5acee93a09dac", [ @@ -708053,7 +708729,7 @@ ] ], "148.html": [ - "e2da8e8f0b151021e91cf4adc5bace003cc4f2f2", + "992f01972dcc83447c782c4467b71e06b5a2cf15", [ null, {} @@ -713171,6 +713847,13 @@ ] }, "parsing-html-fragments": { + "fragment-parse-form-in-template-001.tentative.html": [ + "2badb3bce16d22571dc9267d689a4f8649774a53", + [ + null, + {} + ] + ], "innerHTML-setter-default-namespace.xhtml": [ "19f17f1e28ce7dcb19fbe9e374ad412405c28e41", [ @@ -717583,7 +718266,7 @@ ] ], "idle-detection-allowed-by-permissions-policy.https.sub.html": [ - "6fae367730b40b275cff6ce4d09aa9edfc53d28c", + "410b857b37979f8642086413b4182f22614d58ed", [ null, { @@ -721517,7 +722200,7 @@ ] ], "broken-image-icon.html": [ - "8ca55b41e6b125453d7e2cf409a0cd904c64a672", + "e27e32816e83af5ae049e992a655de026b7db52a", [ null, {} @@ -723858,78 +724541,43 @@ ] }, "magnetometer": { - "Magnetometer-disabled-by-feature-policy.https.html": [ - "33ece4ef7f15ec05b8c78fff1c944e32c8a822f2", - [ - null, - {} - ] - ], "Magnetometer-disabled-by-permissions-policy.https.html": [ - "2dac0031f91a63a29fc0297df71e8602ec4e7e93", - [ - null, - {} - ] - ], - "Magnetometer-enabled-by-feature-policy-attribute-redirect-on-load.https.html": [ - "bcd3f1a77cef3a6cd535c3999a790ba6ee085f66", - [ - null, - {} - ] - ], - "Magnetometer-enabled-by-feature-policy-attribute.https.html": [ - "c8bb99266220ae757e65f2efa7b45cc57c8e6590", - [ - null, - {} - ] - ], - "Magnetometer-enabled-by-feature-policy.https.html": [ - "635572a0dc01bc91389a96b6478a5b16a4221755", + "9b9cb8d861063e530849de8944676c6fe6806054", [ null, {} ] ], "Magnetometer-enabled-by-permissions-policy-attribute-redirect-on-load.https.html": [ - "a41653c0926afce894e4f2964c1c4f66737d27bd", + "a26a904af647002f1ff27c13d6eae8458666c7cf", [ null, {} ] ], "Magnetometer-enabled-by-permissions-policy-attribute.https.html": [ - "1936468f0eb685d46f8683b9d555d39831f1d5b1", + "d307abcc7d71dcabe4dc58036f45c8cc17274cff", [ null, {} ] ], "Magnetometer-enabled-by-permissions-policy.https.html": [ - "ff658c7d593b7f531d46fc582528d3f081b86b8b", - [ - null, - {} - ] - ], - "Magnetometer-enabled-on-self-origin-by-feature-policy.https.html": [ - "666b64c93cf7010601388af7824e9801f73a85c3", + "7e7aeeca6763756b0260c766eccc363081abfa16", [ null, {} ] ], "Magnetometer-enabled-on-self-origin-by-permissions-policy.https.html": [ - "30a4c619a02e3452133f907508c1192d0a2a269e", + "8739e635ebe2ee25e3b1a09eac04f56de80a1ae1", [ null, {} ] ], "Magnetometer-iframe-access.https.html": [ - "455a06b060bf02e433cbe40ad9c7baf26484892b", + "81f24400802baa189059401bc8d5cfe3732a7bbd", [ null, { @@ -723940,13 +724588,6 @@ } ] ], - "Magnetometer-supported-by-feature-policy.html": [ - "a04936389507ca4b6da5ea727ef094ed6d39a77f", - [ - null, - {} - ] - ], "Magnetometer-supported-by-permissions-policy.html": [ "d91716b3bf90647a26e6416a4538b8eec1ccb739", [ @@ -724128,7 +724769,7 @@ ] ], "inferred-mrow-stretchy.html": [ - "b0455ac9665d4f34b2939bc78d69c697969fb632", + "57119530d15b305d116c3338c107424819d83e44", [ null, {} @@ -724255,6 +724896,13 @@ {} ] ], + "embellished-operator-004.html": [ + "1d5c45ee0712aa9ef6121ec462d22c39b4d3550b", + [ + null, + {} + ] + ], "embellished-operator-dynamic-002.html": [ "2c52684765b3337c8d45e8e7520abb9abcc345f0", [ @@ -731112,7 +731760,7 @@ ] ], "navigate-history-traversal-during-onnavigate-should-reject.html": [ - "911fc6bf8553b2d8a849b8956277fdc5ac75b460", + "51c44c7a7e4062dc81ced74fb09ee8ca867f805a", [ null, { @@ -734652,42 +735300,42 @@ }, "orientation-sensor": { "AbsoluteOrientationSensor-disabled-by-permissions-policy.https.html": [ - "982eaf6e1e3d857a3ec7959d73b7b371dadc5e82", + "785ea992c4efb3098d0e94c9af646b3c01558c64", [ null, {} ] ], "AbsoluteOrientationSensor-enabled-by-permissions-policy-attribute-redirect-on-load.https.html": [ - "c30c47819c93439733bc4d8b03dcfa21ab822f39", + "b165f892b7e7727ecb42558fcf405a7ce789a2c1", [ null, {} ] ], "AbsoluteOrientationSensor-enabled-by-permissions-policy-attribute.https.html": [ - "60579435b5dd4854f2da1d0e25309b9996daee72", + "dcaafc7133fd1e4e7a34c9ece782747f217db2d0", [ null, {} ] ], "AbsoluteOrientationSensor-enabled-by-permissions-policy.https.html": [ - "dd4dd5a9e70d4b42da855bbf90a8cc3f8dd77b9f", + "f7fc1c84e81dd470067591e93d9b17dd9a0ab22d", [ null, {} ] ], "AbsoluteOrientationSensor-enabled-on-self-origin-by-permissions-policy.https.html": [ - "5f6db8fd4a578fb72374801cf9136499d26487c1", + "d1456729c088556a365adb0235f5f2d09ea3eb5f", [ null, {} ] ], "AbsoluteOrientationSensor-iframe-access.https.html": [ - "5446e73c523b609e1981d44c3b9a6667c26ad2b4", + "df44618875017c79047f9d250d2eb163f96f4538", [ null, { @@ -734720,42 +735368,42 @@ ] ], "RelativeOrientationSensor-disabled-by-permissions-policy.https.html": [ - "2c98e890015c69d49ebf56b39dc771b7bfe8b86b", + "25dd98810357936040bf92c98717c5172f260689", [ null, {} ] ], "RelativeOrientationSensor-enabled-by-permissions-policy-attribute-redirect-on-load.https.html": [ - "ba0a1da1f06a6bf563f6a4391d32e48930e1817e", + "b5d1b67fc2410c67b5242a72f660aebef5de73e0", [ null, {} ] ], "RelativeOrientationSensor-enabled-by-permissions-policy-attribute.https.html": [ - "a846fcb0d1fe73baba01c9006e5f62fe3b14320b", + "3d9ca5e64e310ee12f566bacc8b1b7986cf5907f", [ null, {} ] ], "RelativeOrientationSensor-enabled-by-permissions-policy.https.html": [ - "f520b87bcc657018d2b19a149def53a155a63096", + "653e686b592279bcd3c4bdbb85037402f10a3971", [ null, {} ] ], "RelativeOrientationSensor-enabled-on-self-origin-by-permissions-policy.https.html": [ - "d69c02ce5104c14b75f809441d65b070cd307ac0", + "190ce8f75b0725f231c6ee29b2fed5518472051d", [ null, {} ] ], "RelativeOrientationSensor-iframe-access.https.html": [ - "10fcb50c3b6731fb63429a846e6111b944264511", + "c314654b6f5d6a130fb531225b367c0dafde3b5e", [ null, { @@ -735247,7 +735895,7 @@ ], "first-paint-only": { "child-painting-first-image.html": [ - "e541120f2e51a0403fcf13a0fd9d25d7c72c69e8", + "78c95ce5cf5c04b579adfdf4f470b54a19de8bb4", [ null, {} @@ -735268,7 +735916,7 @@ ] ], "sibling-painting-first-image.html": [ - "ca1e1555984bb331ff8eefe14b493e8e3ef146ce", + "c2d0071ebb31dd7fc8c0c5e6658c339629a4ce28", [ null, {} @@ -737052,8 +737700,8 @@ } ] ], - "permissions-query-feature-policy-attribute.https.sub.html": [ - "1d7333d9b5f67a405dc6979d5ddcfda444a04c39", + "permissions-query-permissions-policy-attribute.https.sub.html": [ + "2e7121e2b7466cdcbdeda4204ebf4fd0f6d4d633", [ null, {} @@ -737162,21 +737810,21 @@ ] ], "permissions-policy-header-host-wildcard.https.sub.html": [ - "211ca7445df8dbf1be989b361dadaa420fbf54eb", + "978bf89dff993ccdf98c7f467145d44d289508d4", [ null, {} ] ], "permissions-policy-header-port-wildcard.https.sub.html": [ - "adb657023eaf2c4e686adef2ea4dc8a751170c7c", + "a9938f714f82ca001cce5f5f654f883539ad111f", [ null, {} ] ], "permissions-policy-header-scheme-only.https.sub.html": [ - "eab3e8f697fd2c0523e7228491d1dd7777f12841", + "e528f0832e68b4795d2f102ff3ec11287812779d", [ null, {} @@ -737190,7 +737838,7 @@ ] ], "private-state-token-redemption-supported-by-permissions-policy.tentative.html": [ - "0399f167fb045b967114db33c9461b0355c8a9ff", + "68bd6a15b876fbf931be5f027aaa5b1e672fe0b5", [ null, {} @@ -737955,7 +738603,7 @@ ] ], "payment-supported-by-permissions-policy.tentative.html": [ - "4e8796f594c4c21de1912b5b6060b166f64179cd", + "825c95694c8980601ee6b740772f45f796b19dbf", [ null, {} @@ -738014,49 +738662,49 @@ ] ], "permissions-policy-header-policy-allowed-for-all.https.sub.html": [ - "16a2b60c75d5f870a8364d2a2bdf913112f6b58c", + "6827bf80be631b3ff3f5c21669c456839e2b3c7b", [ null, {} ] ], "permissions-policy-header-policy-allowed-for-malformed-wildcard.https.sub.html": [ - "9d98d1abcca5780a750620987449f227f38c311e", + "c7c42946cc29b20af14c71556203b2e24a43c7b3", [ null, {} ] ], "permissions-policy-header-policy-allowed-for-self.https.sub.html": [ - "363ff0b9819f7139d51867141d0a40108e981ea5", + "e1765a49cce6afcd7d205523bce47a8d9737fcae", [ null, {} ] ], "permissions-policy-header-policy-allowed-for-some.https.sub.html": [ - "e9d8ac145866eaff144f4d5b87197c3c40e44673", + "61c73ac0087399e9a5f4f3fc0b89dc9efcddb7df", [ null, {} ] ], "permissions-policy-header-policy-allowed-for-wildcard.https.sub.html": [ - "713d697e64a6491b798ecd9ef8d1102169c6fb39", + "70cfd38e05ccfcd97b330ff716d3b701556aa808", [ null, {} ] ], "permissions-policy-header-policy-declined.https.sub.html": [ - "f02cdce7d1e7db0f5416a3085eacb628eb715dc4", + "2b48ada9e9edee0e1b6d17c443661cc165533782", [ null, {} ] ], "permissions-policy-header-policy-disallowed-for-all.https.sub.html": [ - "f787b7de12ad9408535fa315aad1b2857c08d6aa", + "c58375c5e7c63515681325d04359393f148d5a79", [ null, {} @@ -738156,7 +738804,7 @@ ] ], "picture-in-picture-supported-by-permissions-policy.html": [ - "387a878f3b70ccddd9c8fff9793e725bd90e3b1c", + "a6b8bbfdc232cf7906ce31a060ce5f626be58dbe", [ null, {} @@ -738191,7 +738839,7 @@ ] ], "private-state-token-issue-supported-by-permissions-policy.tentative.html": [ - "52a392de577e4d924cfeab68299c45030bc344fb", + "2ceee8f442080620d06d766e7c9cde0a8ce392cb", [ null, {} @@ -738646,7 +739294,7 @@ ] ], "leave-picture-in-picture.html": [ - "a0fbcb23e57e1402e51f7f5cbd52da611c0ea691", + "ce897a8a815e6fc56c79800f5eb7604a66f0025e", [ null, { @@ -741286,6 +741934,15 @@ {} ] ], + "preload-imagesrcset-no-href.html": [ + "f7a796ab1343ad66a3b8c7f599077b402458406e", + [ + null, + { + "timeout": "long" + } + ] + ], "preload-invalid-resources.html": [ "be6f79e8e6ac58e377dfc73b4e1ffe6d59ae1d06", [ @@ -759058,7 +759715,7 @@ ] ], "wakelock-supported-by-permissions-policy.html": [ - "cc0bb963b16ed086e29d6cfbe4b6fb19468f025e", + "acb97470a82bcdc724c0ba2474f72f80680c5c35", [ null, {} @@ -761548,6 +762205,23 @@ {} ] ], + "onselectstart-on-key-in-contenteditable.html": [ + "1094ac13efa9c0469d64d0fb187491bff3ae4d99", + [ + "selection/onselectstart-on-key-in-contenteditable.html?preventDefault=no", + { + "testdriver": true, + "timeout": "long" + } + ], + [ + "selection/onselectstart-on-key-in-contenteditable.html?preventDefault=yes", + { + "testdriver": true, + "timeout": "long" + } + ] + ], "removeAllRanges.html": [ "026280d6b8c252c8c9486977d31a32d6d211f701", [ @@ -766721,6 +767395,13 @@ {} ] ], + "inserting-fragment-under-shadow-host.html": [ + "404ba729d318391bd6b727fdc301a4888c37296f", + [ + null, + {} + ] + ], "leaktests": { "get-elements.html": [ "40fa9b69314a9cd9f1eee777ce4120440d7801df", @@ -787499,7 +788180,7 @@ ] ], "custom-events.html": [ - "1c49106b510821b2cd5765908dcb878329929026", + "c2f83a9431319de6c14bce1ed7cc66cd560fc7b0", [ null, {} @@ -878112,7 +878793,7 @@ ] ], "usb-supported-by-permissions-policy.html": [ - "8e6352116d33d2aac1dc80809d6357ff78c370d9", + "aa93f708118f8425a17a2cbe1f0276a5a152b23d", [ null, {}
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/IndexedDB/WEB_FEATURES.yml index dfbb455..65294d5 100644 --- a/third_party/blink/web_tests/external/wpt/IndexedDB/WEB_FEATURES.yml +++ b/third_party/blink/web_tests/external/wpt/IndexedDB/WEB_FEATURES.yml
@@ -1,3 +1,10 @@ features: - name: indexeddb - files: "**" + files: + - "*" + - "!idbindex_getAllRecords.any.js" + - "!idbobjectstore_getAllRecords.any.js" +- name: getallrecords + files: + - idbindex_getAllRecords.any.js + - idbobjectstore_getAllRecords.any.js
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/crashtests/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/IndexedDB/crashtests/WEB_FEATURES.yml new file mode 100644 index 0000000..dfbb455 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/IndexedDB/crashtests/WEB_FEATURES.yml
@@ -0,0 +1,3 @@ +features: +- name: indexeddb + files: "**"
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/argon2.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/argon2.js index f160940..de3b4b5 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/argon2.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/argon2.js
@@ -51,7 +51,6 @@ var algorithmName = vector.algorithm; var password = vector.password; - // Key for normal operations promises.push( subtle .importKey('raw-secret', password, algorithmName, false, [ @@ -70,20 +69,3 @@ }); } } - -function equalBuffers(a, b) { - if (a.byteLength !== b.byteLength) { - return false; - } - - var aView = new Uint8Array(a); - var bView = new Uint8Array(b); - - for (var i = 0; i < aView.length; i++) { - if (aView[i] !== bView[i]) { - return false; - } - } - - return true; -}
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/argon2.tentative.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/argon2.tentative.https.any.js index 55fb11c..9422c39 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/argon2.tentative.https.any.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/argon2.tentative.https.any.js
@@ -1,5 +1,6 @@ // META: title=WebCryptoAPI: deriveBits() Using Argon2 // META: timeout=long +// META: script=../util/helpers.js // META: script=/common/subset-tests.js // META: script=argon2_vectors.js // META: script=argon2.js
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/argon2_vectors.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/argon2_vectors.js index 9b9acda5..93d26b5e 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/argon2_vectors.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/argon2_vectors.js
@@ -2,7 +2,6 @@ // Test vectors from RFC 9106 // https://www.rfc-editor.org/rfc/rfc9106 - // Test vectors from RFC 9106 var testVectors = [ // Argon2d test vector {
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits.js index 8ab9db7..1406e8b 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits.js
@@ -224,37 +224,4 @@ .then(function(results) {return {privateKeys: privateKeys, publicKeys: publicKeys, noDeriveBitsKeys: noDeriveBitsKeys, ecdhKeys: ecdhPublicKeys}}); } - // Compares two ArrayBuffer or ArrayBufferView objects. If bitCount is - // omitted, the two values must be the same length and have the same contents - // in every byte. If bitCount is included, only that leading number of bits - // have to match. - function equalBuffers(a, b, bitCount) { - var remainder; - - if (typeof bitCount === "undefined" && a.byteLength !== b.byteLength) { - return false; - } - - var aBytes = new Uint8Array(a); - var bBytes = new Uint8Array(b); - - var length = a.byteLength; - if (typeof bitCount !== "undefined") { - length = Math.floor(bitCount / 8); - } - - for (var i=0; i<length; i++) { - if (aBytes[i] !== bBytes[i]) { - return false; - } - } - - if (typeof bitCount !== "undefined") { - remainder = bitCount % 8; - return aBytes[length] >> (8 - remainder) === bBytes[length] >> (8 - remainder); - } - - return true; - } - }
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits_curve25519.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits_curve25519.https.any.js index 866192e..5684d762 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits_curve25519.https.any.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits_curve25519.https.any.js
@@ -1,4 +1,5 @@ // META: title=WebCryptoAPI: deriveKey() Using ECDH with CFRG Elliptic Curves +// META: script=../util/helpers.js // META: script=cfrg_curves_bits_fixtures.js // META: script=cfrg_curves_bits.js
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits_curve448.tentative.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits_curve448.tentative.https.any.js index 32485c6..5e482ef 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits_curve448.tentative.https.any.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits_curve448.tentative.https.any.js
@@ -1,4 +1,5 @@ // META: title=WebCryptoAPI: deriveKey() Using ECDH with CFRG Elliptic Curves +// META: script=../util/helpers.js // META: script=cfrg_curves_bits_fixtures.js // META: script=cfrg_curves_bits.js
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys.js index 62f9e00a..cefc45a 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys.js
@@ -221,37 +221,4 @@ .then(function(results) {return {privateKeys: privateKeys, publicKeys: publicKeys, noDeriveKeyKeys: noDeriveKeyKeys, ecdhKeys: ecdhPublicKeys}}); } - // Compares two ArrayBuffer or ArrayBufferView objects. If bitCount is - // omitted, the two values must be the same length and have the same contents - // in every byte. If bitCount is included, only that leading number of bits - // have to match. - function equalBuffers(a, b, bitCount) { - var remainder; - - if (typeof bitCount === "undefined" && a.byteLength !== b.byteLength) { - return false; - } - - var aBytes = new Uint8Array(a); - var bBytes = new Uint8Array(b); - - var length = a.byteLength; - if (typeof bitCount !== "undefined") { - length = Math.floor(bitCount / 8); - } - - for (var i=0; i<length; i++) { - if (aBytes[i] !== bBytes[i]) { - return false; - } - } - - if (typeof bitCount !== "undefined") { - remainder = bitCount % 8; - return aBytes[length] >> (8 - remainder) === bBytes[length] >> (8 - remainder); - } - - return true; - } - }
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys_curve25519.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys_curve25519.https.any.js index 91390ba5c..8bcc201 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys_curve25519.https.any.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys_curve25519.https.any.js
@@ -1,4 +1,5 @@ // META: title=WebCryptoAPI: deriveKey() Using ECDH with CFRG Elliptic Curves +// META: script=../util/helpers.js // META: script=cfrg_curves_bits_fixtures.js // META: script=cfrg_curves_keys.js
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys_curve448.tentative.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys_curve448.tentative.https.any.js index b34e3663..0ed3954 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys_curve448.tentative.https.any.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys_curve448.tentative.https.any.js
@@ -1,4 +1,5 @@ // META: title=WebCryptoAPI: deriveKey() Using ECDH with CFRG Elliptic Curves +// META: script=../util/helpers.js // META: script=cfrg_curves_bits_fixtures.js // META: script=cfrg_curves_keys.js
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/derived_bits_length.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/derived_bits_length.https.any.js index 0aee2e3..862945c 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/derived_bits_length.https.any.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/derived_bits_length.https.any.js
@@ -1,4 +1,5 @@ // META: title=WebCryptoAPI: deriveBits() tests for the 'length' parameter +// META: script=../util/helpers.js // META: script=derived_bits_length.js // META: script=derived_bits_length_vectors.js // META: script=derived_bits_length_testcases.js
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/ecdh_bits.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/ecdh_bits.https.any.js index 37e3eb432..58a0cec 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/ecdh_bits.https.any.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/ecdh_bits.https.any.js
@@ -1,4 +1,5 @@ // META: title=WebCryptoAPI: deriveBits() Using ECDH +// META: script=../util/helpers.js // META: script=ecdh_bits.js // Define subtests from a `promise_test` to ensure the harness does not
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/ecdh_bits.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/ecdh_bits.js index 36b29c2..8e79909 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/ecdh_bits.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/ecdh_bits.js
@@ -230,37 +230,4 @@ .then(function(results) {return {privateKeys: privateKeys, publicKeys: publicKeys, ecdsaKeyPairs: ecdsaKeyPairs, noDeriveBitsKeys: noDeriveBitsKeys}}); } - // Compares two ArrayBuffer or ArrayBufferView objects. If bitCount is - // omitted, the two values must be the same length and have the same contents - // in every byte. If bitCount is included, only that leading number of bits - // have to match. - function equalBuffers(a, b, bitCount) { - var remainder; - - if (typeof bitCount === "undefined" && a.byteLength !== b.byteLength) { - return false; - } - - var aBytes = new Uint8Array(a); - var bBytes = new Uint8Array(b); - - var length = a.byteLength; - if (typeof bitCount !== "undefined") { - length = Math.floor(bitCount / 8); - } - - for (var i=0; i<length; i++) { - if (aBytes[i] !== bBytes[i]) { - return false; - } - } - - if (typeof bitCount !== "undefined") { - remainder = bitCount % 8; - return aBytes[length] >> (8 - remainder) === bBytes[length] >> (8 - remainder); - } - - return true; - } - }
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/ecdh_keys.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/ecdh_keys.https.any.js index d8235fc..6464dacf 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/ecdh_keys.https.any.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/ecdh_keys.https.any.js
@@ -1,4 +1,5 @@ // META: title=WebCryptoAPI: deriveKey() Using ECDH +// META: script=../util/helpers.js // META: script=ecdh_keys.js // Define subtests from a `promise_test` to ensure the harness does not
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/ecdh_keys.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/ecdh_keys.js index fce76f1..8c3d2aeb 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/ecdh_keys.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/ecdh_keys.js
@@ -209,37 +209,4 @@ .then(function(results) {return {privateKeys: privateKeys, publicKeys: publicKeys, ecdsaKeyPairs: ecdsaKeyPairs, noDeriveKeyKeys: noDeriveKeyKeys}}); } - // Compares two ArrayBuffer or ArrayBufferView objects. If bitCount is - // omitted, the two values must be the same length and have the same contents - // in every byte. If bitCount is included, only that leading number of bits - // have to match. - function equalBuffers(a, b, bitCount) { - var remainder; - - if (typeof bitCount === "undefined" && a.byteLength !== b.byteLength) { - return false; - } - - var aBytes = new Uint8Array(a); - var bBytes = new Uint8Array(b); - - var length = a.byteLength; - if (typeof bitCount !== "undefined") { - length = Math.floor(bitCount / 8); - } - - for (var i=0; i<length; i++) { - if (aBytes[i] !== bBytes[i]) { - return false; - } - } - - if (typeof bitCount !== "undefined") { - remainder = bitCount % 8; - return aBytes[length] >> (8 - remainder) === bBytes[length] >> (8 - remainder); - } - - return true; - } - }
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/hkdf.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/hkdf.https.any.js index 02492c3..3879ddb 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/hkdf.https.any.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/hkdf.https.any.js
@@ -3,6 +3,7 @@ // META: variant=?1001-2000 // META: variant=?2001-3000 // META: variant=?3001-last +// META: script=../util/helpers.js // META: script=/common/subset-tests.js // META: script=hkdf_vectors.js // META: script=hkdf.js
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/hkdf.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/hkdf.js index 0384f88e..08e8c0c 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/hkdf.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/hkdf.js
@@ -275,21 +275,4 @@ }); } - function equalBuffers(a, b) { - if (a.byteLength !== b.byteLength) { - return false; - } - - var aBytes = new Uint8Array(a); - var bBytes = new Uint8Array(b); - - for (var i=0; i<a.byteLength; i++) { - if (aBytes[i] !== bBytes[i]) { - return false; - } - } - - return true; - } - }
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/pbkdf2.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/pbkdf2.https.any.js index 2efbe52..cc2ed9b 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/pbkdf2.https.any.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/pbkdf2.https.any.js
@@ -9,6 +9,7 @@ // META: variant=?6001-7000 // META: variant=?7001-8000 // META: variant=?8001-last +// META: script=../util/helpers.js // META: script=/common/subset-tests.js // META: script=pbkdf2_vectors.js // META: script=pbkdf2.js
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/pbkdf2.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/pbkdf2.js index 38cf3b1..4d5b013 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/pbkdf2.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/pbkdf2.js
@@ -271,21 +271,4 @@ }); } - function equalBuffers(a, b) { - if (a.byteLength !== b.byteLength) { - return false; - } - - var aBytes = new Uint8Array(a); - var bBytes = new Uint8Array(b); - - for (var i=0; i<a.byteLength; i++) { - if (aBytes[i] !== bBytes[i]) { - return false; - } - } - - return true; - } - }
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/digest/cshake.tentative.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/digest/cshake.tentative.https.any.js index d0c23c0..8179366 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/digest/cshake.tentative.https.any.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/digest/cshake.tentative.https.any.js
@@ -1,4 +1,5 @@ // META: title=WebCryptoAPI: digest() cSHAKE algorithms +// META: script=../util/helpers.js // META: timeout=long var subtle = crypto.subtle; // Change to test prefixed implementations @@ -162,7 +163,7 @@ Object.keys(sourceData).forEach(function (size) { promise_test(function (test) { return crypto.subtle - .digest({ name: alg, length: length }, sourceData[size]) + .digest({ name: alg, outputLength: length }, sourceData[size]) .then(function (result) { assert_true( equalBuffers(result, digestedData[alg][length][size]), @@ -183,7 +184,7 @@ buffer[0] = sourceData[size][0]; return alg; }, - length + outputLength: length }, buffer) .then(function (result) { assert_true( @@ -196,7 +197,7 @@ promise_test(function (test) { var buffer = new Uint8Array(sourceData[size]); var promise = crypto.subtle - .digest({ name: alg, length: length }, buffer) + .digest({ name: alg, outputLength: length }, buffer) .then(function (result) { assert_true( equalBuffers(result, digestedData[alg][length][size]), @@ -217,7 +218,7 @@ buffer.buffer.transfer(); return alg; }, - length + outputLength: length }, buffer) .then(function (result) { assert_true( @@ -230,7 +231,7 @@ promise_test(function (test) { var buffer = new Uint8Array(sourceData[size]); var promise = crypto.subtle - .digest({ name: alg, length: length }, buffer) + .digest({ name: alg, outputLength: length }, buffer) .then(function (result) { assert_true( equalBuffers(result, digestedData[alg][length][size]), @@ -245,17 +246,3 @@ }); }); }); - -function equalBuffers(a, b) { - if (a.byteLength !== b.byteLength) { - return false; - } - var aBytes = new Uint8Array(a); - var bBytes = new Uint8Array(b); - for (var i = 0; i < a.byteLength; i++) { - if (aBytes[i] !== bBytes[i]) { - return false; - } - } - return true; -}
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/digest/digest.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/digest/digest.https.any.js index 47bc220..38ce85ec 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/digest/digest.https.any.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/digest/digest.https.any.js
@@ -1,4 +1,5 @@ // META: title=WebCryptoAPI: digest() +// META: script=../util/helpers.js // META: timeout=long var subtle = crypto.subtle; // Change to test prefixed implementations @@ -176,33 +177,3 @@ done(); - - - // Returns a copy of the sourceBuffer it is sent. - function copyBuffer(sourceBuffer) { - var source = new Uint8Array(sourceBuffer); - var copy = new Uint8Array(sourceBuffer.byteLength) - - for (var i=0; i<source.byteLength; i++) { - copy[i] = source[i]; - } - - return copy; - } - - function equalBuffers(a, b) { - if (a.byteLength !== b.byteLength) { - return false; - } - - var aBytes = new Uint8Array(a); - var bBytes = new Uint8Array(b); - - for (var i=0; i<a.byteLength; i++) { - if (aBytes[i] !== bBytes[i]) { - return false; - } - } - - return true; - }
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/digest/kangarootwelve.tentative.https.any-expected.txt b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/digest/kangarootwelve.tentative.https.any-expected.txt new file mode 100644 index 0000000..10db00e --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/digest/kangarootwelve.tentative.https.any-expected.txt
@@ -0,0 +1,300 @@ +This is a testharness.js-based test. +Found 148 FAIL, 0 TIMEOUT, 0 NOTRUN. +[FAIL] KT128 with 80256 bit output, verify last 32 bytes + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 with 80512 bit output, verify last 64 bytes + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #1 (256 bit output, 0 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #2 (512 bit output, 0 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #3 (256 bit output, 1 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #3 (256 bit output, 1 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #3 (256 bit output, 1 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #3 (256 bit output, 1 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #3 (256 bit output, 1 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #4 (256 bit output, 17 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #4 (256 bit output, 17 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #4 (256 bit output, 17 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #4 (256 bit output, 17 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #4 (256 bit output, 17 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #5 (256 bit output, 289 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #5 (256 bit output, 289 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #5 (256 bit output, 289 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #5 (256 bit output, 289 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #5 (256 bit output, 289 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #6 (256 bit output, 4913 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #6 (256 bit output, 4913 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #6 (256 bit output, 4913 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #6 (256 bit output, 4913 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #6 (256 bit output, 4913 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #7 (256 bit output, 83521 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #7 (256 bit output, 83521 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #7 (256 bit output, 83521 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #7 (256 bit output, 83521 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #7 (256 bit output, 83521 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #8 (256 bit output, 1419857 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #8 (256 bit output, 1419857 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #8 (256 bit output, 1419857 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #8 (256 bit output, 1419857 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #8 (256 bit output, 1419857 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #9 (256 bit output, 24137569 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #9 (256 bit output, 24137569 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #9 (256 bit output, 24137569 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #9 (256 bit output, 24137569 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #9 (256 bit output, 24137569 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #10 (256 bit output, 0 byte input, C=1 bytes) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #11 (256 bit output, 1 byte input, C=41 bytes) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #11 (256 bit output, 1 byte input, C=41 bytes) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #11 (256 bit output, 1 byte input, C=41 bytes) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #11 (256 bit output, 1 byte input, C=41 bytes) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #11 (256 bit output, 1 byte input, C=41 bytes) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #12 (256 bit output, 3 byte input, C=1681 bytes) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #12 (256 bit output, 3 byte input, C=1681 bytes) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #12 (256 bit output, 3 byte input, C=1681 bytes) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #12 (256 bit output, 3 byte input, C=1681 bytes) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #12 (256 bit output, 3 byte input, C=1681 bytes) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #13 (256 bit output, 7 byte input, C=68921 bytes) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #13 (256 bit output, 7 byte input, C=68921 bytes) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #13 (256 bit output, 7 byte input, C=68921 bytes) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #13 (256 bit output, 7 byte input, C=68921 bytes) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #13 (256 bit output, 7 byte input, C=68921 bytes) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #14 (256 bit output, 8191 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #14 (256 bit output, 8191 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #14 (256 bit output, 8191 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #14 (256 bit output, 8191 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #14 (256 bit output, 8191 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #15 (256 bit output, 8192 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #15 (256 bit output, 8192 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #15 (256 bit output, 8192 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #15 (256 bit output, 8192 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #15 (256 bit output, 8192 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #16 (256 bit output, 8192 byte input, C=8189 bytes) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #16 (256 bit output, 8192 byte input, C=8189 bytes) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #16 (256 bit output, 8192 byte input, C=8189 bytes) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #16 (256 bit output, 8192 byte input, C=8189 bytes) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #16 (256 bit output, 8192 byte input, C=8189 bytes) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #17 (256 bit output, 8192 byte input, C=8190 bytes) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #17 (256 bit output, 8192 byte input, C=8190 bytes) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #17 (256 bit output, 8192 byte input, C=8190 bytes) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #17 (256 bit output, 8192 byte input, C=8190 bytes) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #17 (256 bit output, 8192 byte input, C=8190 bytes) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #1 (512 bit output, 0 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #2 (1024 bit output, 0 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #3 (512 bit output, 1 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #3 (512 bit output, 1 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #3 (512 bit output, 1 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #3 (512 bit output, 1 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #3 (512 bit output, 1 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #4 (512 bit output, 17 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #4 (512 bit output, 17 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #4 (512 bit output, 17 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #4 (512 bit output, 17 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #4 (512 bit output, 17 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #5 (512 bit output, 289 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #5 (512 bit output, 289 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #5 (512 bit output, 289 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #5 (512 bit output, 289 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #5 (512 bit output, 289 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #6 (512 bit output, 4913 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #6 (512 bit output, 4913 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #6 (512 bit output, 4913 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #6 (512 bit output, 4913 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #6 (512 bit output, 4913 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #7 (512 bit output, 83521 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #7 (512 bit output, 83521 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #7 (512 bit output, 83521 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #7 (512 bit output, 83521 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #7 (512 bit output, 83521 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #8 (512 bit output, 1419857 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #8 (512 bit output, 1419857 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #8 (512 bit output, 1419857 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #8 (512 bit output, 1419857 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #8 (512 bit output, 1419857 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #9 (512 bit output, 24137569 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #9 (512 bit output, 24137569 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #9 (512 bit output, 24137569 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #9 (512 bit output, 24137569 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #9 (512 bit output, 24137569 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #10 (512 bit output, 0 byte input, C=1 bytes) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #11 (512 bit output, 1 byte input, C=41 bytes) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #11 (512 bit output, 1 byte input, C=41 bytes) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #11 (512 bit output, 1 byte input, C=41 bytes) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #11 (512 bit output, 1 byte input, C=41 bytes) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #11 (512 bit output, 1 byte input, C=41 bytes) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #12 (512 bit output, 3 byte input, C=1681 bytes) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #12 (512 bit output, 3 byte input, C=1681 bytes) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #12 (512 bit output, 3 byte input, C=1681 bytes) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #12 (512 bit output, 3 byte input, C=1681 bytes) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #12 (512 bit output, 3 byte input, C=1681 bytes) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #13 (512 bit output, 7 byte input, C=68921 bytes) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #13 (512 bit output, 7 byte input, C=68921 bytes) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #13 (512 bit output, 7 byte input, C=68921 bytes) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #13 (512 bit output, 7 byte input, C=68921 bytes) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #13 (512 bit output, 7 byte input, C=68921 bytes) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #14 (512 bit output, 8191 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #14 (512 bit output, 8191 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #14 (512 bit output, 8191 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #14 (512 bit output, 8191 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #14 (512 bit output, 8191 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #15 (512 bit output, 8192 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #15 (512 bit output, 8192 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #15 (512 bit output, 8192 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #15 (512 bit output, 8192 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #15 (512 bit output, 8192 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #16 (512 bit output, 8192 byte input, C=8189 bytes) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #16 (512 bit output, 8192 byte input, C=8189 bytes) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #16 (512 bit output, 8192 byte input, C=8189 bytes) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #16 (512 bit output, 8192 byte input, C=8189 bytes) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #16 (512 bit output, 8192 byte input, C=8189 bytes) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #17 (512 bit output, 8192 byte input, C=8190 bytes) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #17 (512 bit output, 8192 byte input, C=8190 bytes) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #17 (512 bit output, 8192 byte input, C=8190 bytes) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #17 (512 bit output, 8192 byte input, C=8190 bytes) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #17 (512 bit output, 8192 byte input, C=8190 bytes) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/digest/kangarootwelve.tentative.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/digest/kangarootwelve.tentative.https.any.js new file mode 100644 index 0000000..9f800b7 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/digest/kangarootwelve.tentative.https.any.js
@@ -0,0 +1,324 @@ +// META: title=WebCryptoAPI: digest() KangarooTwelve algorithms +// META: script=../util/helpers.js +// META: timeout=long + +var subtle = crypto.subtle; // Change to test prefixed implementations + +// Generates a Uint8Array of length n by repeating the pattern 00 01 02 .. F9 FA. +function ptn(n) { + var buf = new Uint8Array(n); + for (var i = 0; i < n; i++) + buf[i] = i % 251; + return buf; +} + +function hexToBytes(hex) { + var bytes = new Uint8Array(hex.length / 2); + for (var i = 0; i < hex.length; i += 2) + bytes[i / 2] = parseInt(hex.substring(i, i + 2), 16); + return bytes; +} + +// RFC 9861 Section 5 test vectors +// [input, outputLengthBits, expected hex(, customization)] +var kt128Vectors = [ + [new Uint8Array(0), 256, + '1ac2d450fc3b4205d19da7bfca1b3751' + + '3c0803577ac7167f06fe2ce1f0ef39e5'], + [new Uint8Array(0), 512, + '1ac2d450fc3b4205d19da7bfca1b3751' + + '3c0803577ac7167f06fe2ce1f0ef39e5' + + '4269c056b8c82e48276038b6d292966c' + + 'c07a3d4645272e31ff38508139eb0a71'], + [ptn(1), 256, + '2bda92450e8b147f8a7cb629e784a058' + + 'efca7cf7d8218e02d345dfaa65244a1f'], + [ptn(17), 256, + '6bf75fa2239198db4772e36478f8e19b' + + '0f371205f6a9a93a273f51df37122888'], + [ptn(Math.pow(17, 2)), 256, + '0c315ebcdedbf61426de7dcf8fb725d1' + + 'e74675d7f5327a5067f367b108ecb67c'], + [ptn(Math.pow(17, 3)), 256, + 'cb552e2ec77d9910701d578b457ddf77' + + '2c12e322e4ee7fe417f92c758f0d59d0'], + [ptn(Math.pow(17, 4)), 256, + '8701045e22205345ff4dda05555cbb5c' + + '3af1a771c2b89baef37db43d9998b9fe'], + [ptn(Math.pow(17, 5)), 256, + '844d610933b1b9963cbdeb5ae3b6b05c' + + 'c7cbd67ceedf883eb678a0a8e0371682'], + [ptn(Math.pow(17, 6)), 256, + '3c390782a8a4e89fa6367f72feaaf132' + + '55c8d95878481d3cd8ce85f58e880af8'], + [new Uint8Array(0), 256, + 'fab658db63e94a246188bf7af69a1330' + + '45f46ee984c56e3c3328caaf1aa1a583', ptn(1)], + [new Uint8Array([0xff]), 256, + 'd848c5068ced736f4462159b9867fd4c' + + '20b808acc3d5bc48e0b06ba0a3762ec4', ptn(41)], + [new Uint8Array([0xff, 0xff, 0xff]), 256, + 'c389e5009ae57120854c2e8c64670ac0' + + '1358cf4c1baf89447a724234dc7ced74', ptn(Math.pow(41, 2))], + [new Uint8Array([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]), 256, + '75d2f86a2e644566726b4fbcfc5657b9' + + 'dbcf070c7b0dca06450ab291d7443bcf', ptn(Math.pow(41, 3))], + [ptn(8191), 256, + '1b577636f723643e990cc7d6a6598374' + + '36fd6a103626600eb8301cd1dbe553d6'], + [ptn(8192), 256, + '48f256f6772f9edfb6a8b661ec92dc93' + + 'b95ebd05a08a17b39ae3490870c926c3'], + [ptn(8192), 256, + '3ed12f70fb05ddb58689510ab3e4d23c' + + '6c6033849aa01e1d8c220a297fedcd0b', ptn(8189)], + [ptn(8192), 256, + '6a7c1b6a5cd0d8c9ca943a4a216cc646' + + '04559a2ea45f78570a15253d67ba00ae', ptn(8190)], +]; + +var kt256Vectors = [ + [new Uint8Array(0), 512, + 'b23d2e9cea9f4904e02bec06817fc10c' + + 'e38ce8e93ef4c89e6537076af8646404' + + 'e3e8b68107b8833a5d30490aa3348235' + + '3fd4adc7148ecb782855003aaebde4a9'], + [new Uint8Array(0), 1024, + 'b23d2e9cea9f4904e02bec06817fc10c' + + 'e38ce8e93ef4c89e6537076af8646404' + + 'e3e8b68107b8833a5d30490aa3348235' + + '3fd4adc7148ecb782855003aaebde4a9' + + 'b0925319d8ea1e121a609821ec19efea' + + '89e6d08daee1662b69c840289f188ba8' + + '60f55760b61f82114c030c97e5178449' + + '608ccd2cd2d919fc7829ff69931ac4d0'], + [ptn(1), 512, + '0d005a194085360217128cf17f91e1f7' + + '1314efa5564539d444912e3437efa17f' + + '82db6f6ffe76e781eaa068bce01f2bbf' + + '81eacb983d7230f2fb02834a21b1ddd0'], + [ptn(17), 512, + '1ba3c02b1fc514474f06c8979978a905' + + '6c8483f4a1b63d0dccefe3a28a2f323e' + + '1cdcca40ebf006ac76ef039715234683' + + '7b1277d3e7faa9c9653b19075098527b'], + [ptn(Math.pow(17, 2)), 512, + 'de8ccbc63e0f133ebb4416814d4c66f6' + + '91bbf8b6a61ec0a7700f836b086cb029' + + 'd54f12ac7159472c72db118c35b4e6aa' + + '213c6562caaa9dcc518959e69b10f3ba'], + [ptn(Math.pow(17, 3)), 512, + '647efb49fe9d717500171b41e7f11bd4' + + '91544443209997ce1c2530d15eb1ffbb' + + '598935ef954528ffc152b1e4d731ee26' + + '83680674365cd191d562bae753b84aa5'], + [ptn(Math.pow(17, 4)), 512, + 'b06275d284cd1cf205bcbe57dccd3ec1' + + 'ff6686e3ed15776383e1f2fa3c6ac8f0' + + '8bf8a162829db1a44b2a43ff83dd89c3' + + 'cf1ceb61ede659766d5ccf817a62ba8d'], + [ptn(Math.pow(17, 5)), 512, + '9473831d76a4c7bf77ace45b59f1458b' + + '1673d64bcd877a7c66b2664aa6dd149e' + + '60eab71b5c2bab858c074ded81ddce2b' + + '4022b5215935c0d4d19bf511aeeb0772'], + [ptn(Math.pow(17, 6)), 512, + '0652b740d78c5e1f7c8dcc1777097382' + + '768b7ff38f9a7a20f29f413bb1b3045b' + + '31a5578f568f911e09cf44746da84224' + + 'a5266e96a4a535e871324e4f9c7004da'], + [new Uint8Array(0), 512, + '9280f5cc39b54a5a594ec63de0bb9937' + + '1e4609d44bf845c2f5b8c316d72b1598' + + '11f748f23e3fabbe5c3226ec96c62186' + + 'df2d33e9df74c5069ceecbb4dd10eff6', ptn(1)], + [new Uint8Array([0xff]), 512, + '47ef96dd616f200937aa7847e34ec2fe' + + 'ae8087e3761dc0f8c1a154f51dc9ccf8' + + '45d7adbce57ff64b639722c6a1672e3b' + + 'f5372d87e00aff89be97240756998853', ptn(41)], + [new Uint8Array([0xff, 0xff, 0xff]), 512, + '3b48667a5051c5966c53c5d42b95de45' + + '1e05584e7806e2fb765eda959074172c' + + 'b438a9e91dde337c98e9c41bed94c4e0' + + 'aef431d0b64ef2324f7932caa6f54969', ptn(Math.pow(41, 2))], + [new Uint8Array([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]), 512, + 'e0911cc00025e1540831e266d94add9b' + + '98712142b80d2629e643aac4efaf5a3a' + + '30a88cbf4ac2a91a2432743054fbcc98' + + '97670e86ba8cec2fc2ace9c966369724', ptn(Math.pow(41, 3))], + [ptn(8191), 512, + '3081434d93a4108d8d8a3305b89682ce' + + 'bedc7ca4ea8a3ce869fbb73cbe4a58ee' + + 'f6f24de38ffc170514c70e7ab2d01f03' + + '812616e863d769afb3753193ba045b20'], + [ptn(8192), 512, + 'c6ee8e2ad3200c018ac87aaa031cdac2' + + '2121b412d07dc6e0dccbb53423747e9a' + + '1c18834d99df596cf0cf4b8dfafb7bf0' + + '2d139d0c9035725adc1a01b7230a41fa'], + [ptn(8192), 512, + '74e47879f10a9c5d11bd2da7e194fe57' + + 'e86378bf3c3f7448eff3c576a0f18c5c' + + 'aae0999979512090a7f348af4260d4de' + + '3c37f1ecaf8d2c2c96c1d16c64b12496', ptn(8189)], + [ptn(8192), 512, + 'f4b5908b929ffe01e0f79ec2f21243d4' + + '1a396b2e7303a6af1d6399cd6c7a0a2d' + + 'd7c4f607e8277f9c9b1cb4ab9ddc59d4' + + 'b92d1fc7558441f1832c3279a4241b8b', ptn(8190)], +]; + +// Large output tests: verify last N bytes of extended output +var largeOutputTests = [ + // [algorithm, outputLengthBits, lastNBytes, expectedLastBytes] + ['KT128', 10032 * 8, 32, + 'e8dc563642f7228c84684c898405d3a8' + + '34799158c079b12880277a1d28e2ff6d'], + ['KT256', 10064 * 8, 64, + 'ad4a1d718cf950506709a4c33396139b' + + '4449041fc79a05d68da35f1e453522e0' + + '56c64fe94958e7085f2964888259b993' + + '2752f3ccd855288efee5fcbb8b563069'], +]; + +largeOutputTests.forEach(function (entry) { + var alg = entry[0]; + var outputLength = entry[1]; + var lastN = entry[2]; + var expected = entry[3]; + + promise_test(function (test) { + return subtle + .digest({ name: alg, outputLength: outputLength }, new Uint8Array(0)) + .then(function (result) { + var full = new Uint8Array(result); + var last = full.slice(full.length - lastN); + assert_true( + equalBuffers(last.buffer, hexToBytes(expected)), + 'last ' + lastN + ' bytes of digest match expected' + ); + }); + }, alg + ' with ' + outputLength + ' bit output, verify last ' + lastN + ' bytes'); +}); + +function customizationEqual(emptyDataVector, customization) { + return equalBuffers(customization ?? new Uint8Array(0), emptyDataVector[3] ?? new Uint8Array(0)); +} + +function outputLengthLessOrEqual(emptyDataVector, outputLength) { + return outputLength <= emptyDataVector[1]; +} + +var allVectors = { + KT128: kt128Vectors, + KT256: kt256Vectors, +}; + +Object.keys(allVectors).forEach(function (alg) { + var emptyDataVector = allVectors[alg][0]; + allVectors[alg].forEach(function (vector, i) { + var input = vector[0]; + var outputLength = vector[1]; + var expected = vector[2]; + var customization = vector[3]; + + var algorithmParams = { name: alg, outputLength: outputLength }; + if (customization !== undefined) + algorithmParams.customization = customization; + + var label = alg + ' vector #' + (i + 1) + + ' (' + outputLength + ' bit output, ' + input.length + ' byte input' + + (customization !== undefined ? ', C=' + customization.length + ' bytes' : '') + ')'; + + promise_test(function (test) { + return subtle + .digest(algorithmParams, input) + .then(function (result) { + assert_true( + equalBuffers(result, hexToBytes(expected)), + 'digest matches expected' + ); + }); + }, label); + + if (input.length > 0) { + promise_test(function (test) { + var buffer = new Uint8Array(input); + // Alter the buffer before calling digest + buffer[0] = ~buffer[0]; + return subtle + .digest({ + get name() { + // Alter the buffer back while calling digest + buffer[0] = input[0]; + return alg; + }, + outputLength: outputLength, + customization: customization, + }, buffer) + .then(function (result) { + assert_true( + equalBuffers(result, hexToBytes(expected)), + 'digest matches expected' + ); + }); + }, label + ' and altered buffer during call'); + + promise_test(function (test) { + var buffer = new Uint8Array(input); + var promise = subtle + .digest(algorithmParams, buffer) + .then(function (result) { + assert_true( + equalBuffers(result, hexToBytes(expected)), + 'digest matches expected' + ); + }); + // Alter the buffer after calling digest + buffer[0] = ~buffer[0]; + return promise; + }, label + ' and altered buffer after call'); + + promise_test(function (test) { + var buffer = new Uint8Array(input); + return subtle + .digest({ + get name() { + // Transfer the buffer while calling digest + buffer.buffer.transfer(); + return alg; + }, + outputLength: outputLength, + customization: customization, + }, buffer) + .then(function (result) { + if (customizationEqual(emptyDataVector, customization) && outputLengthLessOrEqual(emptyDataVector, outputLength)) { + assert_true( + equalBuffers(result, Uint8Array.fromHex(emptyDataVector[2]).subarray(0, outputLength / 8)), + 'digest on transferred buffer should match result for empty buffer' + ); + } else { + assert_equals(result.byteLength, outputLength / 8, + 'digest on transferred buffer should have correct output length'); + } + }); + }, label + ' and transferred buffer during call'); + + promise_test(function (test) { + var buffer = new Uint8Array(input); + var promise = subtle + .digest(algorithmParams, buffer) + .then(function (result) { + assert_true( + equalBuffers(result, hexToBytes(expected)), + 'digest matches expected' + ); + }); + // Transfer the buffer after calling digest + buffer.buffer.transfer(); + return promise; + }, label + ' and transferred buffer after call'); + } + }); +});
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/digest/kangarootwelve.tentative.https.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/digest/kangarootwelve.tentative.https.any.worker-expected.txt new file mode 100644 index 0000000..10db00e --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/digest/kangarootwelve.tentative.https.any.worker-expected.txt
@@ -0,0 +1,300 @@ +This is a testharness.js-based test. +Found 148 FAIL, 0 TIMEOUT, 0 NOTRUN. +[FAIL] KT128 with 80256 bit output, verify last 32 bytes + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 with 80512 bit output, verify last 64 bytes + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #1 (256 bit output, 0 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #2 (512 bit output, 0 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #3 (256 bit output, 1 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #3 (256 bit output, 1 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #3 (256 bit output, 1 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #3 (256 bit output, 1 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #3 (256 bit output, 1 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #4 (256 bit output, 17 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #4 (256 bit output, 17 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #4 (256 bit output, 17 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #4 (256 bit output, 17 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #4 (256 bit output, 17 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #5 (256 bit output, 289 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #5 (256 bit output, 289 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #5 (256 bit output, 289 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #5 (256 bit output, 289 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #5 (256 bit output, 289 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #6 (256 bit output, 4913 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #6 (256 bit output, 4913 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #6 (256 bit output, 4913 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #6 (256 bit output, 4913 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #6 (256 bit output, 4913 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #7 (256 bit output, 83521 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #7 (256 bit output, 83521 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #7 (256 bit output, 83521 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #7 (256 bit output, 83521 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #7 (256 bit output, 83521 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #8 (256 bit output, 1419857 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #8 (256 bit output, 1419857 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #8 (256 bit output, 1419857 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #8 (256 bit output, 1419857 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #8 (256 bit output, 1419857 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #9 (256 bit output, 24137569 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #9 (256 bit output, 24137569 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #9 (256 bit output, 24137569 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #9 (256 bit output, 24137569 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #9 (256 bit output, 24137569 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #10 (256 bit output, 0 byte input, C=1 bytes) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #11 (256 bit output, 1 byte input, C=41 bytes) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #11 (256 bit output, 1 byte input, C=41 bytes) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #11 (256 bit output, 1 byte input, C=41 bytes) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #11 (256 bit output, 1 byte input, C=41 bytes) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #11 (256 bit output, 1 byte input, C=41 bytes) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #12 (256 bit output, 3 byte input, C=1681 bytes) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #12 (256 bit output, 3 byte input, C=1681 bytes) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #12 (256 bit output, 3 byte input, C=1681 bytes) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #12 (256 bit output, 3 byte input, C=1681 bytes) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #12 (256 bit output, 3 byte input, C=1681 bytes) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #13 (256 bit output, 7 byte input, C=68921 bytes) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #13 (256 bit output, 7 byte input, C=68921 bytes) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #13 (256 bit output, 7 byte input, C=68921 bytes) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #13 (256 bit output, 7 byte input, C=68921 bytes) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #13 (256 bit output, 7 byte input, C=68921 bytes) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #14 (256 bit output, 8191 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #14 (256 bit output, 8191 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #14 (256 bit output, 8191 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #14 (256 bit output, 8191 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #14 (256 bit output, 8191 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #15 (256 bit output, 8192 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #15 (256 bit output, 8192 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #15 (256 bit output, 8192 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #15 (256 bit output, 8192 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #15 (256 bit output, 8192 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #16 (256 bit output, 8192 byte input, C=8189 bytes) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #16 (256 bit output, 8192 byte input, C=8189 bytes) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #16 (256 bit output, 8192 byte input, C=8189 bytes) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #16 (256 bit output, 8192 byte input, C=8189 bytes) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #16 (256 bit output, 8192 byte input, C=8189 bytes) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #17 (256 bit output, 8192 byte input, C=8190 bytes) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #17 (256 bit output, 8192 byte input, C=8190 bytes) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #17 (256 bit output, 8192 byte input, C=8190 bytes) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #17 (256 bit output, 8192 byte input, C=8190 bytes) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT128 vector #17 (256 bit output, 8192 byte input, C=8190 bytes) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #1 (512 bit output, 0 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #2 (1024 bit output, 0 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #3 (512 bit output, 1 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #3 (512 bit output, 1 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #3 (512 bit output, 1 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #3 (512 bit output, 1 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #3 (512 bit output, 1 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #4 (512 bit output, 17 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #4 (512 bit output, 17 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #4 (512 bit output, 17 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #4 (512 bit output, 17 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #4 (512 bit output, 17 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #5 (512 bit output, 289 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #5 (512 bit output, 289 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #5 (512 bit output, 289 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #5 (512 bit output, 289 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #5 (512 bit output, 289 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #6 (512 bit output, 4913 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #6 (512 bit output, 4913 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #6 (512 bit output, 4913 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #6 (512 bit output, 4913 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #6 (512 bit output, 4913 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #7 (512 bit output, 83521 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #7 (512 bit output, 83521 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #7 (512 bit output, 83521 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #7 (512 bit output, 83521 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #7 (512 bit output, 83521 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #8 (512 bit output, 1419857 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #8 (512 bit output, 1419857 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #8 (512 bit output, 1419857 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #8 (512 bit output, 1419857 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #8 (512 bit output, 1419857 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #9 (512 bit output, 24137569 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #9 (512 bit output, 24137569 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #9 (512 bit output, 24137569 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #9 (512 bit output, 24137569 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #9 (512 bit output, 24137569 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #10 (512 bit output, 0 byte input, C=1 bytes) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #11 (512 bit output, 1 byte input, C=41 bytes) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #11 (512 bit output, 1 byte input, C=41 bytes) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #11 (512 bit output, 1 byte input, C=41 bytes) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #11 (512 bit output, 1 byte input, C=41 bytes) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #11 (512 bit output, 1 byte input, C=41 bytes) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #12 (512 bit output, 3 byte input, C=1681 bytes) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #12 (512 bit output, 3 byte input, C=1681 bytes) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #12 (512 bit output, 3 byte input, C=1681 bytes) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #12 (512 bit output, 3 byte input, C=1681 bytes) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #12 (512 bit output, 3 byte input, C=1681 bytes) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #13 (512 bit output, 7 byte input, C=68921 bytes) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #13 (512 bit output, 7 byte input, C=68921 bytes) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #13 (512 bit output, 7 byte input, C=68921 bytes) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #13 (512 bit output, 7 byte input, C=68921 bytes) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #13 (512 bit output, 7 byte input, C=68921 bytes) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #14 (512 bit output, 8191 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #14 (512 bit output, 8191 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #14 (512 bit output, 8191 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #14 (512 bit output, 8191 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #14 (512 bit output, 8191 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #15 (512 bit output, 8192 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #15 (512 bit output, 8192 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #15 (512 bit output, 8192 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #15 (512 bit output, 8192 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #15 (512 bit output, 8192 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #16 (512 bit output, 8192 byte input, C=8189 bytes) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #16 (512 bit output, 8192 byte input, C=8189 bytes) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #16 (512 bit output, 8192 byte input, C=8189 bytes) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #16 (512 bit output, 8192 byte input, C=8189 bytes) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #16 (512 bit output, 8192 byte input, C=8189 bytes) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #17 (512 bit output, 8192 byte input, C=8190 bytes) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #17 (512 bit output, 8192 byte input, C=8190 bytes) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #17 (512 bit output, 8192 byte input, C=8190 bytes) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #17 (512 bit output, 8192 byte input, C=8190 bytes) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] KT256 vector #17 (512 bit output, 8192 byte input, C=8190 bytes) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/digest/sha3.tentative.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/digest/sha3.tentative.https.any.js index 4ae9979..f9f38ead 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/digest/sha3.tentative.https.any.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/digest/sha3.tentative.https.any.js
@@ -1,4 +1,5 @@ // META: title=WebCryptoAPI: digest() SHA-3 algorithms +// META: script=../util/helpers.js // META: timeout=long var subtle = crypto.subtle; // Change to test prefixed implementations @@ -176,17 +177,3 @@ } }); }); - -function equalBuffers(a, b) { - if (a.byteLength !== b.byteLength) { - return false; - } - var aBytes = new Uint8Array(a); - var bBytes = new Uint8Array(b); - for (var i = 0; i < a.byteLength; i++) { - if (aBytes[i] !== bBytes[i]) { - return false; - } - } - return true; -}
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/digest/turboshake.tentative.https.any-expected.txt b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/digest/turboshake.tentative.https.any-expected.txt new file mode 100644 index 0000000..7fe54c9c --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/digest/turboshake.tentative.https.any-expected.txt
@@ -0,0 +1,274 @@ +This is a testharness.js-based test. +Found 135 FAIL, 0 TIMEOUT, 0 NOTRUN. +[FAIL] TurboSHAKE128 with 80256 bit output, verify last 32 bytes + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 with 80256 bit output, verify last 32 bytes + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #1 (256 bit output, 0 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #2 (512 bit output, 0 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #3 (256 bit output, 1 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #3 (256 bit output, 1 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #3 (256 bit output, 1 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #3 (256 bit output, 1 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #3 (256 bit output, 1 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #4 (256 bit output, 17 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #4 (256 bit output, 17 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #4 (256 bit output, 17 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #4 (256 bit output, 17 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #4 (256 bit output, 17 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #5 (256 bit output, 289 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #5 (256 bit output, 289 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #5 (256 bit output, 289 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #5 (256 bit output, 289 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #5 (256 bit output, 289 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #6 (256 bit output, 4913 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #6 (256 bit output, 4913 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #6 (256 bit output, 4913 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #6 (256 bit output, 4913 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #6 (256 bit output, 4913 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #7 (256 bit output, 83521 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #7 (256 bit output, 83521 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #7 (256 bit output, 83521 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #7 (256 bit output, 83521 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #7 (256 bit output, 83521 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #8 (256 bit output, 1419857 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #8 (256 bit output, 1419857 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #8 (256 bit output, 1419857 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #8 (256 bit output, 1419857 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #8 (256 bit output, 1419857 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #9 (256 bit output, 24137569 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #9 (256 bit output, 24137569 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #9 (256 bit output, 24137569 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #9 (256 bit output, 24137569 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #9 (256 bit output, 24137569 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #10 (256 bit output, 3 byte input, D=0x1) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #10 (256 bit output, 3 byte input, D=0x1) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #10 (256 bit output, 3 byte input, D=0x1) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #10 (256 bit output, 3 byte input, D=0x1) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #10 (256 bit output, 3 byte input, D=0x1) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #11 (256 bit output, 1 byte input, D=0x6) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #11 (256 bit output, 1 byte input, D=0x6) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #11 (256 bit output, 1 byte input, D=0x6) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #11 (256 bit output, 1 byte input, D=0x6) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #11 (256 bit output, 1 byte input, D=0x6) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #12 (256 bit output, 3 byte input, D=0x7) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #12 (256 bit output, 3 byte input, D=0x7) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #12 (256 bit output, 3 byte input, D=0x7) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #12 (256 bit output, 3 byte input, D=0x7) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #12 (256 bit output, 3 byte input, D=0x7) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #13 (256 bit output, 7 byte input, D=0xb) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #13 (256 bit output, 7 byte input, D=0xb) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #13 (256 bit output, 7 byte input, D=0xb) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #13 (256 bit output, 7 byte input, D=0xb) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #13 (256 bit output, 7 byte input, D=0xb) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #14 (256 bit output, 1 byte input, D=0x30) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #14 (256 bit output, 1 byte input, D=0x30) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #14 (256 bit output, 1 byte input, D=0x30) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #14 (256 bit output, 1 byte input, D=0x30) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #14 (256 bit output, 1 byte input, D=0x30) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #15 (256 bit output, 3 byte input, D=0x7f) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #15 (256 bit output, 3 byte input, D=0x7f) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #15 (256 bit output, 3 byte input, D=0x7f) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #15 (256 bit output, 3 byte input, D=0x7f) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #15 (256 bit output, 3 byte input, D=0x7f) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #1 (512 bit output, 0 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #2 (512 bit output, 1 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #2 (512 bit output, 1 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #2 (512 bit output, 1 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #2 (512 bit output, 1 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #2 (512 bit output, 1 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #3 (512 bit output, 17 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #3 (512 bit output, 17 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #3 (512 bit output, 17 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #3 (512 bit output, 17 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #3 (512 bit output, 17 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #4 (512 bit output, 289 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #4 (512 bit output, 289 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #4 (512 bit output, 289 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #4 (512 bit output, 289 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #4 (512 bit output, 289 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #5 (512 bit output, 4913 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #5 (512 bit output, 4913 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #5 (512 bit output, 4913 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #5 (512 bit output, 4913 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #5 (512 bit output, 4913 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #6 (512 bit output, 83521 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #6 (512 bit output, 83521 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #6 (512 bit output, 83521 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #6 (512 bit output, 83521 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #6 (512 bit output, 83521 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #7 (512 bit output, 1419857 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #7 (512 bit output, 1419857 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #7 (512 bit output, 1419857 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #7 (512 bit output, 1419857 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #7 (512 bit output, 1419857 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #8 (512 bit output, 24137569 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #8 (512 bit output, 24137569 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #8 (512 bit output, 24137569 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #8 (512 bit output, 24137569 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #8 (512 bit output, 24137569 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #9 (512 bit output, 3 byte input, D=0x1) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #9 (512 bit output, 3 byte input, D=0x1) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #9 (512 bit output, 3 byte input, D=0x1) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #9 (512 bit output, 3 byte input, D=0x1) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #9 (512 bit output, 3 byte input, D=0x1) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #10 (512 bit output, 1 byte input, D=0x6) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #10 (512 bit output, 1 byte input, D=0x6) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #10 (512 bit output, 1 byte input, D=0x6) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #10 (512 bit output, 1 byte input, D=0x6) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #10 (512 bit output, 1 byte input, D=0x6) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #11 (512 bit output, 3 byte input, D=0x7) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #11 (512 bit output, 3 byte input, D=0x7) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #11 (512 bit output, 3 byte input, D=0x7) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #11 (512 bit output, 3 byte input, D=0x7) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #11 (512 bit output, 3 byte input, D=0x7) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #12 (512 bit output, 7 byte input, D=0xb) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #12 (512 bit output, 7 byte input, D=0xb) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #12 (512 bit output, 7 byte input, D=0xb) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #12 (512 bit output, 7 byte input, D=0xb) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #12 (512 bit output, 7 byte input, D=0xb) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #13 (512 bit output, 1 byte input, D=0x30) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #13 (512 bit output, 1 byte input, D=0x30) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #13 (512 bit output, 1 byte input, D=0x30) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #13 (512 bit output, 1 byte input, D=0x30) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #13 (512 bit output, 1 byte input, D=0x30) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #14 (512 bit output, 3 byte input, D=0x7f) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #14 (512 bit output, 3 byte input, D=0x7f) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #14 (512 bit output, 3 byte input, D=0x7f) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #14 (512 bit output, 3 byte input, D=0x7f) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #14 (512 bit output, 3 byte input, D=0x7f) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/digest/turboshake.tentative.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/digest/turboshake.tentative.https.any.js new file mode 100644 index 0000000..243931c --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/digest/turboshake.tentative.https.any.js
@@ -0,0 +1,297 @@ +// META: title=WebCryptoAPI: digest() TurboSHAKE algorithms +// META: script=../util/helpers.js +// META: timeout=long + +var subtle = crypto.subtle; // Change to test prefixed implementations + +// Generates a Uint8Array of length n by repeating the pattern 00 01 02 .. F9 FA. +function ptn(n) { + var buf = new Uint8Array(n); + for (var i = 0; i < n; i++) + buf[i] = i % 251; + return buf; +} + +function hexToBytes(hex) { + var bytes = new Uint8Array(hex.length / 2); + for (var i = 0; i < hex.length; i += 2) + bytes[i / 2] = parseInt(hex.substring(i, i + 2), 16); + return bytes; +} + +// RFC 9861 Section 5 test vectors +// [input, outputLengthBits, expected hex(, domainSeparation)] +var turboSHAKE128Vectors = [ + [new Uint8Array(0), 256, + '1e415f1c5983aff2169217277d17bb53' + + '8cd945a397ddec541f1ce41af2c1b74c'], + [new Uint8Array(0), 512, + '1e415f1c5983aff2169217277d17bb53' + + '8cd945a397ddec541f1ce41af2c1b74c' + + '3e8ccae2a4dae56c84a04c2385c03c15' + + 'e8193bdf58737363321691c05462c8df'], + [ptn(1), 256, + '55cedd6f60af7bb29a4042ae832ef3f5' + + '8db7299f893ebb9247247d856958daa9'], + [ptn(17), 256, + '9c97d036a3bac819db70ede0ca554ec6' + + 'e4c2a1a4ffbfd9ec269ca6a111161233'], + [ptn(Math.pow(17, 2)), 256, + '96c77c279e0126f7fc07c9b07f5cdae1' + + 'e0be60bdbe10620040e75d7223a624d2'], + [ptn(Math.pow(17, 3)), 256, + 'd4976eb56bcf118520582b709f73e1d6' + + '853e001fdaf80e1b13e0d0599d5fb372'], + [ptn(Math.pow(17, 4)), 256, + 'da67c7039e98bf530cf7a37830c6664e' + + '14cbab7f540f58403b1b82951318ee5c'], + [ptn(Math.pow(17, 5)), 256, + 'b97a906fbf83ef7c812517abf3b2d0ae' + + 'a0c4f60318ce11cf103925127f59eecd'], + [ptn(Math.pow(17, 6)), 256, + '35cd494adeded2f25239af09a7b8ef0c' + + '4d1ca4fe2d1ac370fa63216fe7b4c2b1'], + [new Uint8Array([0xff, 0xff, 0xff]), 256, + 'bf323f940494e88ee1c540fe660be8a0' + + 'c93f43d15ec006998462fa994eed5dab', 0x01], + [new Uint8Array([0xff]), 256, + '8ec9c66465ed0d4a6c35d13506718d68' + + '7a25cb05c74cca1e42501abd83874a67', 0x06], + [new Uint8Array([0xff, 0xff, 0xff]), 256, + 'b658576001cad9b1e5f399a9f77723bb' + + 'a05458042d68206f7252682dba3663ed', 0x07], + [new Uint8Array([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]), 256, + '8deeaa1aec47ccee569f659c21dfa8e1' + + '12db3cee37b18178b2acd805b799cc37', 0x0b], + [new Uint8Array([0xff]), 256, + '553122e2135e363c3292bed2c6421fa2' + + '32bab03daa07c7d6636603286506325b', 0x30], + [new Uint8Array([0xff, 0xff, 0xff]), 256, + '16274cc656d44cefd422395d0f9053bd' + + 'a6d28e122aba15c765e5ad0e6eaf26f9', 0x7f], +]; + +var turboSHAKE256Vectors = [ + [new Uint8Array(0), 512, + '367a329dafea871c7802ec67f905ae13' + + 'c57695dc2c6663c61035f59a18f8e7db' + + '11edc0e12e91ea60eb6b32df06dd7f00' + + '2fbafabb6e13ec1cc20d995547600db0'], + [ptn(1), 512, + '3e1712f928f8eaf1054632b2aa0a246e' + + 'd8b0c378728f60bc970410155c28820e' + + '90cc90d8a3006aa2372c5c5ea176b068' + + '2bf22bae7467ac94f74d43d39b0482e2'], + [ptn(17), 512, + 'b3bab0300e6a191fbe61379398359235' + + '78794ea54843f5011090fa2f3780a9e5' + + 'cb22c59d78b40a0fbff9e672c0fbe097' + + '0bd2c845091c6044d687054da5d8e9c7'], + [ptn(Math.pow(17, 2)), 512, + '66b810db8e90780424c0847372fdc957' + + '10882fde31c6df75beb9d4cd9305cfca' + + 'e35e7b83e8b7e6eb4b78605880116316' + + 'fe2c078a09b94ad7b8213c0a738b65c0'], + [ptn(Math.pow(17, 3)), 512, + 'c74ebc919a5b3b0dd1228185ba02d29e' + + 'f442d69d3d4276a93efe0bf9a16a7dc0' + + 'cd4eabadab8cd7a5edd96695f5d360ab' + + 'e09e2c6511a3ec397da3b76b9e1674fb'], + [ptn(Math.pow(17, 4)), 512, + '02cc3a8897e6f4f6ccb6fd46631b1f52' + + '07b66c6de9c7b55b2d1a23134a170afd' + + 'ac234eaba9a77cff88c1f020b7372461' + + '8c5687b362c430b248cd38647f848a1d'], + [ptn(Math.pow(17, 5)), 512, + 'add53b06543e584b5823f626996aee50' + + 'fe45ed15f20243a7165485acb4aa76b4' + + 'ffda75cedf6d8cdc95c332bd56f4b986' + + 'b58bb17d1778bfc1b1a97545cdf4ec9f'], + [ptn(Math.pow(17, 6)), 512, + '9e11bc59c24e73993c1484ec66358ef7' + + '1db74aefd84e123f7800ba9c4853e02c' + + 'fe701d9e6bb765a304f0dc34a4ee3ba8' + + '2c410f0da70e86bfbd90ea877c2d6104'], + [new Uint8Array([0xff, 0xff, 0xff]), 512, + 'd21c6fbbf587fa2282f29aea620175fb' + + '0257413af78a0b1b2a87419ce031d933' + + 'ae7a4d383327a8a17641a34f8a1d1003' + + 'ad7da6b72dba84bb62fef28f62f12424', 0x01], + [new Uint8Array([0xff]), 512, + '738d7b4e37d18b7f22ad1b5313e357e3' + + 'dd7d07056a26a303c433fa3533455280' + + 'f4f5a7d4f700efb437fe6d281405e07b' + + 'e32a0a972e22e63adc1b090daefe004b', 0x06], + [new Uint8Array([0xff, 0xff, 0xff]), 512, + '18b3b5b7061c2e67c1753a00e6ad7ed7' + + 'ba1c906cf93efb7092eaf27fbeebb755' + + 'ae6e292493c110e48d260028492b8e09' + + 'b5500612b8f2578985ded5357d00ec67', 0x07], + [new Uint8Array([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]), 512, + 'bb36764951ec97e9d85f7ee9a67a7718' + + 'fc005cf42556be79ce12c0bde50e5736' + + 'd6632b0d0dfb202d1bbb8ffe3dd74cb0' + + '0834fa756cb03471bab13a1e2c16b3c0', 0x0b], + [new Uint8Array([0xff]), 512, + 'f3fe12873d34bcbb2e608779d6b70e7f' + + '86bec7e90bf113cbd4fdd0c4e2f4625e' + + '148dd7ee1a52776cf77f240514d9ccfc' + + '3b5ddab8ee255e39ee389072962c111a', 0x30], + [new Uint8Array([0xff, 0xff, 0xff]), 512, + 'abe569c1f77ec340f02705e7d37c9ab7' + + 'e155516e4a6a150021d70b6fac0bb40c' + + '069f9a9828a0d575cd99f9bae435ab1a' + + 'cf7ed9110ba97ce0388d074bac768776', 0x7f], +]; + +// Large output tests: verify last 32 bytes of extended output +var largeOutputTests = [ + // [algorithm, outputLengthBits, lastNBytes, expectedLastBytes] + ['TurboSHAKE128', 10032 * 8, 32, + 'a3b9b0385900ce761f22aed548e754da' + + '10a5242d62e8c658e3f3a923a7555607'], + ['TurboSHAKE256', 10032 * 8, 32, + 'abefa11630c661269249742685ec082f' + + '207265dccf2f43534e9c61ba0c9d1d75'], +]; + +largeOutputTests.forEach(function (entry) { + var alg = entry[0]; + var outputLength = entry[1]; + var lastN = entry[2]; + var expected = entry[3]; + + promise_test(function (test) { + return subtle + .digest({ name: alg, outputLength: outputLength }, new Uint8Array(0)) + .then(function (result) { + var full = new Uint8Array(result); + var last = full.slice(full.length - lastN); + assert_true( + equalBuffers(last.buffer, hexToBytes(expected)), + 'last ' + lastN + ' bytes of digest match expected' + ); + }); + }, alg + ' with ' + outputLength + ' bit output, verify last ' + lastN + ' bytes'); +}); + +function domainSeparationEqual(emptyDataVector, domainSeparation) { + return (domainSeparation ?? 0x1f) === (emptyDataVector[3] ?? 0x1f); +} + +function outputLengthLessOrEqual(emptyDataVector, outputLength) { + return outputLength <= emptyDataVector[1]; +} + +var allVectors = { + TurboSHAKE128: turboSHAKE128Vectors, + TurboSHAKE256: turboSHAKE256Vectors, +}; + +Object.keys(allVectors).forEach(function (alg) { + var emptyDataVector = allVectors[alg][0]; + allVectors[alg].forEach(function (vector, i) { + var input = vector[0]; + var outputLength = vector[1]; + var expected = vector[2]; + var domainSeparation = vector[3]; + + var algorithmParams = { name: alg, outputLength: outputLength }; + if (domainSeparation !== undefined) + algorithmParams.domainSeparation = domainSeparation; + + var label = alg + ' vector #' + (i + 1) + + ' (' + outputLength + ' bit output, ' + input.length + ' byte input' + + (domainSeparation !== undefined ? ', D=0x' + domainSeparation.toString(16) : '') + ')'; + + promise_test(function (test) { + return subtle + .digest(algorithmParams, input) + .then(function (result) { + assert_true( + equalBuffers(result, hexToBytes(expected)), + 'digest matches expected' + ); + }); + }, label); + + if (input.length > 0) { + promise_test(function (test) { + var buffer = new Uint8Array(input); + // Alter the buffer before calling digest + buffer[0] = ~buffer[0]; + return subtle + .digest({ + get name() { + // Alter the buffer back while calling digest + buffer[0] = input[0]; + return alg; + }, + outputLength: outputLength, + domainSeparation: domainSeparation, + }, buffer) + .then(function (result) { + assert_true( + equalBuffers(result, hexToBytes(expected)), + 'digest matches expected' + ); + }); + }, label + ' and altered buffer during call'); + + promise_test(function (test) { + var buffer = new Uint8Array(input); + var promise = subtle + .digest(algorithmParams, buffer) + .then(function (result) { + assert_true( + equalBuffers(result, hexToBytes(expected)), + 'digest matches expected' + ); + }); + // Alter the buffer after calling digest + buffer[0] = ~buffer[0]; + return promise; + }, label + ' and altered buffer after call'); + + promise_test(function (test) { + var buffer = new Uint8Array(input); + return subtle + .digest({ + get name() { + // Transfer the buffer while calling digest + buffer.buffer.transfer(); + return alg; + }, + outputLength: outputLength, + domainSeparation: domainSeparation, + }, buffer) + .then(function (result) { + if (domainSeparationEqual(emptyDataVector, domainSeparation) && outputLengthLessOrEqual(emptyDataVector, outputLength)) { + assert_true( + equalBuffers(result, Uint8Array.fromHex(emptyDataVector[2]).subarray(0, outputLength / 8)), + 'digest on transferred buffer should match result for empty buffer' + ); + } else { + assert_equals(result.byteLength, outputLength / 8, + 'digest on transferred buffer should have correct output length'); + } + }); + }, label + ' and transferred buffer during call'); + + promise_test(function (test) { + var buffer = new Uint8Array(input); + var promise = subtle + .digest(algorithmParams, buffer) + .then(function (result) { + assert_true( + equalBuffers(result, hexToBytes(expected)), + 'digest matches expected' + ); + }); + // Transfer the buffer after calling digest + buffer.buffer.transfer(); + return promise; + }, label + ' and transferred buffer after call'); + } + }); +});
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/digest/turboshake.tentative.https.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/digest/turboshake.tentative.https.any.worker-expected.txt new file mode 100644 index 0000000..7fe54c9c --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/digest/turboshake.tentative.https.any.worker-expected.txt
@@ -0,0 +1,274 @@ +This is a testharness.js-based test. +Found 135 FAIL, 0 TIMEOUT, 0 NOTRUN. +[FAIL] TurboSHAKE128 with 80256 bit output, verify last 32 bytes + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 with 80256 bit output, verify last 32 bytes + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #1 (256 bit output, 0 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #2 (512 bit output, 0 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #3 (256 bit output, 1 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #3 (256 bit output, 1 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #3 (256 bit output, 1 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #3 (256 bit output, 1 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #3 (256 bit output, 1 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #4 (256 bit output, 17 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #4 (256 bit output, 17 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #4 (256 bit output, 17 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #4 (256 bit output, 17 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #4 (256 bit output, 17 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #5 (256 bit output, 289 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #5 (256 bit output, 289 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #5 (256 bit output, 289 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #5 (256 bit output, 289 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #5 (256 bit output, 289 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #6 (256 bit output, 4913 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #6 (256 bit output, 4913 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #6 (256 bit output, 4913 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #6 (256 bit output, 4913 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #6 (256 bit output, 4913 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #7 (256 bit output, 83521 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #7 (256 bit output, 83521 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #7 (256 bit output, 83521 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #7 (256 bit output, 83521 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #7 (256 bit output, 83521 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #8 (256 bit output, 1419857 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #8 (256 bit output, 1419857 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #8 (256 bit output, 1419857 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #8 (256 bit output, 1419857 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #8 (256 bit output, 1419857 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #9 (256 bit output, 24137569 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #9 (256 bit output, 24137569 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #9 (256 bit output, 24137569 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #9 (256 bit output, 24137569 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #9 (256 bit output, 24137569 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #10 (256 bit output, 3 byte input, D=0x1) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #10 (256 bit output, 3 byte input, D=0x1) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #10 (256 bit output, 3 byte input, D=0x1) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #10 (256 bit output, 3 byte input, D=0x1) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #10 (256 bit output, 3 byte input, D=0x1) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #11 (256 bit output, 1 byte input, D=0x6) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #11 (256 bit output, 1 byte input, D=0x6) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #11 (256 bit output, 1 byte input, D=0x6) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #11 (256 bit output, 1 byte input, D=0x6) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #11 (256 bit output, 1 byte input, D=0x6) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #12 (256 bit output, 3 byte input, D=0x7) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #12 (256 bit output, 3 byte input, D=0x7) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #12 (256 bit output, 3 byte input, D=0x7) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #12 (256 bit output, 3 byte input, D=0x7) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #12 (256 bit output, 3 byte input, D=0x7) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #13 (256 bit output, 7 byte input, D=0xb) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #13 (256 bit output, 7 byte input, D=0xb) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #13 (256 bit output, 7 byte input, D=0xb) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #13 (256 bit output, 7 byte input, D=0xb) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #13 (256 bit output, 7 byte input, D=0xb) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #14 (256 bit output, 1 byte input, D=0x30) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #14 (256 bit output, 1 byte input, D=0x30) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #14 (256 bit output, 1 byte input, D=0x30) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #14 (256 bit output, 1 byte input, D=0x30) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #14 (256 bit output, 1 byte input, D=0x30) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #15 (256 bit output, 3 byte input, D=0x7f) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #15 (256 bit output, 3 byte input, D=0x7f) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #15 (256 bit output, 3 byte input, D=0x7f) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #15 (256 bit output, 3 byte input, D=0x7f) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE128 vector #15 (256 bit output, 3 byte input, D=0x7f) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #1 (512 bit output, 0 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #2 (512 bit output, 1 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #2 (512 bit output, 1 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #2 (512 bit output, 1 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #2 (512 bit output, 1 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #2 (512 bit output, 1 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #3 (512 bit output, 17 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #3 (512 bit output, 17 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #3 (512 bit output, 17 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #3 (512 bit output, 17 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #3 (512 bit output, 17 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #4 (512 bit output, 289 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #4 (512 bit output, 289 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #4 (512 bit output, 289 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #4 (512 bit output, 289 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #4 (512 bit output, 289 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #5 (512 bit output, 4913 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #5 (512 bit output, 4913 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #5 (512 bit output, 4913 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #5 (512 bit output, 4913 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #5 (512 bit output, 4913 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #6 (512 bit output, 83521 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #6 (512 bit output, 83521 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #6 (512 bit output, 83521 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #6 (512 bit output, 83521 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #6 (512 bit output, 83521 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #7 (512 bit output, 1419857 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #7 (512 bit output, 1419857 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #7 (512 bit output, 1419857 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #7 (512 bit output, 1419857 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #7 (512 bit output, 1419857 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #8 (512 bit output, 24137569 byte input) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #8 (512 bit output, 24137569 byte input) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #8 (512 bit output, 24137569 byte input) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #8 (512 bit output, 24137569 byte input) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #8 (512 bit output, 24137569 byte input) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #9 (512 bit output, 3 byte input, D=0x1) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #9 (512 bit output, 3 byte input, D=0x1) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #9 (512 bit output, 3 byte input, D=0x1) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #9 (512 bit output, 3 byte input, D=0x1) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #9 (512 bit output, 3 byte input, D=0x1) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #10 (512 bit output, 1 byte input, D=0x6) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #10 (512 bit output, 1 byte input, D=0x6) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #10 (512 bit output, 1 byte input, D=0x6) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #10 (512 bit output, 1 byte input, D=0x6) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #10 (512 bit output, 1 byte input, D=0x6) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #11 (512 bit output, 3 byte input, D=0x7) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #11 (512 bit output, 3 byte input, D=0x7) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #11 (512 bit output, 3 byte input, D=0x7) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #11 (512 bit output, 3 byte input, D=0x7) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #11 (512 bit output, 3 byte input, D=0x7) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #12 (512 bit output, 7 byte input, D=0xb) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #12 (512 bit output, 7 byte input, D=0xb) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #12 (512 bit output, 7 byte input, D=0xb) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #12 (512 bit output, 7 byte input, D=0xb) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #12 (512 bit output, 7 byte input, D=0xb) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #13 (512 bit output, 1 byte input, D=0x30) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #13 (512 bit output, 1 byte input, D=0x30) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #13 (512 bit output, 1 byte input, D=0x30) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #13 (512 bit output, 1 byte input, D=0x30) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #13 (512 bit output, 1 byte input, D=0x30) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #14 (512 bit output, 3 byte input, D=0x7f) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #14 (512 bit output, 3 byte input, D=0x7f) and altered buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #14 (512 bit output, 3 byte input, D=0x7f) and altered buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #14 (512 bit output, 3 byte input, D=0x7f) and transferred buffer during call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] TurboSHAKE256 vector #14 (512 bit output, 3 byte input, D=0x7f) and transferred buffer after call + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'digest' on 'SubtleCrypto': Algorithm: Unrecognized name" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encap_decap/encap_decap_bits.tentative.https.any-expected.txt b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encap_decap/encap_decap_bits.tentative.https.any-expected.txt index a7484b80c..77354c52 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encap_decap/encap_decap_bits.tentative.https.any-expected.txt +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encap_decap/encap_decap_bits.tentative.https.any-expected.txt
@@ -1,24 +1,18 @@ This is a testharness.js-based test. [FAIL] ML-KEM-512 encapsulateBits basic functionality promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 decapsulateBits basic functionality - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" [FAIL] ML-KEM-512 encapsulateBits/decapsulateBits round-trip compatibility promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" [FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" [FAIL] ML-KEM-768 encapsulateBits basic functionality promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-768 decapsulateBits basic functionality - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" [FAIL] ML-KEM-768 encapsulateBits/decapsulateBits round-trip compatibility promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" [FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" [FAIL] ML-KEM-1024 encapsulateBits basic functionality promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-1024 decapsulateBits basic functionality - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" [FAIL] ML-KEM-1024 encapsulateBits/decapsulateBits round-trip compatibility promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" [FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encap_decap/encap_decap_bits.tentative.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encap_decap/encap_decap_bits.tentative.https.any.js index ab112e4d4..5a66975 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encap_decap/encap_decap_bits.tentative.https.any.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encap_decap/encap_decap_bits.tentative.https.any.js
@@ -73,7 +73,7 @@ ); }, algorithmName + ' encapsulateBits basic functionality'); - // Test decapsulateBits operation + // Test encapsulateBits/decapsulateBits round-trip compatibility promise_test(async function (test) { // Generate a key pair for testing var keyPair = await subtle.generateKey({ name: algorithmName }, false, [ @@ -109,30 +109,6 @@ equalBuffers(decapsulatedBits, encapsulatedBits.sharedKey), 'Decapsulated shared secret should match original' ); - }, algorithmName + ' decapsulateBits basic functionality'); - - // Test round-trip compatibility - promise_test(async function (test) { - var keyPair = await subtle.generateKey({ name: algorithmName }, false, [ - 'encapsulateBits', - 'decapsulateBits', - ]); - - var encapsulatedBits = await subtle.encapsulateBits( - { name: algorithmName }, - keyPair.publicKey - ); - - var decapsulatedBits = await subtle.decapsulateBits( - { name: algorithmName }, - keyPair.privateKey, - encapsulatedBits.ciphertext - ); - - assert_true( - equalBuffers(encapsulatedBits.sharedKey, decapsulatedBits), - 'Encapsulated and decapsulated shared secrets should match' - ); }, algorithmName + ' encapsulateBits/decapsulateBits round-trip compatibility'); @@ -175,19 +151,4 @@ }); } -// Helper function to compare two ArrayBuffers -function equalBuffers(a, b) { - if (a.byteLength !== b.byteLength) { - return false; - } - var aBytes = new Uint8Array(a); - var bBytes = new Uint8Array(b); - for (var i = 0; i < a.byteLength; i++) { - if (aBytes[i] !== bBytes[i]) { - return false; - } - } - return true; -} - define_bits_tests();
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encap_decap/encap_decap_bits.tentative.https.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encap_decap/encap_decap_bits.tentative.https.any.worker-expected.txt index a7484b80c..77354c52 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encap_decap/encap_decap_bits.tentative.https.any.worker-expected.txt +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encap_decap/encap_decap_bits.tentative.https.any.worker-expected.txt
@@ -1,24 +1,18 @@ This is a testharness.js-based test. [FAIL] ML-KEM-512 encapsulateBits basic functionality promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 decapsulateBits basic functionality - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" [FAIL] ML-KEM-512 encapsulateBits/decapsulateBits round-trip compatibility promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" [FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" [FAIL] ML-KEM-768 encapsulateBits basic functionality promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-768 decapsulateBits basic functionality - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" [FAIL] ML-KEM-768 encapsulateBits/decapsulateBits round-trip compatibility promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" [FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" [FAIL] ML-KEM-1024 encapsulateBits basic functionality promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-1024 decapsulateBits basic functionality - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" [FAIL] ML-KEM-1024 encapsulateBits/decapsulateBits round-trip compatibility promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" [FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encap_decap/encap_decap_keys.tentative.https.any-expected.txt b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encap_decap/encap_decap_keys.tentative.https.any-expected.txt index 35d7bed6..737aa0c1 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encap_decap/encap_decap_keys.tentative.https.any-expected.txt +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encap_decap/encap_decap_keys.tentative.https.any-expected.txt
@@ -1,124 +1,244 @@ This is a testharness.js-based test. -Found 60 FAIL, 0 TIMEOUT, 0 NOTRUN. -[FAIL] ML-KEM-512 encapsulateKey with AES-GCM-256 +Found 120 FAIL, 0 TIMEOUT, 0 NOTRUN. +[FAIL] ML-KEM-512 encapsulateKey with AES-GCM-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 decapsulateKey with AES-GCM-256 +[FAIL] ML-KEM-512 decapsulateKey with AES-GCM-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-GCM-256 +[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-GCM-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 encapsulateKey with AES-CBC-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 decapsulateKey with AES-CBC-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-CBC-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 encapsulateKey with AES-CTR-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 decapsulateKey with AES-CTR-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-CTR-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 encapsulateKey with AES-KW-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 decapsulateKey with AES-KW-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-KW-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 encapsulateKey with HMAC-SHA-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 decapsulateKey with HMAC-SHA-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with HMAC-SHA-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-GCM-256 +[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-GCM-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-CBC-256 +[FAIL] ML-KEM-512 encapsulateKey with AES-GCM-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 decapsulateKey with AES-GCM-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-GCM-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-GCM-256 (extractable=false) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-CTR-256 +[FAIL] ML-KEM-512 encapsulateKey with AES-CBC-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 decapsulateKey with AES-CBC-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-CBC-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-CBC-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-KW-256 +[FAIL] ML-KEM-512 encapsulateKey with AES-CBC-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 decapsulateKey with AES-CBC-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-CBC-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-CBC-256 (extractable=false) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with HMAC-SHA-256 +[FAIL] ML-KEM-512 encapsulateKey with AES-CTR-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 decapsulateKey with AES-CTR-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-CTR-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-CTR-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-768 encapsulateKey with AES-GCM-256 +[FAIL] ML-KEM-512 encapsulateKey with AES-CTR-256 (extractable=false) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-768 decapsulateKey with AES-GCM-256 +[FAIL] ML-KEM-512 decapsulateKey with AES-CTR-256 (extractable=false) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-GCM-256 +[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-CTR-256 (extractable=false) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-768 encapsulateKey with AES-CBC-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-768 decapsulateKey with AES-CBC-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-CBC-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-768 encapsulateKey with AES-CTR-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-768 decapsulateKey with AES-CTR-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-CTR-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-768 encapsulateKey with AES-KW-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-768 decapsulateKey with AES-KW-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-KW-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-768 encapsulateKey with HMAC-SHA-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-768 decapsulateKey with HMAC-SHA-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with HMAC-SHA-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-GCM-256 +[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-CTR-256 (extractable=false) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-CBC-256 +[FAIL] ML-KEM-512 encapsulateKey with AES-KW-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 decapsulateKey with AES-KW-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-KW-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-KW-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-CTR-256 +[FAIL] ML-KEM-512 encapsulateKey with AES-KW-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 decapsulateKey with AES-KW-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-KW-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-KW-256 (extractable=false) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-KW-256 +[FAIL] ML-KEM-512 encapsulateKey with HMAC-SHA-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 decapsulateKey with HMAC-SHA-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with HMAC-SHA-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with HMAC-SHA-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with HMAC-SHA-256 +[FAIL] ML-KEM-512 encapsulateKey with HMAC-SHA-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 decapsulateKey with HMAC-SHA-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with HMAC-SHA-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with HMAC-SHA-256 (extractable=false) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-1024 encapsulateKey with AES-GCM-256 +[FAIL] ML-KEM-768 encapsulateKey with AES-GCM-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-1024 decapsulateKey with AES-GCM-256 +[FAIL] ML-KEM-768 decapsulateKey with AES-GCM-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-GCM-256 +[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-GCM-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-1024 encapsulateKey with AES-CBC-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-1024 decapsulateKey with AES-CBC-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-CBC-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-1024 encapsulateKey with AES-CTR-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-1024 decapsulateKey with AES-CTR-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-CTR-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-1024 encapsulateKey with AES-KW-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-1024 decapsulateKey with AES-KW-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-KW-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-1024 encapsulateKey with HMAC-SHA-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-1024 decapsulateKey with HMAC-SHA-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with HMAC-SHA-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-GCM-256 +[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-GCM-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-CBC-256 +[FAIL] ML-KEM-768 encapsulateKey with AES-GCM-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 decapsulateKey with AES-GCM-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-GCM-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-GCM-256 (extractable=false) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-CTR-256 +[FAIL] ML-KEM-768 encapsulateKey with AES-CBC-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 decapsulateKey with AES-CBC-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-CBC-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-CBC-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-KW-256 +[FAIL] ML-KEM-768 encapsulateKey with AES-CBC-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 decapsulateKey with AES-CBC-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-CBC-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-CBC-256 (extractable=false) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with HMAC-SHA-256 +[FAIL] ML-KEM-768 encapsulateKey with AES-CTR-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 decapsulateKey with AES-CTR-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-CTR-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-CTR-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 encapsulateKey with AES-CTR-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 decapsulateKey with AES-CTR-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-CTR-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-CTR-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 encapsulateKey with AES-KW-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 decapsulateKey with AES-KW-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-KW-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-KW-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 encapsulateKey with AES-KW-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 decapsulateKey with AES-KW-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-KW-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-KW-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 encapsulateKey with HMAC-SHA-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 decapsulateKey with HMAC-SHA-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with HMAC-SHA-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with HMAC-SHA-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 encapsulateKey with HMAC-SHA-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 decapsulateKey with HMAC-SHA-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with HMAC-SHA-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with HMAC-SHA-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 encapsulateKey with AES-GCM-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 decapsulateKey with AES-GCM-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-GCM-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-GCM-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 encapsulateKey with AES-GCM-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 decapsulateKey with AES-GCM-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-GCM-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-GCM-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 encapsulateKey with AES-CBC-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 decapsulateKey with AES-CBC-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-CBC-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-CBC-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 encapsulateKey with AES-CBC-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 decapsulateKey with AES-CBC-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-CBC-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-CBC-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 encapsulateKey with AES-CTR-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 decapsulateKey with AES-CTR-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-CTR-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-CTR-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 encapsulateKey with AES-CTR-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 decapsulateKey with AES-CTR-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-CTR-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-CTR-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 encapsulateKey with AES-KW-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 decapsulateKey with AES-KW-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-KW-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-KW-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 encapsulateKey with AES-KW-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 decapsulateKey with AES-KW-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-KW-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-KW-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 encapsulateKey with HMAC-SHA-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 decapsulateKey with HMAC-SHA-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with HMAC-SHA-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with HMAC-SHA-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 encapsulateKey with HMAC-SHA-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 decapsulateKey with HMAC-SHA-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with HMAC-SHA-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with HMAC-SHA-256 (extractable=false) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encap_decap/encap_decap_keys.tentative.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encap_decap/encap_decap_keys.tentative.https.any.js index 4ccb0585b..0a45c1f 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encap_decap/encap_decap_keys.tentative.https.any.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encap_decap/encap_decap_keys.tentative.https.any.js
@@ -38,313 +38,318 @@ variants.forEach(function (algorithmName) { sharedKeyConfigs.forEach(function (config) { - // Test encapsulateKey operation - promise_test(async function (test) { - // Generate a key pair for testing - var keyPair = await subtle.generateKey({ name: algorithmName }, false, [ - 'encapsulateKey', - 'decapsulateKey', - ]); + [true, false].forEach(function (extractable) { + // Test encapsulateKey operation + promise_test(async function (test) { + // Generate a key pair for testing + var keyPair = await subtle.generateKey({ name: algorithmName }, false, [ + 'encapsulateKey', + 'decapsulateKey', + ]); - // Test encapsulateKey - var encapsulatedKey = await subtle.encapsulateKey( - { name: algorithmName }, - keyPair.publicKey, - config.algorithm, - true, - config.usages - ); + // Test encapsulateKey + var encapsulatedKey = await subtle.encapsulateKey( + { name: algorithmName }, + keyPair.publicKey, + config.algorithm, + extractable, + config.usages + ); - assert_true( - encapsulatedKey instanceof Object, - 'encapsulateKey should return an object' - ); - assert_true( - encapsulatedKey.hasOwnProperty('sharedKey'), - 'Result should have sharedKey property' - ); - assert_true( - encapsulatedKey.hasOwnProperty('ciphertext'), - 'Result should have ciphertext property' - ); - assert_true( - encapsulatedKey.sharedKey instanceof CryptoKey, - 'sharedKey should be a CryptoKey' - ); - assert_true( - encapsulatedKey.ciphertext instanceof ArrayBuffer, - 'ciphertext should be ArrayBuffer' - ); + assert_true( + encapsulatedKey instanceof Object, + 'encapsulateKey should return an object' + ); + assert_true( + encapsulatedKey.hasOwnProperty('sharedKey'), + 'Result should have sharedKey property' + ); + assert_true( + encapsulatedKey.hasOwnProperty('ciphertext'), + 'Result should have ciphertext property' + ); + assert_true( + encapsulatedKey.sharedKey instanceof CryptoKey, + 'sharedKey should be a CryptoKey' + ); + assert_true( + encapsulatedKey.ciphertext instanceof ArrayBuffer, + 'ciphertext should be ArrayBuffer' + ); - // Verify the shared key properties - assert_equals( - encapsulatedKey.sharedKey.type, - 'secret', - 'Shared key should be secret type' - ); - assert_equals( - encapsulatedKey.sharedKey.algorithm.name, - config.algorithm.name, - 'Shared key algorithm should match' - ); - assert_true( - encapsulatedKey.sharedKey.extractable, - 'Shared key should be extractable as specified' - ); - assert_array_equals( - encapsulatedKey.sharedKey.usages, - config.usages, - 'Shared key should have correct usages' - ); - - // Verify algorithm-specific properties - if (config.algorithm.length) { + // Verify the shared key properties assert_equals( - encapsulatedKey.sharedKey.algorithm.length, - config.algorithm.length, - 'Key length should be 256' + encapsulatedKey.sharedKey.type, + 'secret', + 'Shared key should be secret type' ); - } - if (config.algorithm.hash) { assert_equals( - encapsulatedKey.sharedKey.algorithm.hash.name, - config.algorithm.hash, - 'Hash algorithm should match' + encapsulatedKey.sharedKey.algorithm.name, + config.algorithm.name, + 'Shared key algorithm should match' ); - } - - // Verify ciphertext length based on algorithm variant - var expectedCiphertextLength; - switch (algorithmName) { - case 'ML-KEM-512': - expectedCiphertextLength = 768; - break; - case 'ML-KEM-768': - expectedCiphertextLength = 1088; - break; - case 'ML-KEM-1024': - expectedCiphertextLength = 1568; - break; - } - assert_equals( - encapsulatedKey.ciphertext.byteLength, - expectedCiphertextLength, - 'Ciphertext should be ' + - expectedCiphertextLength + - ' bytes for ' + - algorithmName - ); - }, algorithmName + ' encapsulateKey with ' + config.description); - - // Test decapsulateKey operation - promise_test(async function (test) { - // Generate a key pair for testing - var keyPair = await subtle.generateKey({ name: algorithmName }, false, [ - 'encapsulateKey', - 'decapsulateKey', - ]); - - // First encapsulate to get ciphertext - var encapsulatedKey = await subtle.encapsulateKey( - { name: algorithmName }, - keyPair.publicKey, - config.algorithm, - true, - config.usages - ); - - // Then decapsulate using the private key - var decapsulatedKey = await subtle.decapsulateKey( - { name: algorithmName }, - keyPair.privateKey, - encapsulatedKey.ciphertext, - config.algorithm, - true, - config.usages - ); - - assert_true( - decapsulatedKey instanceof CryptoKey, - 'decapsulateKey should return a CryptoKey' - ); - assert_equals( - decapsulatedKey.type, - 'secret', - 'Decapsulated key should be secret type' - ); - assert_equals( - decapsulatedKey.algorithm.name, - config.algorithm.name, - 'Decapsulated key algorithm should match' - ); - assert_true( - decapsulatedKey.extractable, - 'Decapsulated key should be extractable as specified' - ); - assert_array_equals( - decapsulatedKey.usages, - config.usages, - 'Decapsulated key should have correct usages' - ); - - // Extract both keys and verify they are identical - var originalKeyMaterial = await subtle.exportKey( - 'raw', - encapsulatedKey.sharedKey - ); - var decapsulatedKeyMaterial = await subtle.exportKey( - 'raw', - decapsulatedKey - ); - - assert_true( - equalBuffers(originalKeyMaterial, decapsulatedKeyMaterial), - 'Decapsulated key material should match original' - ); - - // Verify the key material is 32 bytes (256 bits) - assert_equals( - originalKeyMaterial.byteLength, - 32, - 'Shared key material should be 32 bytes' - ); - }, algorithmName + ' decapsulateKey with ' + config.description); - - // Test round-trip compatibility - promise_test(async function (test) { - var keyPair = await subtle.generateKey({ name: algorithmName }, false, [ - 'encapsulateKey', - 'decapsulateKey', - ]); - - var encapsulatedKey = await subtle.encapsulateKey( - { name: algorithmName }, - keyPair.publicKey, - config.algorithm, - true, - config.usages - ); - - var decapsulatedKey = await subtle.decapsulateKey( - { name: algorithmName }, - keyPair.privateKey, - encapsulatedKey.ciphertext, - config.algorithm, - true, - config.usages - ); - - // Verify keys have the same material - var originalKeyMaterial = await subtle.exportKey( - 'raw', - encapsulatedKey.sharedKey - ); - var decapsulatedKeyMaterial = await subtle.exportKey( - 'raw', - decapsulatedKey - ); - - assert_true( - equalBuffers(originalKeyMaterial, decapsulatedKeyMaterial), - 'Encapsulated and decapsulated keys should have the same material' - ); - - // Test that the derived keys can actually be used for their intended purpose - if ( - config.algorithm.name.startsWith('AES') && - config.usages.includes('encrypt') - ) { - await testAESOperation( - encapsulatedKey.sharedKey, - decapsulatedKey, - config.algorithm - ); - } else if (config.algorithm.name === 'HMAC') { - await testHMACOperation(encapsulatedKey.sharedKey, decapsulatedKey); - } - }, algorithmName + - ' encapsulateKey/decapsulateKey round-trip with ' + - config.description); - }); - - // Test vector-based decapsulation for each shared key config - sharedKeyConfigs.forEach(function (config) { - promise_test(async function (test) { - var vectors = ml_kem_vectors[algorithmName]; - - // Import the private key from the vector's privateSeed - var privateKey = await subtle.importKey( - 'raw-seed', - vectors.privateSeed, - { name: algorithmName }, - false, - ['decapsulateKey'] - ); - - // Decapsulate the sample ciphertext from the vectors to get a shared key - var decapsulatedKey = await subtle.decapsulateKey( - { name: algorithmName }, - privateKey, - vectors.sampleCiphertext, - config.algorithm, - true, - config.usages - ); - - assert_true( - decapsulatedKey instanceof CryptoKey, - 'decapsulateKey should return a CryptoKey' - ); - assert_equals( - decapsulatedKey.type, - 'secret', - 'Decapsulated key should be secret type' - ); - assert_equals( - decapsulatedKey.algorithm.name, - config.algorithm.name, - 'Decapsulated key algorithm should match' - ); - assert_true( - decapsulatedKey.extractable, - 'Decapsulated key should be extractable as specified' - ); - assert_array_equals( - decapsulatedKey.usages, - config.usages, - 'Decapsulated key should have correct usages' - ); - - // Extract the key material and verify it matches the expected shared secret - var keyMaterial = await subtle.exportKey('raw', decapsulatedKey); - assert_equals( - keyMaterial.byteLength, - 32, - 'Shared key material should be 32 bytes' - ); - assert_true( - equalBuffers(keyMaterial, vectors.expectedSharedSecret), - "Decapsulated key material should match vector's expectedSharedSecret" - ); - - // Verify algorithm-specific properties - if (config.algorithm.length) { assert_equals( - decapsulatedKey.algorithm.length, - config.algorithm.length, - 'Key length should be 256' + encapsulatedKey.sharedKey.extractable, + extractable, + 'Shared key should have correct extractable property' ); - } - if (config.algorithm.hash) { + assert_array_equals( + encapsulatedKey.sharedKey.usages, + config.usages, + 'Shared key should have correct usages' + ); + + // Verify algorithm-specific properties + if (config.algorithm.length) { + assert_equals( + encapsulatedKey.sharedKey.algorithm.length, + config.algorithm.length, + 'Key length should be 256' + ); + } + if (config.algorithm.hash) { + assert_equals( + encapsulatedKey.sharedKey.algorithm.hash.name, + config.algorithm.hash, + 'Hash algorithm should match' + ); + } + + // Verify ciphertext length based on algorithm variant + var expectedCiphertextLength; + switch (algorithmName) { + case 'ML-KEM-512': + expectedCiphertextLength = 768; + break; + case 'ML-KEM-768': + expectedCiphertextLength = 1088; + break; + case 'ML-KEM-1024': + expectedCiphertextLength = 1568; + break; + } assert_equals( - decapsulatedKey.algorithm.hash.name, - config.algorithm.hash, - 'Hash algorithm should match' + encapsulatedKey.ciphertext.byteLength, + expectedCiphertextLength, + 'Ciphertext should be ' + + expectedCiphertextLength + + ' bytes for ' + + algorithmName ); - } - }, algorithmName + - ' vector-based sampleCiphertext decapsulation with ' + - config.description); + }, `${algorithmName} encapsulateKey with ${config.description} (extractable=${extractable})`); + + // Test decapsulateKey operation + promise_test(async function (test) { + // Generate a key pair for testing + var keyPair = await subtle.generateKey({ name: algorithmName }, false, [ + 'encapsulateKey', + 'decapsulateKey', + ]); + + // First encapsulate to get ciphertext + var encapsulatedKey = await subtle.encapsulateKey( + { name: algorithmName }, + keyPair.publicKey, + config.algorithm, + extractable, + config.usages + ); + + // Then decapsulate using the private key + var decapsulatedKey = await subtle.decapsulateKey( + { name: algorithmName }, + keyPair.privateKey, + encapsulatedKey.ciphertext, + config.algorithm, + extractable, + config.usages + ); + + assert_true( + decapsulatedKey instanceof CryptoKey, + 'decapsulateKey should return a CryptoKey' + ); + assert_equals( + decapsulatedKey.type, + 'secret', + 'Decapsulated key should be secret type' + ); + assert_equals( + decapsulatedKey.algorithm.name, + config.algorithm.name, + 'Decapsulated key algorithm should match' + ); + assert_equals( + decapsulatedKey.extractable, + extractable, + 'Decapsulated key should have correct extractable property' + ); + assert_array_equals( + decapsulatedKey.usages, + config.usages, + 'Decapsulated key should have correct usages' + ); + + if (extractable) { + // Extract both keys and verify they are identical + var originalKeyMaterial = await subtle.exportKey( + 'raw', + encapsulatedKey.sharedKey + ); + var decapsulatedKeyMaterial = await subtle.exportKey( + 'raw', + decapsulatedKey + ); + + assert_true( + equalBuffers(originalKeyMaterial, decapsulatedKeyMaterial), + 'Decapsulated key material should match original' + ); + + // Verify the key material is 32 bytes (256 bits) + assert_equals( + originalKeyMaterial.byteLength, + 32, + 'Shared key material should be 32 bytes' + ); + } + }, `${algorithmName} decapsulateKey with ${config.description} (extractable=${extractable})`); + + // Test round-trip compatibility + promise_test(async function (test) { + var keyPair = await subtle.generateKey({ name: algorithmName }, false, [ + 'encapsulateKey', + 'decapsulateKey', + ]); + + var encapsulatedKey = await subtle.encapsulateKey( + { name: algorithmName }, + keyPair.publicKey, + config.algorithm, + extractable, + config.usages + ); + + var decapsulatedKey = await subtle.decapsulateKey( + { name: algorithmName }, + keyPair.privateKey, + encapsulatedKey.ciphertext, + config.algorithm, + extractable, + config.usages + ); + + if (extractable) { + // Verify keys have the same material + var originalKeyMaterial = await subtle.exportKey( + 'raw', + encapsulatedKey.sharedKey + ); + var decapsulatedKeyMaterial = await subtle.exportKey( + 'raw', + decapsulatedKey + ); + + assert_true( + equalBuffers(originalKeyMaterial, decapsulatedKeyMaterial), + 'Encapsulated and decapsulated keys should have the same material' + ); + } + + // Test that the derived keys can actually be used for their intended purpose + if ( + config.algorithm.name.startsWith('AES') && + config.usages.includes('encrypt') + ) { + await testAESOperation( + encapsulatedKey.sharedKey, + decapsulatedKey, + config.algorithm + ); + } else if (config.algorithm.name === 'HMAC') { + await testHMACOperation(encapsulatedKey.sharedKey, decapsulatedKey); + } + }, `${algorithmName} encapsulateKey/decapsulateKey round-trip with ${config.description} (extractable=${extractable})`); + + // Test vector-based decapsulation + promise_test(async function (test) { + var vectors = ml_kem_vectors[algorithmName]; + + // Import the private key from the vector's privateSeed + var privateKey = await subtle.importKey( + 'raw-seed', + vectors.privateSeed, + { name: algorithmName }, + false, + ['decapsulateKey'] + ); + + // Decapsulate the sample ciphertext from the vectors to get a shared key + var decapsulatedKey = await subtle.decapsulateKey( + { name: algorithmName }, + privateKey, + vectors.sampleCiphertext, + config.algorithm, + extractable, + config.usages + ); + + assert_true( + decapsulatedKey instanceof CryptoKey, + 'decapsulateKey should return a CryptoKey' + ); + assert_equals( + decapsulatedKey.type, + 'secret', + 'Decapsulated key should be secret type' + ); + assert_equals( + decapsulatedKey.algorithm.name, + config.algorithm.name, + 'Decapsulated key algorithm should match' + ); + assert_equals( + decapsulatedKey.extractable, + extractable, + 'Decapsulated key should have correct extractable property' + ); + assert_array_equals( + decapsulatedKey.usages, + config.usages, + 'Decapsulated key should have correct usages' + ); + + if (extractable) { + // Extract the key material and verify it matches the expected shared secret + var keyMaterial = await subtle.exportKey('raw', decapsulatedKey); + assert_equals( + keyMaterial.byteLength, + 32, + 'Shared key material should be 32 bytes' + ); + assert_true( + equalBuffers(keyMaterial, vectors.expectedSharedSecret), + "Decapsulated key material should match vector's expectedSharedSecret" + ); + } + + // Verify algorithm-specific properties + if (config.algorithm.length) { + assert_equals( + decapsulatedKey.algorithm.length, + config.algorithm.length, + 'Key length should be 256' + ); + } + if (config.algorithm.hash) { + assert_equals( + decapsulatedKey.algorithm.hash.name, + config.algorithm.hash, + 'Hash algorithm should match' + ); + } + }, `${algorithmName} vector-based sampleCiphertext decapsulation with ${config.description} (extractable=${extractable})`); + }); }); }); } @@ -430,19 +435,4 @@ assert_true(verified2, 'HMAC verification should succeed with key2'); } -// Helper function to compare two ArrayBuffers -function equalBuffers(a, b) { - if (a.byteLength !== b.byteLength) { - return false; - } - var aBytes = new Uint8Array(a); - var bBytes = new Uint8Array(b); - for (var i = 0; i < a.byteLength; i++) { - if (aBytes[i] !== bBytes[i]) { - return false; - } - } - return true; -} - define_key_tests();
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encap_decap/encap_decap_keys.tentative.https.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encap_decap/encap_decap_keys.tentative.https.any.worker-expected.txt index 35d7bed6..737aa0c1 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encap_decap/encap_decap_keys.tentative.https.any.worker-expected.txt +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encap_decap/encap_decap_keys.tentative.https.any.worker-expected.txt
@@ -1,124 +1,244 @@ This is a testharness.js-based test. -Found 60 FAIL, 0 TIMEOUT, 0 NOTRUN. -[FAIL] ML-KEM-512 encapsulateKey with AES-GCM-256 +Found 120 FAIL, 0 TIMEOUT, 0 NOTRUN. +[FAIL] ML-KEM-512 encapsulateKey with AES-GCM-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 decapsulateKey with AES-GCM-256 +[FAIL] ML-KEM-512 decapsulateKey with AES-GCM-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-GCM-256 +[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-GCM-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 encapsulateKey with AES-CBC-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 decapsulateKey with AES-CBC-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-CBC-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 encapsulateKey with AES-CTR-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 decapsulateKey with AES-CTR-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-CTR-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 encapsulateKey with AES-KW-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 decapsulateKey with AES-KW-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-KW-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 encapsulateKey with HMAC-SHA-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 decapsulateKey with HMAC-SHA-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with HMAC-SHA-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-GCM-256 +[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-GCM-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-CBC-256 +[FAIL] ML-KEM-512 encapsulateKey with AES-GCM-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 decapsulateKey with AES-GCM-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-GCM-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-GCM-256 (extractable=false) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-CTR-256 +[FAIL] ML-KEM-512 encapsulateKey with AES-CBC-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 decapsulateKey with AES-CBC-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-CBC-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-CBC-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-KW-256 +[FAIL] ML-KEM-512 encapsulateKey with AES-CBC-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 decapsulateKey with AES-CBC-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-CBC-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-CBC-256 (extractable=false) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with HMAC-SHA-256 +[FAIL] ML-KEM-512 encapsulateKey with AES-CTR-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 decapsulateKey with AES-CTR-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-CTR-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-CTR-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-768 encapsulateKey with AES-GCM-256 +[FAIL] ML-KEM-512 encapsulateKey with AES-CTR-256 (extractable=false) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-768 decapsulateKey with AES-GCM-256 +[FAIL] ML-KEM-512 decapsulateKey with AES-CTR-256 (extractable=false) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-GCM-256 +[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-CTR-256 (extractable=false) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-768 encapsulateKey with AES-CBC-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-768 decapsulateKey with AES-CBC-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-CBC-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-768 encapsulateKey with AES-CTR-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-768 decapsulateKey with AES-CTR-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-CTR-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-768 encapsulateKey with AES-KW-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-768 decapsulateKey with AES-KW-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-KW-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-768 encapsulateKey with HMAC-SHA-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-768 decapsulateKey with HMAC-SHA-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with HMAC-SHA-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-GCM-256 +[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-CTR-256 (extractable=false) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-CBC-256 +[FAIL] ML-KEM-512 encapsulateKey with AES-KW-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 decapsulateKey with AES-KW-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-KW-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-KW-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-CTR-256 +[FAIL] ML-KEM-512 encapsulateKey with AES-KW-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 decapsulateKey with AES-KW-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-KW-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-KW-256 (extractable=false) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-KW-256 +[FAIL] ML-KEM-512 encapsulateKey with HMAC-SHA-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 decapsulateKey with HMAC-SHA-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with HMAC-SHA-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with HMAC-SHA-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with HMAC-SHA-256 +[FAIL] ML-KEM-512 encapsulateKey with HMAC-SHA-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 decapsulateKey with HMAC-SHA-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with HMAC-SHA-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with HMAC-SHA-256 (extractable=false) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-1024 encapsulateKey with AES-GCM-256 +[FAIL] ML-KEM-768 encapsulateKey with AES-GCM-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-1024 decapsulateKey with AES-GCM-256 +[FAIL] ML-KEM-768 decapsulateKey with AES-GCM-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-GCM-256 +[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-GCM-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-1024 encapsulateKey with AES-CBC-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-1024 decapsulateKey with AES-CBC-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-CBC-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-1024 encapsulateKey with AES-CTR-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-1024 decapsulateKey with AES-CTR-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-CTR-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-1024 encapsulateKey with AES-KW-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-1024 decapsulateKey with AES-KW-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-KW-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-1024 encapsulateKey with HMAC-SHA-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-1024 decapsulateKey with HMAC-SHA-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with HMAC-SHA-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-GCM-256 +[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-GCM-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-CBC-256 +[FAIL] ML-KEM-768 encapsulateKey with AES-GCM-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 decapsulateKey with AES-GCM-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-GCM-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-GCM-256 (extractable=false) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-CTR-256 +[FAIL] ML-KEM-768 encapsulateKey with AES-CBC-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 decapsulateKey with AES-CBC-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-CBC-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-CBC-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-KW-256 +[FAIL] ML-KEM-768 encapsulateKey with AES-CBC-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 decapsulateKey with AES-CBC-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-CBC-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-CBC-256 (extractable=false) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with HMAC-SHA-256 +[FAIL] ML-KEM-768 encapsulateKey with AES-CTR-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 decapsulateKey with AES-CTR-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-CTR-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-CTR-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 encapsulateKey with AES-CTR-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 decapsulateKey with AES-CTR-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-CTR-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-CTR-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 encapsulateKey with AES-KW-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 decapsulateKey with AES-KW-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-KW-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-KW-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 encapsulateKey with AES-KW-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 decapsulateKey with AES-KW-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-KW-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-KW-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 encapsulateKey with HMAC-SHA-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 decapsulateKey with HMAC-SHA-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with HMAC-SHA-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with HMAC-SHA-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 encapsulateKey with HMAC-SHA-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 decapsulateKey with HMAC-SHA-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with HMAC-SHA-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with HMAC-SHA-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 encapsulateKey with AES-GCM-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 decapsulateKey with AES-GCM-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-GCM-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-GCM-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 encapsulateKey with AES-GCM-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 decapsulateKey with AES-GCM-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-GCM-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-GCM-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 encapsulateKey with AES-CBC-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 decapsulateKey with AES-CBC-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-CBC-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-CBC-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 encapsulateKey with AES-CBC-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 decapsulateKey with AES-CBC-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-CBC-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-CBC-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 encapsulateKey with AES-CTR-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 decapsulateKey with AES-CTR-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-CTR-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-CTR-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 encapsulateKey with AES-CTR-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 decapsulateKey with AES-CTR-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-CTR-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-CTR-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 encapsulateKey with AES-KW-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 decapsulateKey with AES-KW-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-KW-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-KW-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 encapsulateKey with AES-KW-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 decapsulateKey with AES-KW-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-KW-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-KW-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 encapsulateKey with HMAC-SHA-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 decapsulateKey with HMAC-SHA-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with HMAC-SHA-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with HMAC-SHA-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 encapsulateKey with HMAC-SHA-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 decapsulateKey with HMAC-SHA-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with HMAC-SHA-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with HMAC-SHA-256 (extractable=false) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encap_decap/ml_kem_encap_decap.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encap_decap/ml_kem_encap_decap.js deleted file mode 100644 index 9167efa..0000000 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encap_decap/ml_kem_encap_decap.js +++ /dev/null
@@ -1,410 +0,0 @@ -// Test implementation for ML-KEM encapsulate and decapsulate operations - -function define_tests() { - var subtle = self.crypto.subtle; - - // Test data for all ML-KEM variants - var variants = ['ML-KEM-512', 'ML-KEM-768', 'ML-KEM-1024']; - - variants.forEach(function (algorithmName) { - var testVector = ml_kem_vectors[algorithmName]; - - // Test encapsulateBits operation - promise_test(async function (test) { - // Generate a key pair for testing - var keyPair = await subtle.generateKey({ name: algorithmName }, false, [ - 'encapsulateBits', - 'decapsulateBits', - ]); - - // Test encapsulateBits - var encapsulatedBits = await subtle.encapsulateBits( - { name: algorithmName }, - keyPair.publicKey - ); - - assert_true( - encapsulatedBits instanceof Object, - 'encapsulateBits should return an object' - ); - assert_true( - encapsulatedBits.hasOwnProperty('sharedKey'), - 'Result should have sharedKey property' - ); - assert_true( - encapsulatedBits.hasOwnProperty('ciphertext'), - 'Result should have ciphertext property' - ); - assert_true( - encapsulatedBits.sharedKey instanceof ArrayBuffer, - 'sharedKey should be ArrayBuffer' - ); - assert_true( - encapsulatedBits.ciphertext instanceof ArrayBuffer, - 'ciphertext should be ArrayBuffer' - ); - - // Verify sharedKey length (should be 32 bytes for all ML-KEM variants) - assert_equals( - encapsulatedBits.sharedKey.byteLength, - 32, - 'Shared key should be 32 bytes' - ); - - // Verify ciphertext length based on algorithm variant - var expectedCiphertextLength; - switch (algorithmName) { - case 'ML-KEM-512': - expectedCiphertextLength = 768; - break; - case 'ML-KEM-768': - expectedCiphertextLength = 1088; - break; - case 'ML-KEM-1024': - expectedCiphertextLength = 1568; - break; - } - assert_equals( - encapsulatedBits.ciphertext.byteLength, - expectedCiphertextLength, - 'Ciphertext should be ' + - expectedCiphertextLength + - ' bytes for ' + - algorithmName - ); - }, algorithmName + ' encapsulateBits basic functionality'); - - // Test decapsulateBits operation - promise_test(async function (test) { - // Generate a key pair for testing - var keyPair = await subtle.generateKey({ name: algorithmName }, false, [ - 'encapsulateBits', - 'decapsulateBits', - ]); - - // First encapsulate to get ciphertext - var encapsulatedBits = await subtle.encapsulateBits( - { name: algorithmName }, - keyPair.publicKey - ); - - // Then decapsulate using the private key - var decapsulatedBits = await subtle.decapsulateBits( - { name: algorithmName }, - keyPair.privateKey, - encapsulatedBits.ciphertext - ); - - assert_true( - decapsulatedBits instanceof ArrayBuffer, - 'decapsulateBits should return ArrayBuffer' - ); - assert_equals( - decapsulatedBits.byteLength, - 32, - 'Decapsulated bits should be 32 bytes' - ); - - // The decapsulated shared secret should match the original - assert_true( - equalBuffers(decapsulatedBits, encapsulatedBits.sharedKey), - 'Decapsulated shared secret should match original' - ); - }, algorithmName + ' decapsulateBits basic functionality'); - - // Test encapsulateKey operation - promise_test(async function (test) { - // Generate a key pair for testing - var keyPair = await subtle.generateKey({ name: algorithmName }, false, [ - 'encapsulateKey', - 'decapsulateKey', - ]); - - // Test encapsulateKey with AES-GCM as the shared key algorithm - var encapsulatedKey = await subtle.encapsulateKey( - { name: algorithmName }, - keyPair.publicKey, - { name: 'AES-GCM', length: 256 }, - true, - ['encrypt', 'decrypt'] - ); - - assert_true( - encapsulatedKey instanceof Object, - 'encapsulateKey should return an object' - ); - assert_true( - encapsulatedKey.hasOwnProperty('sharedKey'), - 'Result should have sharedKey property' - ); - assert_true( - encapsulatedKey.hasOwnProperty('ciphertext'), - 'Result should have ciphertext property' - ); - assert_true( - encapsulatedKey.sharedKey instanceof CryptoKey, - 'sharedKey should be a CryptoKey' - ); - assert_true( - encapsulatedKey.ciphertext instanceof ArrayBuffer, - 'ciphertext should be ArrayBuffer' - ); - - // Verify the shared key properties - assert_equals( - encapsulatedKey.sharedKey.type, - 'secret', - 'Shared key should be secret type' - ); - assert_equals( - encapsulatedKey.sharedKey.algorithm.name, - 'AES-GCM', - 'Shared key algorithm should be AES-GCM' - ); - assert_equals( - encapsulatedKey.sharedKey.algorithm.length, - 256, - 'Shared key length should be 256' - ); - assert_true( - encapsulatedKey.sharedKey.extractable, - 'Shared key should be extractable as specified' - ); - assert_array_equals( - encapsulatedKey.sharedKey.usages, - ['encrypt', 'decrypt'], - 'Shared key should have correct usages' - ); - }, algorithmName + ' encapsulateKey basic functionality'); - - // Test decapsulateKey operation - promise_test(async function (test) { - // Generate a key pair for testing - var keyPair = await subtle.generateKey({ name: algorithmName }, false, [ - 'encapsulateKey', - 'decapsulateKey', - ]); - - // First encapsulate to get ciphertext - var encapsulatedKey = await subtle.encapsulateKey( - { name: algorithmName }, - keyPair.publicKey, - { name: 'AES-GCM', length: 256 }, - true, - ['encrypt', 'decrypt'] - ); - - // Then decapsulate using the private key - var decapsulatedKey = await subtle.decapsulateKey( - { name: algorithmName }, - keyPair.privateKey, - encapsulatedKey.ciphertext, - { name: 'AES-GCM', length: 256 }, - true, - ['encrypt', 'decrypt'] - ); - - assert_true( - decapsulatedKey instanceof CryptoKey, - 'decapsulateKey should return a CryptoKey' - ); - assert_equals( - decapsulatedKey.type, - 'secret', - 'Decapsulated key should be secret type' - ); - assert_equals( - decapsulatedKey.algorithm.name, - 'AES-GCM', - 'Decapsulated key algorithm should be AES-GCM' - ); - assert_equals( - decapsulatedKey.algorithm.length, - 256, - 'Decapsulated key length should be 256' - ); - assert_true( - decapsulatedKey.extractable, - 'Decapsulated key should be extractable as specified' - ); - assert_array_equals( - decapsulatedKey.usages, - ['encrypt', 'decrypt'], - 'Decapsulated key should have correct usages' - ); - - // Extract both keys and verify they are identical - var originalKeyMaterial = await subtle.exportKey( - 'raw', - encapsulatedKey.sharedKey - ); - var decapsulatedKeyMaterial = await subtle.exportKey( - 'raw', - decapsulatedKey - ); - - assert_true( - equalBuffers(originalKeyMaterial, decapsulatedKeyMaterial), - 'Decapsulated key material should match original' - ); - }, algorithmName + ' decapsulateKey basic functionality'); - - // Test error cases for encapsulateBits - promise_test(async function (test) { - var keyPair = await subtle.generateKey({ name: algorithmName }, false, [ - 'encapsulateBits', - 'decapsulateBits', - ]); - - // Test with wrong key type (private key instead of public) - await promise_rejects_dom( - test, - 'InvalidAccessError', - subtle.encapsulateBits({ name: algorithmName }, keyPair.privateKey), - 'encapsulateBits should reject private key' - ); - - // Test with wrong algorithm name - await promise_rejects_dom( - test, - 'InvalidAccessError', - subtle.encapsulateBits({ name: 'AES-GCM' }, keyPair.publicKey), - 'encapsulateBits should reject mismatched algorithm' - ); - }, algorithmName + ' encapsulateBits error cases'); - - // Test error cases for decapsulateBits - promise_test(async function (test) { - var keyPair = await subtle.generateKey({ name: algorithmName }, false, [ - 'encapsulateBits', - 'decapsulateBits', - ]); - - var encapsulatedBits = await subtle.encapsulateBits( - { name: algorithmName }, - keyPair.publicKey - ); - - // Test with wrong key type (public key instead of private) - await promise_rejects_dom( - test, - 'InvalidAccessError', - subtle.decapsulateBits( - { name: algorithmName }, - keyPair.publicKey, - encapsulatedBits.ciphertext - ), - 'decapsulateBits should reject public key' - ); - - // Test with wrong algorithm name - await promise_rejects_dom( - test, - 'InvalidAccessError', - subtle.decapsulateBits( - { name: 'AES-GCM' }, - keyPair.privateKey, - encapsulatedBits.ciphertext - ), - 'decapsulateBits should reject mismatched algorithm' - ); - - // Test with invalid ciphertext - var invalidCiphertext = new Uint8Array(10); // Wrong size - await promise_rejects_dom( - test, - 'OperationError', - subtle.decapsulateBits( - { name: algorithmName }, - keyPair.privateKey, - invalidCiphertext - ), - 'decapsulateBits should reject invalid ciphertext' - ); - }, algorithmName + ' decapsulateBits error cases'); - - // Test error cases for encapsulateKey - promise_test(async function (test) { - var keyPair = await subtle.generateKey({ name: algorithmName }, false, [ - 'encapsulateKey', - 'decapsulateKey', - ]); - - // Test with key without encapsulateKey usage - var wrongKeyPair = await subtle.generateKey( - { name: algorithmName }, - false, - ['decapsulateKey'] // Missing encapsulateKey usage - ); - - await promise_rejects_dom( - test, - 'InvalidAccessError', - subtle.encapsulateKey( - { name: algorithmName }, - wrongKeyPair.publicKey, - { name: 'AES-GCM', length: 256 }, - true, - ['encrypt', 'decrypt'] - ), - 'encapsulateKey should reject key without encapsulateKey usage' - ); - }, algorithmName + ' encapsulateKey error cases'); - - // Test error cases for decapsulateKey - promise_test(async function (test) { - var keyPair = await subtle.generateKey({ name: algorithmName }, false, [ - 'encapsulateKey', - 'decapsulateKey', - ]); - - var encapsulatedKey = await subtle.encapsulateKey( - { name: algorithmName }, - keyPair.publicKey, - { name: 'AES-GCM', length: 256 }, - true, - ['encrypt', 'decrypt'] - ); - - // Test with key without decapsulateKey usage - var wrongKeyPair = await subtle.generateKey( - { name: algorithmName }, - false, - ['encapsulateKey'] // Missing decapsulateKey usage - ); - - await promise_rejects_dom( - test, - 'InvalidAccessError', - subtle.decapsulateKey( - { name: algorithmName }, - wrongKeyPair.privateKey, - encapsulatedKey.ciphertext, - { name: 'AES-GCM', length: 256 }, - true, - ['encrypt', 'decrypt'] - ), - 'decapsulateKey should reject key without decapsulateKey usage' - ); - }, algorithmName + ' decapsulateKey error cases'); - }); -} - -// Helper function to compare two ArrayBuffers -function equalBuffers(a, b) { - if (a.byteLength !== b.byteLength) { - return false; - } - var aBytes = new Uint8Array(a); - var bBytes = new Uint8Array(b); - for (var i = 0; i < a.byteLength; i++) { - if (aBytes[i] !== bBytes[i]) { - return false; - } - } - return true; -} - -function run_test() { - define_tests(); -}
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encrypt_decrypt/aes.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encrypt_decrypt/aes.js index 456f664..879a6ef 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encrypt_decrypt/aes.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encrypt_decrypt/aes.js
@@ -482,34 +482,5 @@ } } - // Returns a copy of the sourceBuffer it is sent. - function copyBuffer(sourceBuffer) { - var source = new Uint8Array(sourceBuffer); - var copy = new Uint8Array(sourceBuffer.byteLength) - - for (var i=0; i<source.byteLength; i++) { - copy[i] = source[i]; - } - - return copy; - } - - function equalBuffers(a, b) { - if (a.byteLength !== b.byteLength) { - return false; - } - - var aBytes = new Uint8Array(a); - var bBytes = new Uint8Array(b); - - for (var i=0; i<a.byteLength; i++) { - if (aBytes[i] !== bBytes[i]) { - return false; - } - } - - return true; - } - return; }
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encrypt_decrypt/aes_cbc.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encrypt_decrypt/aes_cbc.https.any.js index 35637a4..ec09aae 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encrypt_decrypt/aes_cbc.https.any.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encrypt_decrypt/aes_cbc.https.any.js
@@ -1,4 +1,5 @@ // META: title=WebCryptoAPI: encrypt() Using AES-CBC +// META: script=../util/helpers.js // META: script=aes_cbc_vectors.js // META: script=aes.js // META: timeout=long
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encrypt_decrypt/aes_ctr.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encrypt_decrypt/aes_ctr.https.any.js index 9f0c6690..f9d85bb 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encrypt_decrypt/aes_ctr.https.any.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encrypt_decrypt/aes_ctr.https.any.js
@@ -1,4 +1,5 @@ // META: title=WebCryptoAPI: encrypt() Using AES-CTR +// META: script=../util/helpers.js // META: script=aes_ctr_vectors.js // META: script=aes.js // META: timeout=long
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encrypt_decrypt/aes_gcm.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encrypt_decrypt/aes_gcm.https.any.js index 6e3a6efb..b3e6b5f 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encrypt_decrypt/aes_gcm.https.any.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encrypt_decrypt/aes_gcm.https.any.js
@@ -1,4 +1,5 @@ // META: title=WebCryptoAPI: encrypt() Using AES-GCM w/ 96-bit iv +// META: script=../util/helpers.js // META: script=aes_gcm_96_iv_fixtures.js // META: script=aes_gcm_vectors.js // META: script=aes.js
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encrypt_decrypt/aes_gcm_256_iv.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encrypt_decrypt/aes_gcm_256_iv.https.any.js index 92900fb..196a8ea9 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encrypt_decrypt/aes_gcm_256_iv.https.any.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encrypt_decrypt/aes_gcm_256_iv.https.any.js
@@ -1,4 +1,5 @@ // META: title=WebCryptoAPI: encrypt() Using AES-GCM w/ 256-bit iv +// META: script=../util/helpers.js // META: script=aes_gcm_256_iv_fixtures.js // META: script=aes_gcm_vectors.js // META: script=aes.js
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encrypt_decrypt/aes_gcm_vectors.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encrypt_decrypt/aes_gcm_vectors.js index 965fe95..f0d88a9 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encrypt_decrypt/aes_gcm_vectors.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encrypt_decrypt/aes_gcm_vectors.js
@@ -59,7 +59,6 @@ // Scenarios that should fail because of a bad tag length, causing an OperationError var failing = []; keyLengths.forEach(function(keyLength) { - // First, make some tests for bad tag lengths [24, 48, 72, 95, 129].forEach(function(badTagLength) { failing.push({ name: "AES-GCM " + keyLength.toString() + "-bit key, " + (iv.byteLength << 3).toString() + "-bit iv, " + "illegal tag length " + badTagLength.toString() + "-bits",
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encrypt_decrypt/aes_ocb.tentative.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encrypt_decrypt/aes_ocb.tentative.https.any.js index 1d321fc..cca34e9 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encrypt_decrypt/aes_ocb.tentative.https.any.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encrypt_decrypt/aes_ocb.tentative.https.any.js
@@ -1,4 +1,5 @@ // META: title=WebCryptoAPI: encrypt() Using AES-OCB w/ 120-bit iv +// META: script=../util/helpers.js // META: script=aes_ocb_fixtures.js // META: script=aes_ocb_vectors.js // META: script=aes.js
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encrypt_decrypt/chacha20_poly1305.tentative.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encrypt_decrypt/chacha20_poly1305.tentative.https.any.js index ed21fb5..d03f7c0 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encrypt_decrypt/chacha20_poly1305.tentative.https.any.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encrypt_decrypt/chacha20_poly1305.tentative.https.any.js
@@ -1,5 +1,6 @@ // META: title=WebCryptoAPI: encrypt()/decrypt() ChaCha20-Poly1305 // META: timeout=long +// META: script=../util/helpers.js var subtle = crypto.subtle; // Change to test prefixed implementations @@ -120,20 +121,6 @@ }, }; -function equalBuffers(a, b) { - if (a.byteLength !== b.byteLength) { - return false; - } - var aBytes = new Uint8Array(a); - var bBytes = new Uint8Array(b); - for (var i = 0; i < a.byteLength; i++) { - if (aBytes[i] !== bBytes[i]) { - return false; - } - } - return true; -} - // Test ChaCha20-Poly1305 encryption/decryption var algorithmName = 'ChaCha20-Poly1305';
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encrypt_decrypt/rsa.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encrypt_decrypt/rsa.js index 6f585cbe..071c086b 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encrypt_decrypt/rsa.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encrypt_decrypt/rsa.js
@@ -560,18 +560,7 @@ .then(function(key) { vector.publicKey = key; return vector; - }); // Returns a copy of the sourceBuffer it is sent. - function copyBuffer(sourceBuffer) { - var source = new Uint8Array(sourceBuffer); - var copy = new Uint8Array(sourceBuffer.byteLength) - - for (var i=0; i<source.byteLength; i++) { - copy[i] = source[i]; - } - - return copy; - } - + }); } if (vector.privateKey !== null) { @@ -589,34 +578,5 @@ return Promise.all([publicPromise, privatePromise]); } - // Returns a copy of the sourceBuffer it is sent. - function copyBuffer(sourceBuffer) { - var source = new Uint8Array(sourceBuffer); - var copy = new Uint8Array(sourceBuffer.byteLength) - - for (var i=0; i<source.byteLength; i++) { - copy[i] = source[i]; - } - - return copy; - } - - function equalBuffers(a, b) { - if (a.byteLength !== b.byteLength) { - return false; - } - - var aBytes = new Uint8Array(a); - var bBytes = new Uint8Array(b); - - for (var i=0; i<a.byteLength; i++) { - if (aBytes[i] !== bBytes[i]) { - return false; - } - } - - return true; - } - return; }
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encrypt_decrypt/rsa_oaep.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encrypt_decrypt/rsa_oaep.https.any.js index 20fd17c5..3550f5e 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encrypt_decrypt/rsa_oaep.https.any.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/encrypt_decrypt/rsa_oaep.https.any.js
@@ -1,4 +1,5 @@ // META: title=WebCryptoAPI: encrypt() Using RSA-OAEP +// META: script=../util/helpers.js // META: script=rsa_vectors.js // META: script=rsa.js // META: timeout=long
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/getPublicKey.tentative.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/getPublicKey.tentative.https.any.js index 5c61075..1b151345 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/getPublicKey.tentative.https.any.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/getPublicKey.tentative.https.any.js
@@ -155,18 +155,6 @@ // Test with empty usages array algorithms.forEach(function(algorithm) { promise_test(async function(t) { - // Skip X25519 if not supported - if (algorithm.name === "X25519") { - try { - await crypto.subtle.generateKey(algorithm.generateKeyParams, false, algorithm.usages); - } catch (e) { - if (e.name === "NotSupportedError") { - return; - } - throw e; - } - } - const keyPair = await crypto.subtle.generateKey( algorithm.generateKeyParams, false,
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/ML-DSA_importKey.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/ML-DSA_importKey.js index 3723b32..d9257ac 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/ML-DSA_importKey.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/ML-DSA_importKey.js
@@ -106,44 +106,6 @@ // Helper methods follow: -// Are two array buffers the same? -function equalBuffers(a, b) { - if (a.byteLength !== b.byteLength) { - return false; - } - - var aBytes = new Uint8Array(a); - var bBytes = new Uint8Array(b); - - for (var i = 0; i < a.byteLength; i++) { - if (aBytes[i] !== bBytes[i]) { - return false; - } - } - - return true; -} - -// Are two Jwk objects "the same"? That is, does the object returned include -// matching values for each property that was expected? It's okay if the -// returned object has extra methods; they aren't checked. -function equalJwk(expected, got) { - var fields = Object.keys(expected); - var fieldName; - - for (var i = 0; i < fields.length; i++) { - fieldName = fields[i]; - if (!(fieldName in got)) { - return false; - } - if (expected[fieldName] !== got[fieldName]) { - return false; - } - } - - return true; -} - // Convert method parameters to a string to uniquely name each test function parameterString(format, data, algorithm, extractable, usages) { if ('byteLength' in data) { @@ -166,57 +128,3 @@ return result; } - -// Character representation of any object we may use as a parameter. -function objectToString(obj) { - var keyValuePairs = []; - - if (Array.isArray(obj)) { - return ( - '[' + - obj - .map(function (elem) { - return objectToString(elem); - }) - .join(', ') + - ']' - ); - } else if (typeof obj === 'object') { - Object.keys(obj) - .sort() - .forEach(function (keyName) { - keyValuePairs.push(keyName + ': ' + objectToString(obj[keyName])); - }); - return '{' + keyValuePairs.join(', ') + '}'; - } else if (typeof obj === 'undefined') { - return 'undefined'; - } else { - return obj.toString(); - } - - var keyValuePairs = []; - - Object.keys(obj) - .sort() - .forEach(function (keyName) { - var value = obj[keyName]; - if (typeof value === 'object') { - value = objectToString(value); - } else if (typeof value === 'array') { - value = - '[' + - value - .map(function (elem) { - return objectToString(elem); - }) - .join(', ') + - ']'; - } else { - value = value.toString(); - } - - keyValuePairs.push(keyName + ': ' + value); - }); - - return '{' + keyValuePairs.join(', ') + '}'; -}
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/ML-KEM_importKey.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/ML-KEM_importKey.js index c264a16..ad2f7504 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/ML-KEM_importKey.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/ML-KEM_importKey.js
@@ -106,44 +106,6 @@ // Helper methods follow: -// Are two array buffers the same? -function equalBuffers(a, b) { - if (a.byteLength !== b.byteLength) { - return false; - } - - var aBytes = new Uint8Array(a); - var bBytes = new Uint8Array(b); - - for (var i = 0; i < a.byteLength; i++) { - if (aBytes[i] !== bBytes[i]) { - return false; - } - } - - return true; -} - -// Are two Jwk objects "the same"? That is, does the object returned include -// matching values for each property that was expected? It's okay if the -// returned object has extra methods; they aren't checked. -function equalJwk(expected, got) { - var fields = Object.keys(expected); - var fieldName; - - for (var i = 0; i < fields.length; i++) { - fieldName = fields[i]; - if (!(fieldName in got)) { - return false; - } - if (expected[fieldName] !== got[fieldName]) { - return false; - } - } - - return true; -} - // Convert method parameters to a string to uniquely name each test function parameterString(format, data, algorithm, extractable, usages) { if ('byteLength' in data) { @@ -166,57 +128,3 @@ return result; } - -// Character representation of any object we may use as a parameter. -function objectToString(obj) { - var keyValuePairs = []; - - if (Array.isArray(obj)) { - return ( - '[' + - obj - .map(function (elem) { - return objectToString(elem); - }) - .join(', ') + - ']' - ); - } else if (typeof obj === 'object') { - Object.keys(obj) - .sort() - .forEach(function (keyName) { - keyValuePairs.push(keyName + ': ' + objectToString(obj[keyName])); - }); - return '{' + keyValuePairs.join(', ') + '}'; - } else if (typeof obj === 'undefined') { - return 'undefined'; - } else { - return obj.toString(); - } - - var keyValuePairs = []; - - Object.keys(obj) - .sort() - .forEach(function (keyName) { - var value = obj[keyName]; - if (typeof value === 'object') { - value = objectToString(value); - } else if (typeof value === 'array') { - value = - '[' + - value - .map(function (elem) { - return objectToString(elem); - }) - .join(', ') + - ']'; - } else { - value = value.toString(); - } - - keyValuePairs.push(keyName + ': ' + value); - }); - - return '{' + keyValuePairs.join(', ') + '}'; -}
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/ec_importKey.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/ec_importKey.https.any.js index 6a5cc8d..3b78bab 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/ec_importKey.https.any.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/ec_importKey.https.any.js
@@ -220,44 +220,6 @@ // Helper methods follow: - // Are two array buffers the same? - function equalBuffers(a, b) { - if (a.byteLength !== b.byteLength) { - return false; - } - - var aBytes = new Uint8Array(a); - var bBytes = new Uint8Array(b); - - for (var i=0; i<a.byteLength; i++) { - if (aBytes[i] !== bBytes[i]) { - return false; - } - } - - return true; - } - - // Are two Jwk objects "the same"? That is, does the object returned include - // matching values for each property that was expected? It's okay if the - // returned object has extra methods; they aren't checked. - function equalJwk(expected, got) { - var fields = Object.keys(expected); - var fieldName; - - for(var i=0; i<fields.length; i++) { - fieldName = fields[i]; - if (!(fieldName in got)) { - return false; - } - if (expected[fieldName] !== got[fieldName]) { - return false; - } - } - - return true; - } - // Build minimal Jwk objects from raw key data and algorithm specifications function jwkData(keyData, algorithm) { var result = { @@ -273,17 +235,6 @@ return result; } - // Jwk format wants Base 64 without the typical padding at the end. - function byteArrayToUnpaddedBase64(byteArray){ - var binaryString = ""; - for (var i=0; i<byteArray.byteLength; i++){ - binaryString += String.fromCharCode(byteArray[i]); - } - var base64String = btoa(binaryString); - - return base64String.replace(/=/g, ""); - } - // Convert method parameters to a string to uniquely name each test function parameterString(format, compressed, data, algorithm, extractable, usages) { if ("byteLength" in data) { @@ -301,38 +252,3 @@ return result; } - - // Character representation of any object we may use as a parameter. - function objectToString(obj) { - var keyValuePairs = []; - - if (Array.isArray(obj)) { - return "[" + obj.map(function(elem){return objectToString(elem);}).join(", ") + "]"; - } else if (typeof obj === "object") { - Object.keys(obj).sort().forEach(function(keyName) { - keyValuePairs.push(keyName + ": " + objectToString(obj[keyName])); - }); - return "{" + keyValuePairs.join(", ") + "}"; - } else if (typeof obj === "undefined") { - return "undefined"; - } else { - return obj.toString(); - } - - var keyValuePairs = []; - - Object.keys(obj).sort().forEach(function(keyName) { - var value = obj[keyName]; - if (typeof value === "object") { - value = objectToString(value); - } else if (typeof value === "array") { - value = "[" + value.map(function(elem){return objectToString(elem);}).join(", ") + "]"; - } else { - value = value.toString(); - } - - keyValuePairs.push(keyName + ": " + value); - }); - - return "{" + keyValuePairs.join(", ") + "}"; - }
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey.js index 8627f85e..665c9c1 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey.js
@@ -102,44 +102,6 @@ // Helper methods follow: -// Are two array buffers the same? -function equalBuffers(a, b) { - if (a.byteLength !== b.byteLength) { - return false; - } - - var aBytes = new Uint8Array(a); - var bBytes = new Uint8Array(b); - - for (var i=0; i<a.byteLength; i++) { - if (aBytes[i] !== bBytes[i]) { - return false; - } - } - - return true; -} - -// Are two Jwk objects "the same"? That is, does the object returned include -// matching values for each property that was expected? It's okay if the -// returned object has extra methods; they aren't checked. -function equalJwk(expected, got) { - var fields = Object.keys(expected); - var fieldName; - - for(var i=0; i<fields.length; i++) { - fieldName = fields[i]; - if (!(fieldName in got)) { - return false; - } - if (expected[fieldName] !== got[fieldName]) { - return false; - } - } - - return true; -} - // Build minimal Jwk objects from raw key data and algorithm specifications function jwkData(keyData, algorithm) { var result = { @@ -155,17 +117,6 @@ return result; } -// Jwk format wants Base 64 without the typical padding at the end. -function byteArrayToUnpaddedBase64(byteArray){ - var binaryString = ""; - for (var i=0; i<byteArray.byteLength; i++){ - binaryString += String.fromCharCode(byteArray[i]); - } - var base64String = btoa(binaryString); - - return base64String.replace(/=/g, ""); -} - // Convert method parameters to a string to uniquely name each test function parameterString(format, data, algorithm, extractable, usages) { if ("byteLength" in data) { @@ -183,38 +134,3 @@ return result; } - -// Character representation of any object we may use as a parameter. -function objectToString(obj) { - var keyValuePairs = []; - - if (Array.isArray(obj)) { - return "[" + obj.map(function(elem){return objectToString(elem);}).join(", ") + "]"; - } else if (typeof obj === "object") { - Object.keys(obj).sort().forEach(function(keyName) { - keyValuePairs.push(keyName + ": " + objectToString(obj[keyName])); - }); - return "{" + keyValuePairs.join(", ") + "}"; - } else if (typeof obj === "undefined") { - return "undefined"; - } else { - return obj.toString(); - } - - var keyValuePairs = []; - - Object.keys(obj).sort().forEach(function(keyName) { - var value = obj[keyName]; - if (typeof value === "object") { - value = objectToString(value); - } else if (typeof value === "array") { - value = "[" + value.map(function(elem){return objectToString(elem);}).join(", ") + "]"; - } else { - value = value.toString(); - } - - keyValuePairs.push(keyName + ": " + value); - }); - - return "{" + keyValuePairs.join(", ") + "}"; -}
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/rsa_importKey.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/rsa_importKey.https.any.js index c0917ca..049f50ce 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/rsa_importKey.https.any.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/rsa_importKey.https.any.js
@@ -153,44 +153,6 @@ // Helper methods follow: - // Are two array buffers the same? - function equalBuffers(a, b) { - if (a.byteLength !== b.byteLength) { - return false; - } - - var aBytes = new Uint8Array(a); - var bBytes = new Uint8Array(b); - - for (var i=0; i<a.byteLength; i++) { - if (aBytes[i] !== bBytes[i]) { - return false; - } - } - - return true; - } - - // Are two Jwk objects "the same"? That is, does the object returned include - // matching values for each property that was expected? It's okay if the - // returned object has extra methods; they aren't checked. - function equalJwk(expected, got) { - var fields = Object.keys(expected); - var fieldName; - - for(var i=0; i<fields.length; i++) { - fieldName = fields[i]; - if (!(fieldName in got)) { - return false; - } - if (expected[fieldName] !== got[fieldName]) { - return false; - } - } - - return true; - } - // Build minimal Jwk objects from raw key data and algorithm specifications function jwkData(keyData, algorithm) { var result = { @@ -206,17 +168,6 @@ return result; } - // Jwk format wants Base 64 without the typical padding at the end. - function byteArrayToUnpaddedBase64(byteArray){ - var binaryString = ""; - for (var i=0; i<byteArray.byteLength; i++){ - binaryString += String.fromCharCode(byteArray[i]); - } - var base64String = btoa(binaryString); - - return base64String.replace(/=/g, ""); - } - // Convert method parameters to a string to uniquely name each test function parameterString(format, data, algorithm, extractable, usages) { if ("byteLength" in data) { @@ -234,38 +185,3 @@ return result; } - - // Character representation of any object we may use as a parameter. - function objectToString(obj) { - var keyValuePairs = []; - - if (Array.isArray(obj)) { - return "[" + obj.map(function(elem){return objectToString(elem);}).join(", ") + "]"; - } else if (typeof obj === "object") { - Object.keys(obj).sort().forEach(function(keyName) { - keyValuePairs.push(keyName + ": " + objectToString(obj[keyName])); - }); - return "{" + keyValuePairs.join(", ") + "}"; - } else if (typeof obj === "undefined") { - return "undefined"; - } else { - return obj.toString(); - } - - var keyValuePairs = []; - - Object.keys(obj).sort().forEach(function(keyName) { - var value = obj[keyName]; - if (typeof value === "object") { - value = objectToString(value); - } else if (typeof value === "array") { - value = "[" + value.map(function(elem){return objectToString(elem);}).join(", ") + "]"; - } else { - value = value.toString(); - } - - keyValuePairs.push(keyName + ": " + value); - }); - - return "{" + keyValuePairs.join(", ") + "}"; - }
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/symmetric_importKey.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/symmetric_importKey.js index 07f367c..8633af52 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/symmetric_importKey.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/symmetric_importKey.js
@@ -115,44 +115,6 @@ // Helper methods follow: - // Are two array buffers the same? - function equalBuffers(a, b) { - if (a.byteLength !== b.byteLength) { - return false; - } - - var aBytes = new Uint8Array(a); - var bBytes = new Uint8Array(b); - - for (var i=0; i<a.byteLength; i++) { - if (aBytes[i] !== bBytes[i]) { - return false; - } - } - - return true; - } - - // Are two Jwk objects "the same"? That is, does the object returned include - // matching values for each property that was expected? It's okay if the - // returned object has extra methods; they aren't checked. - function equalJwk(expected, got) { - var fields = Object.keys(expected); - var fieldName; - - for(var i=0; i<fields.length; i++) { - fieldName = fields[i]; - if (!(fieldName in got)) { - return false; - } - if (expected[fieldName] !== got[fieldName]) { - return false; - } - } - - return true; - } - // Build minimal Jwk objects from raw key data and algorithm specifications function jwkData(keyData, algorithm) { var result = { @@ -170,17 +132,6 @@ return result; } - // Jwk format wants Base 64 without the typical padding at the end. - function byteArrayToUnpaddedBase64(byteArray){ - var binaryString = ""; - for (var i=0; i<byteArray.byteLength; i++){ - binaryString += String.fromCharCode(byteArray[i]); - } - var base64String = btoa(binaryString); - - return base64String.replace(/=/g, ""); - } - // Convert method parameters to a string to uniquely name each test function parameterString(format, data, algorithm, extractable, usages) { var result = "(" + @@ -193,39 +144,4 @@ return result; } - - // Character representation of any object we may use as a parameter. - function objectToString(obj) { - var keyValuePairs = []; - - if (Array.isArray(obj)) { - return "[" + obj.map(function(elem){return objectToString(elem);}).join(", ") + "]"; - } else if (typeof obj === "object") { - Object.keys(obj).sort().forEach(function(keyName) { - keyValuePairs.push(keyName + ": " + objectToString(obj[keyName])); - }); - return "{" + keyValuePairs.join(", ") + "}"; - } else if (typeof obj === "undefined") { - return "undefined"; - } else { - return obj.toString(); - } - - var keyValuePairs = []; - - Object.keys(obj).sort().forEach(function(keyName) { - var value = obj[keyName]; - if (typeof value === "object") { - value = objectToString(value); - } else if (typeof value === "array") { - value = "[" + value.map(function(elem){return objectToString(elem);}).join(", ") + "]"; - } else { - value = value.toString(); - } - - keyValuePairs.push(keyName + ": " + value); - }); - - return "{" + keyValuePairs.join(", ") + "}"; - } }
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/ecdsa.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/ecdsa.https.any.js index 9764cc33..3f1e2e5 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/ecdsa.https.any.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/ecdsa.https.any.js
@@ -1,4 +1,5 @@ // META: title=WebCryptoAPI: sign() and verify() Using ECDSA +// META: script=../util/helpers.js // META: script=ecdsa_vectors.js // META: script=ecdsa.js // META: timeout=long
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/ecdsa.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/ecdsa.js index b2e0bf60..cc13b1b 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/ecdsa.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/ecdsa.js
@@ -654,34 +654,5 @@ return Promise.all([publicPromise, privatePromise]); } - // Returns a copy of the sourceBuffer it is sent. - function copyBuffer(sourceBuffer) { - var source = new Uint8Array(sourceBuffer); - var copy = new Uint8Array(sourceBuffer.byteLength) - - for (var i=0; i<source.byteLength; i++) { - copy[i] = source[i]; - } - - return copy; - } - - function equalBuffers(a, b) { - if (a.byteLength !== b.byteLength) { - return false; - } - - var aBytes = new Uint8Array(a); - var bBytes = new Uint8Array(b); - - for (var i=0; i<a.byteLength; i++) { - if (aBytes[i] !== bBytes[i]) { - return false; - } - } - - return true; - } - return; }
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/eddsa.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/eddsa.js index 5ff6f21..7796156 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/eddsa.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/eddsa.js
@@ -333,17 +333,5 @@ }, "Sign and verify using generated " + vector.algorithmName + " keys."); }); - // Returns a copy of the sourceBuffer it is sent. - function copyBuffer(sourceBuffer) { - var source = new Uint8Array(sourceBuffer); - var copy = new Uint8Array(sourceBuffer.byteLength) - - for (var i=0; i<source.byteLength; i++) { - copy[i] = source[i]; - } - - return copy; - } - return; }
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/eddsa_curve25519.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/eddsa_curve25519.https.any.js index 3be9eef..b012b64 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/eddsa_curve25519.https.any.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/eddsa_curve25519.https.any.js
@@ -1,4 +1,5 @@ // META: title=WebCryptoAPI: sign() and verify() Using EdDSA +// META: script=../util/helpers.js // META: script=eddsa_vectors.js // META: script=eddsa.js // META: timeout=long
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/eddsa_curve448.tentative.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/eddsa_curve448.tentative.https.any.js index 6960c29..281bb63 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/eddsa_curve448.tentative.https.any.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/eddsa_curve448.tentative.https.any.js
@@ -1,4 +1,5 @@ // META: title=WebCryptoAPI: sign() and verify() Using EdDSA +// META: script=../util/helpers.js // META: script=eddsa_vectors.js // META: script=eddsa.js // META: timeout=long
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/eddsa_small_order_points.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/eddsa_small_order_points.https.any.js index be025557f..5192b56 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/eddsa_small_order_points.https.any.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/eddsa_small_order_points.https.any.js
@@ -1,4 +1,5 @@ // META: title=WebCryptoAPI: verify() Using EdDSA with small-order points +// META: script=../util/helpers.js // META: script=eddsa_vectors.js // META: script=eddsa_small_order_points.js // META: timeout=long
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/hmac.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/hmac.https.any.js index 419bab05..a6c88f8 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/hmac.https.any.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/hmac.https.any.js
@@ -1,4 +1,5 @@ // META: title=WebCryptoAPI: sign() and verify() Using HMAC +// META: script=../util/helpers.js // META: script=hmac_vectors.js // META: script=hmac.js // META: timeout=long
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/hmac.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/hmac.js index 8a099f4..929d946 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/hmac.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/hmac.js
@@ -490,34 +490,5 @@ } } - // Returns a copy of the sourceBuffer it is sent. - function copyBuffer(sourceBuffer) { - var source = new Uint8Array(sourceBuffer); - var copy = new Uint8Array(sourceBuffer.byteLength) - - for (var i=0; i<source.byteLength; i++) { - copy[i] = source[i]; - } - - return copy; - } - - function equalBuffers(a, b) { - if (a.byteLength !== b.byteLength) { - return false; - } - - var aBytes = new Uint8Array(a); - var bBytes = new Uint8Array(b); - - for (var i=0; i<a.byteLength; i++) { - if (aBytes[i] !== bBytes[i]) { - return false; - } - } - - return true; - } - return; }
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/kmac.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/kmac.js index f3cc9b4c..d9d82d1 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/kmac.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/kmac.js
@@ -15,7 +15,7 @@ var promise = importVectorKeys(vector, ["verify", "sign"]) .then(function(vector) { promise_test(function(test) { - var algorithmParams = {name: vector.algorithm, length: vector.length}; + var algorithmParams = {name: vector.algorithm, outputLength: vector.outputLength}; if (vector.customization !== undefined) { algorithmParams.customization = vector.customization; } @@ -48,7 +48,7 @@ var signature = copyBuffer(vector.signature); signature[0] = 255 - signature[0]; var algorithmParams = { - length: vector.length, + outputLength: vector.outputLength, get name() { signature[0] = vector.signature[0]; return vector.algorithm; @@ -81,7 +81,7 @@ .then(function(vector) { promise_test(function(test) { var signature = copyBuffer(vector.signature); - var algorithmParams = {name: vector.algorithm, length: vector.length}; + var algorithmParams = {name: vector.algorithm, outputLength: vector.outputLength}; if (vector.customization !== undefined) { algorithmParams.customization = vector.customization; } @@ -115,7 +115,7 @@ signature.buffer.transfer(); return vector.algorithm; }, - length: vector.length + outputLength: vector.outputLength }; if (vector.customization !== undefined) { algorithmParams.customization = vector.customization; @@ -144,7 +144,7 @@ .then(function(vector) { promise_test(function(test) { var signature = copyBuffer(vector.signature); - var algorithmParams = {name: vector.algorithm, length: vector.length}; + var algorithmParams = {name: vector.algorithm, outputLength: vector.outputLength}; if (vector.customization !== undefined) { algorithmParams.customization = vector.customization; } @@ -175,7 +175,7 @@ var plaintext = copyBuffer(vector.plaintext); plaintext[0] = 255 - plaintext[0]; var algorithmParams = { - length: vector.length, + outputLength: vector.outputLength, get name() { plaintext[0] = vector.plaintext[0]; return vector.algorithm; @@ -208,7 +208,7 @@ .then(function(vector) { promise_test(function(test) { var plaintext = copyBuffer(vector.plaintext); - var algorithmParams = {name: vector.algorithm, length: vector.length}; + var algorithmParams = {name: vector.algorithm, outputLength: vector.outputLength}; if (vector.customization !== undefined) { algorithmParams.customization = vector.customization; } @@ -242,7 +242,7 @@ plaintext.buffer.transfer(); return vector.algorithm; }, - length: vector.length + outputLength: vector.outputLength }; if (vector.customization !== undefined) { algorithmParams.customization = vector.customization; @@ -271,7 +271,7 @@ .then(function(vector) { promise_test(function(test) { var plaintext = copyBuffer(vector.plaintext); - var algorithmParams = {name: vector.algorithm, length: vector.length}; + var algorithmParams = {name: vector.algorithm, outputLength: vector.outputLength}; if (vector.customization !== undefined) { algorithmParams.customization = vector.customization; } @@ -301,7 +301,7 @@ var promise = importVectorKeys(vector, ["sign"]) .then(function(vector) { promise_test(function(test) { - var algorithmParams = {name: vector.algorithm, length: vector.length}; + var algorithmParams = {name: vector.algorithm, outputLength: vector.outputLength}; if (vector.customization !== undefined) { algorithmParams.customization = vector.customization; } @@ -326,7 +326,7 @@ var promise = importVectorKeys(vector, ["verify", "sign"]) .then(function(vectors) { promise_test(function(test) { - var algorithmParams = {name: vector.algorithm, length: vector.length}; + var algorithmParams = {name: vector.algorithm, outputLength: vector.outputLength}; if (vector.customization !== undefined) { algorithmParams.customization = vector.customization; } @@ -363,7 +363,7 @@ return importVectorKeys(vector, ["verify", "sign"]) .then(function(vectors) { promise_test(function(test) { - var algorithmParams = {name: vector.algorithm, length: vector.length}; + var algorithmParams = {name: vector.algorithm, outputLength: vector.outputLength}; if (vector.customization !== undefined) { algorithmParams.customization = vector.customization; } @@ -401,7 +401,7 @@ return importVectorKeys(vector, ["verify", "sign"]) .then(function(vector) { promise_test(function(test) { - var algorithmParams = {name: vector.algorithm, length: vector.length}; + var algorithmParams = {name: vector.algorithm, outputLength: vector.outputLength}; if (vector.customization !== undefined) { algorithmParams.customization = vector.customization; } @@ -438,7 +438,7 @@ var plaintext = copyBuffer(vector.plaintext); plaintext[0] = 255 - plaintext[0]; promise_test(function(test) { - var algorithmParams = {name: vector.algorithm, length: vector.length}; + var algorithmParams = {name: vector.algorithm, outputLength: vector.outputLength}; if (vector.customization !== undefined) { algorithmParams.customization = vector.customization; } @@ -470,7 +470,7 @@ var signature = copyBuffer(vector.signature); signature[0] = 255 - signature[0]; promise_test(function(test) { - var algorithmParams = {name: vector.algorithm, length: vector.length}; + var algorithmParams = {name: vector.algorithm, outputLength: vector.outputLength}; if (vector.customization !== undefined) { algorithmParams.customization = vector.customization; } @@ -501,7 +501,7 @@ .then(function(vector) { var signature = vector.signature.slice(1); // Drop first byte promise_test(function(test) { - var algorithmParams = {name: vector.algorithm, length: vector.length}; + var algorithmParams = {name: vector.algorithm, outputLength: vector.outputLength}; if (vector.customization !== undefined) { algorithmParams.customization = vector.customization; } @@ -531,8 +531,8 @@ var promise = importVectorKeys(vector, ["verify", "sign"]) .then(function(vector) { promise_test(function(test) { - var differentLength = vector.length === 256 ? 512 : 256; - var algorithmParams = {name: vector.algorithm, length: differentLength}; + var differentLength = vector.outputLength === 256 ? 512 : 256; + var algorithmParams = {name: vector.algorithm, outputLength: differentLength}; if (vector.customization !== undefined) { algorithmParams.customization = vector.customization; } @@ -582,34 +582,5 @@ } } - // Returns a copy of the sourceBuffer it is sent. - function copyBuffer(sourceBuffer) { - var source = new Uint8Array(sourceBuffer); - var copy = new Uint8Array(sourceBuffer.byteLength) - - for (var i=0; i<source.byteLength; i++) { - copy[i] = source[i]; - } - - return copy; - } - - function equalBuffers(a, b) { - if (a.byteLength !== b.byteLength) { - return false; - } - - var aBytes = new Uint8Array(a); - var bBytes = new Uint8Array(b); - - for (var i=0; i<a.byteLength; i++) { - if (aBytes[i] !== bBytes[i]) { - return false; - } - } - - return true; - } - return; }
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/kmac.tentative.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/kmac.tentative.https.any.js index a2b5203..3d34c575 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/kmac.tentative.https.any.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/kmac.tentative.https.any.js
@@ -1,4 +1,5 @@ // META: title=WebCryptoAPI: sign() and verify() Using KMAC +// META: script=../util/helpers.js // META: script=kmac_vectors.js // META: script=kmac.js // META: timeout=long
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/kmac_vectors.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/kmac_vectors.js index 39d0efe..6b35cab1 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/kmac_vectors.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/kmac_vectors.js
@@ -6,7 +6,7 @@ // Sample #1 - KMAC128, no customization name: "KMAC128 with no customization", algorithm: "KMAC128", - length: 256, + outputLength: 256, keyBuffer: new Uint8Array([ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, @@ -25,7 +25,7 @@ // Sample #2 - KMAC128, with customization name: "KMAC128 with customization", algorithm: "KMAC128", - length: 256, + outputLength: 256, keyBuffer: new Uint8Array([ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, @@ -47,7 +47,7 @@ // Sample #3 - KMAC128, large data, with customization name: "KMAC128 with large data and customization", algorithm: "KMAC128", - length: 256, + outputLength: 256, keyBuffer: new Uint8Array([ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, @@ -69,7 +69,7 @@ // Sample #4 - KMAC256, with customization, 512-bit output name: "KMAC256 with customization and 512-bit output", algorithm: "KMAC256", - length: 512, + outputLength: 512, keyBuffer: new Uint8Array([ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, @@ -94,7 +94,7 @@ // Sample #5 - KMAC256, large data, no customization, 512-bit output name: "KMAC256 with large data and no customization", algorithm: "KMAC256", - length: 512, + outputLength: 512, keyBuffer: new Uint8Array([ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, @@ -116,7 +116,7 @@ // Sample #6 - KMAC256, large data, with customization, 512-bit output name: "KMAC256 with large data and customization", algorithm: "KMAC256", - length: 512, + outputLength: 512, keyBuffer: new Uint8Array([ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/mldsa.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/mldsa.js index 9c65468..1087927 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/mldsa.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/mldsa.js
@@ -1034,34 +1034,5 @@ return Promise.all([publicPromise, privatePromise]); } - // Returns a copy of the sourceBuffer it is sent. - function copyBuffer(sourceBuffer) { - var source = new Uint8Array(sourceBuffer); - var copy = new Uint8Array(sourceBuffer.byteLength); - - for (var i = 0; i < source.byteLength; i++) { - copy[i] = source[i]; - } - - return copy; - } - - function equalBuffers(a, b) { - if (a.byteLength !== b.byteLength) { - return false; - } - - var aBytes = new Uint8Array(a); - var bBytes = new Uint8Array(b); - - for (var i = 0; i < a.byteLength; i++) { - if (aBytes[i] !== bBytes[i]) { - return false; - } - } - - return true; - } - return; }
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/mldsa.tentative.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/mldsa.tentative.https.any.js index 364e1d3..be336b3 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/mldsa.tentative.https.any.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/mldsa.tentative.https.any.js
@@ -1,4 +1,5 @@ // META: title=WebCryptoAPI: sign() and verify() Using ML-DSA +// META: script=../util/helpers.js // META: script=mldsa_vectors.js // META: script=mldsa.js // META: timeout=long
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/rsa.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/rsa.js index 09c7ceb7..667f5d2 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/rsa.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/rsa.js
@@ -577,34 +577,5 @@ return Promise.all([publicPromise, privatePromise]); } - // Returns a copy of the sourceBuffer it is sent. - function copyBuffer(sourceBuffer) { - var source = new Uint8Array(sourceBuffer); - var copy = new Uint8Array(sourceBuffer.byteLength) - - for (var i=0; i<source.byteLength; i++) { - copy[i] = source[i]; - } - - return copy; - } - - function equalBuffers(a, b) { - if (a.byteLength !== b.byteLength) { - return false; - } - - var aBytes = new Uint8Array(a); - var bBytes = new Uint8Array(b); - - for (var i=0; i<a.byteLength; i++) { - if (aBytes[i] !== bBytes[i]) { - return false; - } - } - - return true; - } - return; }
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/rsa_pkcs.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/rsa_pkcs.https.any.js index d930a71..3e3a8c23 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/rsa_pkcs.https.any.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/rsa_pkcs.https.any.js
@@ -1,4 +1,5 @@ // META: title=WebCryptoAPI: sign() and verify() Using RSASSA-PKCS1-v1_5 +// META: script=../util/helpers.js // META: script=rsa_pkcs_vectors.js // META: script=rsa.js // META: timeout=long
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/rsa_pss.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/rsa_pss.https.any.js index f02ba209..399baba7 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/rsa_pss.https.any.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/rsa_pss.https.any.js
@@ -1,4 +1,5 @@ // META: title=WebCryptoAPI: sign() and verify() Using RSA-PSS +// META: script=../util/helpers.js // META: script=rsa_pss_vectors.js // META: script=rsa.js // META: timeout=long
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/util/helpers.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/util/helpers.js index dbcc5053..3d44b7a 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/util/helpers.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/util/helpers.js
@@ -84,23 +84,6 @@ } else { return obj.toString(); } - - var keyValuePairs = []; - - Object.keys(obj).sort().forEach(function(keyName) { - var value = obj[keyName]; - if (typeof value === "object") { - value = objectToString(value); - } else if (typeof value === "array") { - value = "[" + value.map(function(elem){return objectToString(elem);}).join(", ") + "]"; - } else { - value = value.toString(); - } - - keyValuePairs.push(keyName + ": " + value); - }); - - return "{" + keyValuePairs.join(", ") + "}"; } // Is key a CryptoKey object with correct algorithm, extractable, and usages? @@ -332,3 +315,79 @@ return arrayBuffer; } + +// Compares two ArrayBuffer or ArrayBufferView objects. If bitCount is +// omitted, the two values must be the same length and have the same contents +// in every byte. If bitCount is included, only that leading number of bits +// have to match. +function equalBuffers(a, b, bitCount) { + var remainder; + + if (typeof bitCount === "undefined" && a.byteLength !== b.byteLength) { + return false; + } + + var aBytes = new Uint8Array(a); + var bBytes = new Uint8Array(b); + + var length = a.byteLength; + if (typeof bitCount !== "undefined") { + length = Math.floor(bitCount / 8); + } + + for (var i=0; i<length; i++) { + if (aBytes[i] !== bBytes[i]) { + return false; + } + } + + if (typeof bitCount !== "undefined") { + remainder = bitCount % 8; + return aBytes[length] >> (8 - remainder) === bBytes[length] >> (8 - remainder); + } + + return true; +} + +// Returns a copy of the sourceBuffer it is sent. +function copyBuffer(sourceBuffer) { + var source = new Uint8Array(sourceBuffer); + var copy = new Uint8Array(sourceBuffer.byteLength) + + for (var i=0; i<source.byteLength; i++) { + copy[i] = source[i]; + } + + return copy; +} + +// Are two Jwk objects "the same"? That is, does the object returned include +// matching values for each property that was expected? It's okay if the +// returned object has extra methods; they aren't checked. +function equalJwk(expected, got) { + var fields = Object.keys(expected); + var fieldName; + + for(var i=0; i<fields.length; i++) { + fieldName = fields[i]; + if (!(fieldName in got)) { + return false; + } + if (objectToString(expected[fieldName]) !== objectToString(got[fieldName])) { + return false; + } + } + + return true; +} + +// Jwk format wants Base 64 without the typical padding at the end. +function byteArrayToUnpaddedBase64(byteArray){ + var binaryString = ""; + for (var i=0; i<byteArray.byteLength; i++){ + binaryString += String.fromCharCode(byteArray[i]); + } + var base64String = btoa(binaryString); + + return base64String.replace(/=/g, ""); +}
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/wrapKey_unwrapKey/wrapKey_unwrapKey.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/wrapKey_unwrapKey/wrapKey_unwrapKey.https.any.js index 880f7d6..9fa3bb775 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/wrapKey_unwrapKey/wrapKey_unwrapKey.https.any.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/wrapKey_unwrapKey/wrapKey_unwrapKey.https.any.js
@@ -307,79 +307,6 @@ } } - // Are two array buffers the same? - function equalBuffers(a, b) { - if (a.byteLength !== b.byteLength) { - return false; - } - - var aBytes = new Uint8Array(a); - var bBytes = new Uint8Array(b); - - for (var i=0; i<a.byteLength; i++) { - if (aBytes[i] !== bBytes[i]) { - return false; - } - } - - return true; - } - - // Are two Jwk objects "the same"? That is, does the object returned include - // matching values for each property that was expected? It's okay if the - // returned object has extra methods; they aren't checked. - function equalJwk(expected, got) { - var fields = Object.keys(expected); - var fieldName; - - for(var i=0; i<fields.length; i++) { - fieldName = fields[i]; - if (!(fieldName in got)) { - return false; - } - if (objectToString(expected[fieldName]) !== objectToString(got[fieldName])) { - return false; - } - } - - return true; - } - - // Character representation of any object we may use as a parameter. - function objectToString(obj) { - var keyValuePairs = []; - - if (Array.isArray(obj)) { - return "[" + obj.map(function(elem){return objectToString(elem);}).join(", ") + "]"; - } else if (typeof obj === "object") { - Object.keys(obj).sort().forEach(function(keyName) { - keyValuePairs.push(keyName + ": " + objectToString(obj[keyName])); - }); - return "{" + keyValuePairs.join(", ") + "}"; - } else if (typeof obj === "undefined") { - return "undefined"; - } else { - return obj.toString(); - } - - var keyValuePairs = []; - - Object.keys(obj).sort().forEach(function(keyName) { - var value = obj[keyName]; - if (typeof value === "object") { - value = objectToString(value); - } else if (typeof value === "array") { - value = "[" + value.map(function(elem){return objectToString(elem);}).join(", ") + "]"; - } else { - value = value.toString(); - } - - keyValuePairs.push(keyName + ": " + value); - }); - - return "{" + keyValuePairs.join(", ") + "}"; - } - // Can we compare key values by using them function canCompareNonExtractableKeys(key){ if (key.usages.indexOf("decrypt") !== -1) {
diff --git a/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-disabled-by-feature-policy.https-expected.txt b/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-disabled-by-feature-policy.https-expected.txt deleted file mode 100644 index 2cd00b4..0000000 --- a/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-disabled-by-feature-policy.https-expected.txt +++ /dev/null
@@ -1,15 +0,0 @@ -This is a testharness.js-based test. -[FAIL] Accelerometer: Permissions-Policy header accelerometer=() disallows same-origin iframes. - test_feature_availability is not defined -[FAIL] Accelerometer: Permissions-Policy header accelerometer=() disallows cross-origin iframes. - test_feature_availability is not defined -[FAIL] LinearAccelerationSensor: Permissions-Policy header accelerometer=() disallows same-origin iframes. - test_feature_availability is not defined -[FAIL] LinearAccelerationSensor: Permissions-Policy header accelerometer=() disallows cross-origin iframes. - test_feature_availability is not defined -[FAIL] GravitySensor: Permissions-Policy header accelerometer=() disallows same-origin iframes. - test_feature_availability is not defined -[FAIL] GravitySensor: Permissions-Policy header accelerometer=() disallows cross-origin iframes. - test_feature_availability is not defined -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-disabled-by-feature-policy.https.html b/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-disabled-by-feature-policy.https.html deleted file mode 100644 index c416351..0000000 --- a/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-disabled-by-feature-policy.https.html +++ /dev/null
@@ -1,15 +0,0 @@ -<!DOCTYPE html> -<body> -<title>Accelerometer Permissions Policy Test: Disabled</title> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="/feature-policy/resources/featurepolicy.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> -<script> -"use strict"; - -run_permissions_policy_tests_disabled('Accelerometer'); -run_permissions_policy_tests_disabled('LinearAccelerationSensor'); -run_permissions_policy_tests_disabled('GravitySensor'); -</script> -</body>
diff --git a/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-disabled-by-feature-policy.https.html.headers b/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-disabled-by-feature-policy.https.html.headers deleted file mode 100644 index beea0422..0000000 --- a/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-disabled-by-feature-policy.https.html.headers +++ /dev/null
@@ -1 +0,0 @@ -Feature-Policy: accelerometer 'none'
diff --git a/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-disabled-by-permissions-policy.https.html b/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-disabled-by-permissions-policy.https.html index a30391b0..12ef675f 100644 --- a/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-disabled-by-permissions-policy.https.html +++ b/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-disabled-by-permissions-policy.https.html
@@ -4,7 +4,7 @@ <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="/permissions-policy/resources/permissions-policy.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> +<script src="/generic-sensor/generic-sensor-permissions-policy-test.sub.js"></script> <script> "use strict";
diff --git a/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-enabled-by-feature-policy-attribute-redirect-on-load.https-expected.txt b/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-enabled-by-feature-policy-attribute-redirect-on-load.https-expected.txt deleted file mode 100644 index 324f766..0000000 --- a/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-enabled-by-feature-policy-attribute-redirect-on-load.https-expected.txt +++ /dev/null
@@ -1,15 +0,0 @@ -This is a testharness.js-based test. -[FAIL] Accelerometer: Permissions-Policy allow='accelerometer' attribute allows same-origin relocation - test_feature_availability is not defined -[FAIL] Accelerometer: Permissions-Policy allow='accelerometer' attribute disallows cross-origin relocation - test_feature_availability is not defined -[FAIL] LinearAccelerationSensor: Permissions-Policy allow='accelerometer' attribute allows same-origin relocation - test_feature_availability is not defined -[FAIL] LinearAccelerationSensor: Permissions-Policy allow='accelerometer' attribute disallows cross-origin relocation - test_feature_availability is not defined -[FAIL] GravitySensor: Permissions-Policy allow='accelerometer' attribute allows same-origin relocation - test_feature_availability is not defined -[FAIL] GravitySensor: Permissions-Policy allow='accelerometer' attribute disallows cross-origin relocation - test_feature_availability is not defined -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-enabled-by-feature-policy-attribute-redirect-on-load.https.html b/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-enabled-by-feature-policy-attribute-redirect-on-load.https.html deleted file mode 100644 index 84baf777..0000000 --- a/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-enabled-by-feature-policy-attribute-redirect-on-load.https.html +++ /dev/null
@@ -1,15 +0,0 @@ -<!DOCTYPE html> -<body> -<title>Accelerometer Permissions Policy Test: Enabled by attribute redirect on load</title> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="/feature-policy/resources/featurepolicy.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> -<script> -"use strict"; - -run_permissions_policy_tests_enabled_by_attribute_redirect_on_load('Accelerometer'); -run_permissions_policy_tests_enabled_by_attribute_redirect_on_load('LinearAccelerationSensor'); -run_permissions_policy_tests_enabled_by_attribute_redirect_on_load('GravitySensor'); -</script> -</body>
diff --git a/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-enabled-by-feature-policy-attribute.https-expected.txt b/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-enabled-by-feature-policy-attribute.https-expected.txt deleted file mode 100644 index afe7b978..0000000 --- a/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-enabled-by-feature-policy-attribute.https-expected.txt +++ /dev/null
@@ -1,15 +0,0 @@ -This is a testharness.js-based test. -[FAIL] Accelerometer: Permissions-Policy allow='accelerometer' attribute allows same-origin iframe - test_feature_availability is not defined -[FAIL] Accelerometer: Permissions-Policy allow='accelerometer' attribute allows cross-origin iframe - test_feature_availability is not defined -[FAIL] LinearAccelerationSensor: Permissions-Policy allow='accelerometer' attribute allows same-origin iframe - test_feature_availability is not defined -[FAIL] LinearAccelerationSensor: Permissions-Policy allow='accelerometer' attribute allows cross-origin iframe - test_feature_availability is not defined -[FAIL] GravitySensor: Permissions-Policy allow='accelerometer' attribute allows same-origin iframe - test_feature_availability is not defined -[FAIL] GravitySensor: Permissions-Policy allow='accelerometer' attribute allows cross-origin iframe - test_feature_availability is not defined -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-enabled-by-feature-policy-attribute.https.html b/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-enabled-by-feature-policy-attribute.https.html deleted file mode 100644 index ba7d64a..0000000 --- a/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-enabled-by-feature-policy-attribute.https.html +++ /dev/null
@@ -1,15 +0,0 @@ -<!DOCTYPE html> -<body> -<title>Accelerometer Permissions Policy Test: Enabled by attribute</title> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="/feature-policy/resources/featurepolicy.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> -<script> -"use strict"; - -run_permissions_policy_tests_enabled_by_attribute('Accelerometer'); -run_permissions_policy_tests_enabled_by_attribute('LinearAccelerationSensor'); -run_permissions_policy_tests_enabled_by_attribute('GravitySensor'); -</script> -</body>
diff --git a/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-enabled-by-feature-policy.https-expected.txt b/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-enabled-by-feature-policy.https-expected.txt deleted file mode 100644 index 27737bd..0000000 --- a/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-enabled-by-feature-policy.https-expected.txt +++ /dev/null
@@ -1,15 +0,0 @@ -This is a testharness.js-based test. -[FAIL] Accelerometer: Permissions-Policy header accelerometer=* allows same-origin iframes. - test_feature_availability is not defined -[FAIL] Accelerometer: Permissions-Policy header accelerometer=* allows cross-origin iframes. - test_feature_availability is not defined -[FAIL] LinearAccelerationSensor: Permissions-Policy header accelerometer=* allows same-origin iframes. - test_feature_availability is not defined -[FAIL] LinearAccelerationSensor: Permissions-Policy header accelerometer=* allows cross-origin iframes. - test_feature_availability is not defined -[FAIL] GravitySensor: Permissions-Policy header accelerometer=* allows same-origin iframes. - test_feature_availability is not defined -[FAIL] GravitySensor: Permissions-Policy header accelerometer=* allows cross-origin iframes. - test_feature_availability is not defined -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-enabled-by-feature-policy.https.html b/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-enabled-by-feature-policy.https.html deleted file mode 100644 index 10d2c25..0000000 --- a/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-enabled-by-feature-policy.https.html +++ /dev/null
@@ -1,15 +0,0 @@ -<!DOCTYPE html> -<body> -<title>Accelerometer Permissions Policy Test: Enabled</title> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="/feature-policy/resources/featurepolicy.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> -<script> -"use strict"; - -run_permissions_policy_tests_enabled('Accelerometer'); -run_permissions_policy_tests_enabled('LinearAccelerationSensor'); -run_permissions_policy_tests_enabled('GravitySensor'); -</script> -</body>
diff --git a/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-enabled-by-feature-policy.https.html.headers b/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-enabled-by-feature-policy.https.html.headers deleted file mode 100644 index 5df2754..0000000 --- a/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-enabled-by-feature-policy.https.html.headers +++ /dev/null
@@ -1 +0,0 @@ -Feature-Policy: accelerometer *
diff --git a/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-enabled-by-permissions-policy-attribute-redirect-on-load.https.html b/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-enabled-by-permissions-policy-attribute-redirect-on-load.https.html index 1cffdd6..54762a1 100644 --- a/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-enabled-by-permissions-policy-attribute-redirect-on-load.https.html +++ b/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-enabled-by-permissions-policy-attribute-redirect-on-load.https.html
@@ -4,7 +4,7 @@ <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="/permissions-policy/resources/permissions-policy.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> +<script src="/generic-sensor/generic-sensor-permissions-policy-test.sub.js"></script> <script> "use strict";
diff --git a/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-enabled-by-permissions-policy-attribute.https.html b/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-enabled-by-permissions-policy-attribute.https.html index 8dae3b7..93b6f95 100644 --- a/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-enabled-by-permissions-policy-attribute.https.html +++ b/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-enabled-by-permissions-policy-attribute.https.html
@@ -4,7 +4,7 @@ <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="/permissions-policy/resources/permissions-policy.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> +<script src="/generic-sensor/generic-sensor-permissions-policy-test.sub.js"></script> <script> "use strict";
diff --git a/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-enabled-by-permissions-policy.https.html b/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-enabled-by-permissions-policy.https.html index 9c6c2217..9ef257c 100644 --- a/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-enabled-by-permissions-policy.https.html +++ b/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-enabled-by-permissions-policy.https.html
@@ -4,7 +4,7 @@ <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="/permissions-policy/resources/permissions-policy.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> +<script src="/generic-sensor/generic-sensor-permissions-policy-test.sub.js"></script> <script> "use strict";
diff --git a/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-enabled-on-self-origin-by-feature-policy.https-expected.txt b/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-enabled-on-self-origin-by-feature-policy.https-expected.txt deleted file mode 100644 index 9114c3a..0000000 --- a/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-enabled-on-self-origin-by-feature-policy.https-expected.txt +++ /dev/null
@@ -1,15 +0,0 @@ -This is a testharness.js-based test. -[FAIL] Accelerometer: Permissions-Policy header accelerometer=(self) allows same-origin iframes. - test_feature_availability is not defined -[FAIL] Accelerometer: Permissions-Policy header accelerometer=(self) disallows cross-origin iframes. - test_feature_availability is not defined -[FAIL] LinearAccelerationSensor: Permissions-Policy header accelerometer=(self) allows same-origin iframes. - test_feature_availability is not defined -[FAIL] LinearAccelerationSensor: Permissions-Policy header accelerometer=(self) disallows cross-origin iframes. - test_feature_availability is not defined -[FAIL] GravitySensor: Permissions-Policy header accelerometer=(self) allows same-origin iframes. - test_feature_availability is not defined -[FAIL] GravitySensor: Permissions-Policy header accelerometer=(self) disallows cross-origin iframes. - test_feature_availability is not defined -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-enabled-on-self-origin-by-feature-policy.https.html b/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-enabled-on-self-origin-by-feature-policy.https.html deleted file mode 100644 index 592f1f07..0000000 --- a/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-enabled-on-self-origin-by-feature-policy.https.html +++ /dev/null
@@ -1,15 +0,0 @@ -<!DOCTYPE html> -<body> -<title>Accelerometer Permissions Policy Test: Enabled on self origin</title> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="/feature-policy/resources/featurepolicy.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> -<script> -"use strict"; - -run_permissions_policy_tests_enabled_on_self_origin('Accelerometer'); -run_permissions_policy_tests_enabled_on_self_origin('LinearAccelerationSensor'); -run_permissions_policy_tests_enabled_on_self_origin('GravitySensor'); -</script> -</body>
diff --git a/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-enabled-on-self-origin-by-feature-policy.https.html.headers b/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-enabled-on-self-origin-by-feature-policy.https.html.headers deleted file mode 100644 index cdefed8..0000000 --- a/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-enabled-on-self-origin-by-feature-policy.https.html.headers +++ /dev/null
@@ -1 +0,0 @@ -Feature-Policy: accelerometer 'self'
diff --git a/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-enabled-on-self-origin-by-permissions-policy.https.html b/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-enabled-on-self-origin-by-permissions-policy.https.html index ef9545f..1d4fc38d 100644 --- a/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-enabled-on-self-origin-by-permissions-policy.https.html +++ b/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-enabled-on-self-origin-by-permissions-policy.https.html
@@ -4,7 +4,7 @@ <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="/permissions-policy/resources/permissions-policy.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> +<script src="/generic-sensor/generic-sensor-permissions-policy-test.sub.js"></script> <script> "use strict";
diff --git a/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-iframe-access.https.html b/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-iframe-access.https.html index 887c6139..d5aa381c 100644 --- a/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-iframe-access.https.html +++ b/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-iframe-access.https.html
@@ -10,7 +10,7 @@ <script src="/resources/testdriver-vendor.js"></script> <script src="/generic-sensor/resources/generic-sensor-helpers.js"></script> <script src="/generic-sensor/generic-sensor-iframe-tests.sub.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> +<script src="/generic-sensor/generic-sensor-permissions-policy-test.sub.js"></script> <script src="resources/sensor-data.js"></script> <div id="log"></div> <script>
diff --git a/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-supported-by-feature-policy.html b/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-supported-by-feature-policy.html deleted file mode 100644 index 8e09c7ac..0000000 --- a/third_party/blink/web_tests/external/wpt/accelerometer/Accelerometer-supported-by-feature-policy.html +++ /dev/null
@@ -1,11 +0,0 @@ -<!DOCTYPE html> -<title>Test that accelerometer is advertised in the feature list</title> -<link rel="help" href="https://w3c.github.io/webappsec-feature-policy/#dom-featurepolicy-features"> -<link rel="help" href="https://w3c.github.io/sensors/#feature-policy-api"> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script> -test(() => { - assert_in_array('accelerometer', document.featurePolicy.features()); -}, 'document.featurePolicy.features should advertise accelerometer.'); -</script>
diff --git a/third_party/blink/web_tests/external/wpt/accelerometer/resources/sensor-data.js b/third_party/blink/web_tests/external/wpt/accelerometer/resources/sensor-data.js index 6f56cfdb..ca47d69 100644 --- a/third_party/blink/web_tests/external/wpt/accelerometer/resources/sensor-data.js +++ b/third_party/blink/web_tests/external/wpt/accelerometer/resources/sensor-data.js
@@ -4,21 +4,21 @@ sensorName: 'Accelerometer', permissionName: 'accelerometer', testDriverName: 'accelerometer', - featurePolicyNames: ['accelerometer'] + permissionsPolicyNames: ['accelerometer'] }; const kGravitySensorData = { sensorName: 'GravitySensor', permissionName: 'accelerometer', testDriverName: 'gravity', - featurePolicyNames: ['accelerometer'] + permissionsPolicyNames: ['accelerometer'] }; const kLinearAccelerationSensorData = { sensorName: 'LinearAccelerationSensor', permissionName: 'accelerometer', testDriverName: 'linear-acceleration', - featurePolicyNames: ['accelerometer'] + permissionsPolicyNames: ['accelerometer'] }; const kAccelerometerReadings = {
diff --git a/third_party/blink/web_tests/external/wpt/ai/language-model/language-model-prompt-empty-input.tentative.https.window.js b/third_party/blink/web_tests/external/wpt/ai/language-model/language-model-prompt-empty-input.tentative.https.window.js new file mode 100644 index 0000000..7cd8246 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/ai/language-model/language-model-prompt-empty-input.tentative.https.window.js
@@ -0,0 +1,53 @@ +// META: title=Language Model Prompt Empty Input +// META: script=/resources/testdriver.js +// META: script=/resources/testdriver-vendor.js +// META: script=../resources/util.js +// META: timeout=long + +'use strict'; + +promise_test(async (t) => { + await ensureLanguageModel(); + const model = await createLanguageModel(); + + // null and undefined are coerced to the strings "null" and "undefined" by the + // IDL bindings. + assert_regexp_match(await model.prompt(null), /null/); + assert_regexp_match(await model.prompt(undefined), /undefined/); + + // Empty string is allowed even when context is empty. + assert_equals(typeof await model.prompt(""), "string"); + + // Empty sequence [] is allowed even when context is empty. + assert_equals(typeof await model.prompt([]), "string"); + + // Nested empty content sequence is allowed. + assert_equals(typeof await model.prompt([{ role: 'user', content: [] }]), "string"); + + // Nested structured message with empty text is allowed. + assert_equals(typeof await model.prompt([{ role: 'user', content: [{ type: 'text', value: '' }] }]), "string"); +}, "LanguageModel.prompt() allows empty or coerced inputs"); + +promise_test(async (t) => { + await ensureLanguageModel(); + const model = await createLanguageModel(); + + assert_equals(await model.append(null), undefined); + assert_equals(await model.append(undefined), undefined); + assert_equals(await model.append(""), undefined); + assert_equals(await model.append([]), undefined); + assert_equals(await model.append([{ role: 'user', content: [] }]), undefined); + assert_equals(await model.append([{ role: 'user', content: [{ type: 'text', value: '' }] }]), undefined); +}, "LanguageModel.append() allows empty or coerced inputs"); + +promise_test(async (t) => { + await ensureLanguageModel(); + const model = await createLanguageModel(); + + assert_true(model.promptStreaming(null) instanceof ReadableStream); + assert_true(model.promptStreaming(undefined) instanceof ReadableStream); + assert_true(model.promptStreaming("") instanceof ReadableStream); + assert_true(model.promptStreaming([]) instanceof ReadableStream); + assert_true(model.promptStreaming([{ role: 'user', content: [] }]) instanceof ReadableStream); + assert_true(model.promptStreaming([{ role: 'user', content: [{ type: 'text', value: '' }] }]) instanceof ReadableStream); +}, "LanguageModel.promptStreaming() allows empty or coerced inputs");
diff --git a/third_party/blink/web_tests/external/wpt/ai/language-model/language-model-prompt.tentative.https.window.js b/third_party/blink/web_tests/external/wpt/ai/language-model/language-model-prompt.tentative.https.window.js index c102d3f..86b0302 100644 --- a/third_party/blink/web_tests/external/wpt/ai/language-model/language-model-prompt.tentative.https.window.js +++ b/third_party/blink/web_tests/external/wpt/ai/language-model/language-model-prompt.tentative.https.window.js
@@ -29,7 +29,6 @@ promise_test(async (t) => { await ensureLanguageModel(); const session = await createLanguageModel(); - assert_true(!!(await session.prompt([]))); // Invalid input should be stringified. assert_regexp_match(await session.prompt({}), /\[object Object\]/); }, 'Check empty Object input');
diff --git a/third_party/blink/web_tests/external/wpt/ambient-light/AmbientLightSensor-disabled-by-permissions-policy.https.html b/third_party/blink/web_tests/external/wpt/ambient-light/AmbientLightSensor-disabled-by-permissions-policy.https.html index 6e27c59..71af5aa6 100644 --- a/third_party/blink/web_tests/external/wpt/ambient-light/AmbientLightSensor-disabled-by-permissions-policy.https.html +++ b/third_party/blink/web_tests/external/wpt/ambient-light/AmbientLightSensor-disabled-by-permissions-policy.https.html
@@ -4,7 +4,7 @@ <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="/permissions-policy/resources/permissions-policy.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> +<script src="/generic-sensor/generic-sensor-permissions-policy-test.sub.js"></script> <script> "use strict";
diff --git a/third_party/blink/web_tests/external/wpt/ambient-light/AmbientLightSensor-enabled-by-permissions-policy-attribute-redirect-on-load.https.html b/third_party/blink/web_tests/external/wpt/ambient-light/AmbientLightSensor-enabled-by-permissions-policy-attribute-redirect-on-load.https.html index ca259ac..d6fc325 100644 --- a/third_party/blink/web_tests/external/wpt/ambient-light/AmbientLightSensor-enabled-by-permissions-policy-attribute-redirect-on-load.https.html +++ b/third_party/blink/web_tests/external/wpt/ambient-light/AmbientLightSensor-enabled-by-permissions-policy-attribute-redirect-on-load.https.html
@@ -4,7 +4,7 @@ <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="/permissions-policy/resources/permissions-policy.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> +<script src="/generic-sensor/generic-sensor-permissions-policy-test.sub.js"></script> <script> "use strict";
diff --git a/third_party/blink/web_tests/external/wpt/ambient-light/AmbientLightSensor-enabled-by-permissions-policy-attribute.https.html b/third_party/blink/web_tests/external/wpt/ambient-light/AmbientLightSensor-enabled-by-permissions-policy-attribute.https.html index 4ecbe4c..19be7aa2 100644 --- a/third_party/blink/web_tests/external/wpt/ambient-light/AmbientLightSensor-enabled-by-permissions-policy-attribute.https.html +++ b/third_party/blink/web_tests/external/wpt/ambient-light/AmbientLightSensor-enabled-by-permissions-policy-attribute.https.html
@@ -4,7 +4,7 @@ <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="/permissions-policy/resources/permissions-policy.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> +<script src="/generic-sensor/generic-sensor-permissions-policy-test.sub.js"></script> <script> "use strict";
diff --git a/third_party/blink/web_tests/external/wpt/ambient-light/AmbientLightSensor-enabled-by-permissions-policy.https.html b/third_party/blink/web_tests/external/wpt/ambient-light/AmbientLightSensor-enabled-by-permissions-policy.https.html index d7539e5..2314be2c 100644 --- a/third_party/blink/web_tests/external/wpt/ambient-light/AmbientLightSensor-enabled-by-permissions-policy.https.html +++ b/third_party/blink/web_tests/external/wpt/ambient-light/AmbientLightSensor-enabled-by-permissions-policy.https.html
@@ -4,7 +4,7 @@ <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="/permissions-policy/resources/permissions-policy.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> +<script src="/generic-sensor/generic-sensor-permissions-policy-test.sub.js"></script> <script> "use strict";
diff --git a/third_party/blink/web_tests/external/wpt/ambient-light/AmbientLightSensor-enabled-on-self-origin-by-permissions-policy.https.html b/third_party/blink/web_tests/external/wpt/ambient-light/AmbientLightSensor-enabled-on-self-origin-by-permissions-policy.https.html index bcaeb56..8982076f0 100644 --- a/third_party/blink/web_tests/external/wpt/ambient-light/AmbientLightSensor-enabled-on-self-origin-by-permissions-policy.https.html +++ b/third_party/blink/web_tests/external/wpt/ambient-light/AmbientLightSensor-enabled-on-self-origin-by-permissions-policy.https.html
@@ -4,7 +4,7 @@ <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="/permissions-policy/resources/permissions-policy.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> +<script src="/generic-sensor/generic-sensor-permissions-policy-test.sub.js"></script> <script> "use strict";
diff --git a/third_party/blink/web_tests/external/wpt/ambient-light/AmbientLightSensor-iframe-access.https.html b/third_party/blink/web_tests/external/wpt/ambient-light/AmbientLightSensor-iframe-access.https.html index c45804a..21970281 100644 --- a/third_party/blink/web_tests/external/wpt/ambient-light/AmbientLightSensor-iframe-access.https.html +++ b/third_party/blink/web_tests/external/wpt/ambient-light/AmbientLightSensor-iframe-access.https.html
@@ -9,7 +9,7 @@ <script src="/resources/testdriver-vendor.js"></script> <script src="/generic-sensor/resources/generic-sensor-helpers.js"></script> <script src="/generic-sensor/generic-sensor-iframe-tests.sub.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> +<script src="/generic-sensor/generic-sensor-permissions-policy-test.sub.js"></script> <script src="resources/sensor-data.js"></script> <div id="log"></div> <script>
diff --git a/third_party/blink/web_tests/external/wpt/ambient-light/resources/sensor-data.js b/third_party/blink/web_tests/external/wpt/ambient-light/resources/sensor-data.js index c1f7bd5..ef91018 100644 --- a/third_party/blink/web_tests/external/wpt/ambient-light/resources/sensor-data.js +++ b/third_party/blink/web_tests/external/wpt/ambient-light/resources/sensor-data.js
@@ -4,7 +4,7 @@ sensorName: 'AmbientLightSensor', permissionName: 'ambient-light-sensor', testDriverName: 'ambient-light', - featurePolicyNames: ['ambient-light-sensor'] + permissionsPolicyNames: ['ambient-light-sensor'] }; const kReadings = {
diff --git a/third_party/blink/web_tests/external/wpt/client-hints/accept-ch-stickiness/cross-origin-subresource-with-feature-policy.https.html b/third_party/blink/web_tests/external/wpt/client-hints/accept-ch-stickiness/cross-origin-subresource-with-permissions-policy.https.html similarity index 85% rename from third_party/blink/web_tests/external/wpt/client-hints/accept-ch-stickiness/cross-origin-subresource-with-feature-policy.https.html rename to third_party/blink/web_tests/external/wpt/client-hints/accept-ch-stickiness/cross-origin-subresource-with-permissions-policy.https.html index 3108c23..4e1ab9e 100644 --- a/third_party/blink/web_tests/external/wpt/client-hints/accept-ch-stickiness/cross-origin-subresource-with-feature-policy.https.html +++ b/third_party/blink/web_tests/external/wpt/client-hints/accept-ch-stickiness/cross-origin-subresource-with-permissions-policy.https.html
@@ -11,7 +11,7 @@ run_test({ name: "cross origin subresources authorized by FP gets it own resources", initial_url: echo, accept_url: accept, - expect_url: "resources/feature-policy-with-cross-origin-subresource.html", + expect_url: "resources/permissions-policy-with-cross-origin-subresource.html", type: "navigation" }); </script> </body>
diff --git a/third_party/blink/web_tests/external/wpt/client-hints/accept-ch-stickiness/resources/feature-policy-with-cross-origin-subresource.html b/third_party/blink/web_tests/external/wpt/client-hints/accept-ch-stickiness/resources/permissions-policy-with-cross-origin-subresource.html similarity index 100% rename from third_party/blink/web_tests/external/wpt/client-hints/accept-ch-stickiness/resources/feature-policy-with-cross-origin-subresource.html rename to third_party/blink/web_tests/external/wpt/client-hints/accept-ch-stickiness/resources/permissions-policy-with-cross-origin-subresource.html
diff --git a/third_party/blink/web_tests/external/wpt/client-hints/accept-ch-stickiness/resources/feature-policy-with-cross-origin-subresource.html.headers b/third_party/blink/web_tests/external/wpt/client-hints/accept-ch-stickiness/resources/permissions-policy-with-cross-origin-subresource.html.headers similarity index 100% rename from third_party/blink/web_tests/external/wpt/client-hints/accept-ch-stickiness/resources/feature-policy-with-cross-origin-subresource.html.headers rename to third_party/blink/web_tests/external/wpt/client-hints/accept-ch-stickiness/resources/permissions-policy-with-cross-origin-subresource.html.headers
diff --git a/third_party/blink/web_tests/external/wpt/client-hints/accept-ch/feature-policy-navigation/__dir__.headers b/third_party/blink/web_tests/external/wpt/client-hints/accept-ch/permissions-policy-navigation/__dir__.headers similarity index 100% rename from third_party/blink/web_tests/external/wpt/client-hints/accept-ch/feature-policy-navigation/__dir__.headers rename to third_party/blink/web_tests/external/wpt/client-hints/accept-ch/permissions-policy-navigation/__dir__.headers
diff --git a/third_party/blink/web_tests/external/wpt/client-hints/accept-ch/permissions-policy-navigation/no-permissions-policy.https-expected.txt b/third_party/blink/web_tests/external/wpt/client-hints/accept-ch/permissions-policy-navigation/no-permissions-policy.https-expected.txt new file mode 100644 index 0000000..7d1ab53 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/client-hints/accept-ch/permissions-policy-navigation/no-permissions-policy.https-expected.txt
@@ -0,0 +1,4 @@ +This is a testharness.js-based test. +Harness Error. harness_status.status = 1 , harness_status.message = Unhandled rejection: test_frame is not defined +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/client-hints/accept-ch/feature-policy-navigation/no-feature-policy.https.html b/third_party/blink/web_tests/external/wpt/client-hints/accept-ch/permissions-policy-navigation/no-permissions-policy.https.html similarity index 92% rename from third_party/blink/web_tests/external/wpt/client-hints/accept-ch/feature-policy-navigation/no-feature-policy.https.html rename to third_party/blink/web_tests/external/wpt/client-hints/accept-ch/permissions-policy-navigation/no-permissions-policy.https.html index 02458f31..333b2560 100644 --- a/third_party/blink/web_tests/external/wpt/client-hints/accept-ch/feature-policy-navigation/no-feature-policy.https.html +++ b/third_party/blink/web_tests/external/wpt/client-hints/accept-ch/permissions-policy-navigation/no-permissions-policy.https.html
@@ -4,7 +4,7 @@ <script src="/resources/testharnessreport.js"></script> <script src="/common/get-host-info.sub.js"></script> <script src="/client-hints/resources/export.js"></script> -<script src="/client-hints/resources/feature-policy-navigation.js"></script> +<script src="/client-hints/resources/permissions-policy-navigation.js"></script> <script> (async () => { await test_frame(
diff --git a/third_party/blink/web_tests/external/wpt/client-hints/accept-ch/permissions-policy-navigation/permissions-policy.https-expected.txt b/third_party/blink/web_tests/external/wpt/client-hints/accept-ch/permissions-policy-navigation/permissions-policy.https-expected.txt new file mode 100644 index 0000000..7d1ab53 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/client-hints/accept-ch/permissions-policy-navigation/permissions-policy.https-expected.txt
@@ -0,0 +1,4 @@ +This is a testharness.js-based test. +Harness Error. harness_status.status = 1 , harness_status.message = Unhandled rejection: test_frame is not defined +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/client-hints/accept-ch/feature-policy-navigation/feature-policy.https.html b/third_party/blink/web_tests/external/wpt/client-hints/accept-ch/permissions-policy-navigation/permissions-policy.https.html similarity index 90% rename from third_party/blink/web_tests/external/wpt/client-hints/accept-ch/feature-policy-navigation/feature-policy.https.html rename to third_party/blink/web_tests/external/wpt/client-hints/accept-ch/permissions-policy-navigation/permissions-policy.https.html index 90a2728..41510b6 100644 --- a/third_party/blink/web_tests/external/wpt/client-hints/accept-ch/feature-policy-navigation/feature-policy.https.html +++ b/third_party/blink/web_tests/external/wpt/client-hints/accept-ch/permissions-policy-navigation/permissions-policy.https.html
@@ -4,7 +4,7 @@ <script src="/resources/testharnessreport.js"></script> <script src="/common/get-host-info.sub.js"></script> <script src="/client-hints/resources/export.js"></script> -<script src="/client-hints/resources/feature-policy-navigation.js"></script> +<script src="/client-hints/resources/permissions-policy-navigation.js"></script> <script> (async () => { await test_frame(
diff --git a/third_party/blink/web_tests/external/wpt/client-hints/accept-ch/feature-policy-navigation/feature-policy.https.html.headers b/third_party/blink/web_tests/external/wpt/client-hints/accept-ch/permissions-policy-navigation/permissions-policy.https.html.headers similarity index 100% rename from third_party/blink/web_tests/external/wpt/client-hints/accept-ch/feature-policy-navigation/feature-policy.https.html.headers rename to third_party/blink/web_tests/external/wpt/client-hints/accept-ch/permissions-policy-navigation/permissions-policy.https.html.headers
diff --git a/third_party/blink/web_tests/external/wpt/client-hints/accept-ch/permissions-policy.sub.https-expected.txt b/third_party/blink/web_tests/external/wpt/client-hints/accept-ch/permissions-policy.sub.https-expected.txt new file mode 100644 index 0000000..b323165 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/client-hints/accept-ch/permissions-policy.sub.https-expected.txt
@@ -0,0 +1,7 @@ +This is a testharness.js-based test. +[FAIL] Accept-CH header test + assert_false: dpr-received expected false got true +[FAIL] Cross-Origin Accept-CH header test + assert_true: device-memory-received expected true got false +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/client-hints/accept-ch/feature-policy.sub.https.html b/third_party/blink/web_tests/external/wpt/client-hints/accept-ch/permissions-policy.sub.https.html similarity index 96% rename from third_party/blink/web_tests/external/wpt/client-hints/accept-ch/feature-policy.sub.https.html rename to third_party/blink/web_tests/external/wpt/client-hints/accept-ch/permissions-policy.sub.https.html index 8f9be9fd..1597b19 100644 --- a/third_party/blink/web_tests/external/wpt/client-hints/accept-ch/feature-policy.sub.https.html +++ b/third_party/blink/web_tests/external/wpt/client-hints/accept-ch/permissions-policy.sub.https.html
@@ -19,7 +19,7 @@ return fetch(get_host_info()["HTTPS_ORIGIN"] + "/client-hints/resources/echo-client-hints-received.py").then(r => { assert_equals(r.status, 200) // Verify that the browser includes client hints in the headers for a - // same-origin fetch which not specifically excluded via Feature-Policy. + // same-origin fetch which not specifically excluded via Permissions-Policy. assert_true(r.headers.has("device-memory-received"), "device-memory-received"); assert_true(r.headers.has("device-memory-deprecated-received"), "device-memory-deprecated-received"); assert_false(r.headers.has("dpr-received"), "dpr-received"); @@ -54,7 +54,7 @@ return fetch(get_host_info()["HTTPS_REMOTE_ORIGIN"] + "/client-hints/resources/echo-client-hints-received.py").then(r => { assert_equals(r.status, 200) // Verify that the browser includes client hints in the headers for a - // cross-origin fetch which are specifically requested via Feature-Policy. + // cross-origin fetch which are specifically requested via Permissions-Policy. assert_true(r.headers.has("device-memory-received"), "device-memory-received"); assert_true(r.headers.has("device-memory-deprecated-received"), "device-memory-deprecated-received"); assert_false(r.headers.has("dpr-received"), "dpr-received");
diff --git a/third_party/blink/web_tests/external/wpt/client-hints/http-equiv-accept-ch-iframe.https-expected.txt b/third_party/blink/web_tests/external/wpt/client-hints/http-equiv-accept-ch-iframe.https-expected.txt new file mode 100644 index 0000000..7d1ab53 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/client-hints/http-equiv-accept-ch-iframe.https-expected.txt
@@ -0,0 +1,4 @@ +This is a testharness.js-based test. +Harness Error. harness_status.status = 1 , harness_status.message = Unhandled rejection: test_frame is not defined +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/client-hints/http-equiv-accept-ch-iframe.https.html b/third_party/blink/web_tests/external/wpt/client-hints/http-equiv-accept-ch-iframe.https.html index 4bde8eb..bcd1c2b 100644 --- a/third_party/blink/web_tests/external/wpt/client-hints/http-equiv-accept-ch-iframe.https.html +++ b/third_party/blink/web_tests/external/wpt/client-hints/http-equiv-accept-ch-iframe.https.html
@@ -6,7 +6,7 @@ <script src="/resources/testharnessreport.js"></script> <script src="/common/get-host-info.sub.js"></script> <script src="/client-hints/resources/export.js"></script> -<script src="resources/feature-policy-navigation.js"></script> +<script src="resources/permissions-policy-navigation.js"></script> <script> (async () => { await test_frame(
diff --git a/third_party/blink/web_tests/external/wpt/client-hints/meta-equiv-delegate-ch-iframe.https-expected.txt b/third_party/blink/web_tests/external/wpt/client-hints/meta-equiv-delegate-ch-iframe.https-expected.txt new file mode 100644 index 0000000..7d1ab53 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/client-hints/meta-equiv-delegate-ch-iframe.https-expected.txt
@@ -0,0 +1,4 @@ +This is a testharness.js-based test. +Harness Error. harness_status.status = 1 , harness_status.message = Unhandled rejection: test_frame is not defined +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/client-hints/meta-equiv-delegate-ch-iframe.https.html b/third_party/blink/web_tests/external/wpt/client-hints/meta-equiv-delegate-ch-iframe.https.html index 2ce9c63c..994d63853 100644 --- a/third_party/blink/web_tests/external/wpt/client-hints/meta-equiv-delegate-ch-iframe.https.html +++ b/third_party/blink/web_tests/external/wpt/client-hints/meta-equiv-delegate-ch-iframe.https.html
@@ -7,7 +7,7 @@ <script src="/resources/testharnessreport.js"></script> <script src="/common/get-host-info.sub.js"></script> <script src="/client-hints/resources/export.js"></script> -<script src="resources/feature-policy-navigation.js"></script> +<script src="resources/permissions-policy-navigation.js"></script> <script> (async () => { await test_frame(
diff --git a/third_party/blink/web_tests/external/wpt/compute-pressure/permissions-policy/compute-pressure-supported-by-permissions-policy-expected.txt b/third_party/blink/web_tests/external/wpt/compute-pressure/permissions-policy/compute-pressure-supported-by-permissions-policy-expected.txt new file mode 100644 index 0000000..a9f22b3b --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/compute-pressure/permissions-policy/compute-pressure-supported-by-permissions-policy-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] document.permissionsPolicy.features should advertise compute-pressure. + Cannot read properties of undefined (reading 'features') +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/compute-pressure/permissions-policy/compute-pressure-supported-by-permissions-policy.html b/third_party/blink/web_tests/external/wpt/compute-pressure/permissions-policy/compute-pressure-supported-by-permissions-policy.html index 35f09b7b..034b093 100644 --- a/third_party/blink/web_tests/external/wpt/compute-pressure/permissions-policy/compute-pressure-supported-by-permissions-policy.html +++ b/third_party/blink/web_tests/external/wpt/compute-pressure/permissions-policy/compute-pressure-supported-by-permissions-policy.html
@@ -6,6 +6,6 @@ <script src="/resources/testharnessreport.js"></script> <script> test(() => { - assert_in_array('compute-pressure', document.featurePolicy.features()); -}, 'document.featurePolicy.features should advertise compute-pressure.'); + assert_in_array('compute-pressure', document.permissionsPolicy.features()); +}, 'document.permissionsPolicy.features should advertise compute-pressure.'); </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-clip/clip-text-inline-block-child-ref.html b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-clip/clip-text-inline-block-child-ref.html new file mode 100644 index 0000000..14150147 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-clip/clip-text-inline-block-child-ref.html
@@ -0,0 +1,12 @@ +<!DOCTYPE html> +<link rel="stylesheet" href="/fonts/ahem.css"> +<style> +.clip { + font: 50px/1 Ahem; + color: green; +} +.inline-block { + display: inline-block; +} +</style> +<div class="clip">XXXXX<span class="inline-block">XXXXX</span></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-clip/clip-text-inline-block-child.html b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-clip/clip-text-inline-block-child.html new file mode 100644 index 0000000..4af572ce --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-clip/clip-text-inline-block-child.html
@@ -0,0 +1,19 @@ +<!DOCTYPE html> +<title>background-clip:text with display:inline-block child</title> +<link rel="help" href="https://drafts.csswg.org/css-backgrounds-4/#valdef-background-clip-text"> +<link rel="match" href="clip-text-inline-block-child-ref.html"> +<link rel="stylesheet" href="/fonts/ahem.css"> + +<style> +.clip { + font: 50px/1 Ahem; + color: transparent; + background-color: green; + background-clip: text; +} +.inline-block { + display: inline-block; +} +</style> +<!-- Test passes if there is a 10-character green text. --> +<div class="clip">XXXXX<span class="inline-block">XXXXX</span></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-clip/clip-text-relative-child-ref.html b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-clip/clip-text-relative-child-ref.html new file mode 100644 index 0000000..f949d81 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-clip/clip-text-relative-child-ref.html
@@ -0,0 +1,12 @@ +<!DOCTYPE html> +<link rel="stylesheet" href="/fonts/ahem.css"> +<style> +.clip { + font: 50px/1 Ahem; + color: green; +} +.relative { + position: relative; +} +</style> +<div class="clip">XXXXX<span class="relative">XXXXX</span></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-clip/clip-text-relative-child.html b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-clip/clip-text-relative-child.html new file mode 100644 index 0000000..87e67be --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-clip/clip-text-relative-child.html
@@ -0,0 +1,19 @@ +<!DOCTYPE html> +<title>background-clip:text with position:relative child</title> +<link rel="help" href="https://drafts.csswg.org/css-backgrounds-4/#valdef-background-clip-text"> +<link rel="match" href="clip-text-relative-child-ref.html"> +<link rel="stylesheet" href="/fonts/ahem.css"> + +<style> +.clip { + font: 50px/1 Ahem; + color: transparent; + background-color: green; + background-clip: text; +} +.relative { + position: relative; +} +</style> +<!-- Test passes if there is a 10-character green text. --> +<div class="clip">XXXXX<span class="relative">XXXXX</span></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-clip/clip-text-stacking-context-child-ref.html b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-clip/clip-text-stacking-context-child-ref.html new file mode 100644 index 0000000..18a1693 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-clip/clip-text-stacking-context-child-ref.html
@@ -0,0 +1,12 @@ +<!DOCTYPE html> +<link rel="stylesheet" href="/fonts/ahem.css"> +<style> +.clip { + font: 50px/1 Ahem; + color: green; +} +</style> +<div class="clip">XXXXX<div style="opacity: 0.99">XXXXX</div></div> +<div class="clip">XXXXX<div style="transform: translateX(0)">XXXXX</div></div> +<div class="clip">XXXXX<div style="will-change: opacity">XXXXX</div></div> +<div class="clip">XXXXX<div style="filter: opacity(1)">XXXXX</div></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-clip/clip-text-stacking-context-child.html b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-clip/clip-text-stacking-context-child.html new file mode 100644 index 0000000..06395c95 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-clip/clip-text-stacking-context-child.html
@@ -0,0 +1,28 @@ +<!DOCTYPE html> +<title>background-clip:text with stacking context children</title> +<link rel="help" href="https://drafts.csswg.org/css-backgrounds-4/#valdef-background-clip-text"> +<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/9563"> +<link rel="match" href="clip-text-stacking-context-child-ref.html"> +<link rel="stylesheet" href="/fonts/ahem.css"> + +<style> +.clip { + font: 50px/1 Ahem; + color: transparent; + background-color: green; + background-clip: text; +} +</style> +<!-- Test passes if there are 8 5-character green texts. --> + +<!-- opacity creates stacking context --> +<div class="clip">XXXXX<div style="opacity: 0.99">XXXXX</div></div> + +<!-- transform creates stacking context --> +<div class="clip">XXXXX<div style="transform: translateX(0)">XXXXX</div></div> + +<!-- will-change creates stacking context --> +<div class="clip">XXXXX<div style="will-change: opacity">XXXXX</div></div> + +<!-- filter creates stacking context --> +<div class="clip">XXXXX<div style="filter: opacity(1)">XXXXX</div></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-clip/clip-text-text-align-ref.html b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-clip/clip-text-text-align-ref.html new file mode 100644 index 0000000..f494541 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-clip/clip-text-text-align-ref.html
@@ -0,0 +1,12 @@ +<!DOCTYPE html> +<link rel="stylesheet" href="/fonts/ahem.css"> +<style> +.clip { + font: 50px/1 Ahem; + width: 250px; + color: green; +} +</style> +<div class="clip" style="text-align: left">XXXXX</div> +<div class="clip" style="text-align: center">XXXXX</div> +<div class="clip" style="text-align: right">XXXXX</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-clip/clip-text-text-align.html b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-clip/clip-text-text-align.html new file mode 100644 index 0000000..722b016 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-clip/clip-text-text-align.html
@@ -0,0 +1,19 @@ +<!DOCTYPE html> +<title>background-clip:text with text-align</title> +<link rel="help" href="https://drafts.csswg.org/css-backgrounds-4/#valdef-background-clip-text"> +<link rel="match" href="clip-text-text-align-ref.html"> +<link rel="stylesheet" href="/fonts/ahem.css"> + +<style> +.clip { + font: 50px/1 Ahem; + width: 250px; + color: transparent; + background-color: green; + background-clip: text; +} +</style> +<!-- Test passes if there are three 5-character green texts with left, center, and right alignment. --> +<div class="clip" style="text-align: left">XXXXX</div> +<div class="clip" style="text-align: center">XXXXX</div> +<div class="clip" style="text-align: right">XXXXX</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color-adjust/rendering/dark-color-scheme/color-scheme-color-property.html b/third_party/blink/web_tests/external/wpt/css/css-color-adjust/rendering/dark-color-scheme/color-scheme-color-initial-affected-by-color-scheme-property.html similarity index 100% rename from third_party/blink/web_tests/external/wpt/css/css-color-adjust/rendering/dark-color-scheme/color-scheme-color-property.html rename to third_party/blink/web_tests/external/wpt/css/css-color-adjust/rendering/dark-color-scheme/color-scheme-color-initial-affected-by-color-scheme-property.html
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color-adjust/rendering/dark-color-scheme/color-scheme-color-initial-affected-by-meta-color-scheme-dynamic.html b/third_party/blink/web_tests/external/wpt/css/css-color-adjust/rendering/dark-color-scheme/color-scheme-color-initial-affected-by-meta-color-scheme-dynamic.html new file mode 100644 index 0000000..91a4bd4 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-color-adjust/rendering/dark-color-scheme/color-scheme-color-initial-affected-by-meta-color-scheme-dynamic.html
@@ -0,0 +1,30 @@ +<!doctype html> + +<title>CSS Color Adjustment Test: initial color is affected by meta color-scheme</title> +<link rel="author" title="Kiet Ho" href="mailto:kiet.ho@apple.com"> + +<meta id="meta" name="color-scheme" /> + +<link rel="help" href="https://drafts.csswg.org/css-color-adjust/#color-scheme-processing"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<style> + #ref { color: CanvasText; } + #initial { color: initial; } +</style> + +<div id="ref"></div> +<div id="initial"></div> + +<script> + test(() => { + meta.setAttribute("content", "light") + assert_equals(getComputedStyle(initial).color, getComputedStyle(ref).color); + }, "In light mode as indicated by <meta> color-scheme, explicit color: initial matches CanvasText"); + + test(() => { + meta.setAttribute("content", "dark") + assert_equals(getComputedStyle(initial).color, getComputedStyle(ref).color); + }, "In dark mode as indicated by <meta> color-scheme, explicit color: initial matches CanvasText"); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color-adjust/rendering/dark-color-scheme/color-scheme-iframe-background-mismatch-opaque-cross-origin-003-ref.html b/third_party/blink/web_tests/external/wpt/css/css-color-adjust/rendering/dark-color-scheme/color-scheme-iframe-background-mismatch-opaque-cross-origin-003-ref.html new file mode 100644 index 0000000..3846321 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-color-adjust/rendering/dark-color-scheme/color-scheme-iframe-background-mismatch-opaque-cross-origin-003-ref.html
@@ -0,0 +1,5 @@ +<!doctype html> +<style> + html { color-scheme: dark; } +</style> +<p>You should not see any white boxes.</p>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color-adjust/rendering/dark-color-scheme/color-scheme-iframe-background-mismatch-opaque-cross-origin-003.sub.html b/third_party/blink/web_tests/external/wpt/css/css-color-adjust/rendering/dark-color-scheme/color-scheme-iframe-background-mismatch-opaque-cross-origin-003.sub.html new file mode 100644 index 0000000..a279921 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-color-adjust/rendering/dark-color-scheme/color-scheme-iframe-background-mismatch-opaque-cross-origin-003.sub.html
@@ -0,0 +1,25 @@ +<!doctype html> + +<title>CSS Color Adjustment Test: Cross-origin frame with light color-scheme should not get opaque background when embedding element is also light, even though the parent document is dark</title> +<link rel="author" title="Kiet Ho" href="mailto:kiet.ho@apple.com"> +<link rel="help" href="https://drafts.csswg.org/css-color-adjust/#color-scheme-effect"> +<link rel="match" href="color-scheme-iframe-background-mismatch-opaque-cross-origin-003-ref.html"> + +<style> + html { + color-scheme: dark; + } + + iframe { + margin: 0; + border: 0; + padding: 0; + width: 200px; + height: 200px; + display: block; + color-scheme: light; + } +</style> + +<p>You should not see any white boxes.</p> +<iframe src="http://{{hosts[alt][]}}:{{ports[http][0]}}/css/css-color-adjust/rendering/dark-color-scheme/support/light-frame-empty.html"></iframe>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color-adjust/rendering/dark-color-scheme/support/light-frame-empty.html b/third_party/blink/web_tests/external/wpt/css/css-color-adjust/rendering/dark-color-scheme/support/light-frame-empty.html new file mode 100644 index 0000000..7f4da1e --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-color-adjust/rendering/dark-color-scheme/support/light-frame-empty.html
@@ -0,0 +1,4 @@ +<!doctype html> +<style> + :root { color-scheme: light } +</style>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-computed-color-mix-function-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-computed-color-mix-function-expected.txt new file mode 100644 index 0000000..74d9c24 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-computed-color-mix-function-expected.txt
@@ -0,0 +1,16 @@ +This is a testharness.js-based test. +Found 6 FAIL, 0 TIMEOUT, 0 NOTRUN. +[FAIL] Property color value 'color-mix(in srgb, red)' + assert_true: 'color-mix(in srgb, red)' is a supported value for color. expected true got false +[FAIL] Property color value 'color-mix(in srgb, red 50%)' + assert_true: 'color-mix(in srgb, red 50%)' is a supported value for color. expected true got false +[FAIL] Property color value 'color-mix(in srgb, red, green, blue)' + assert_true: 'color-mix(in srgb, red, green, blue)' is a supported value for color. expected true got false +[FAIL] Property color value 'color-mix(in srgb, red 50%, green 30%, blue 20%)' + assert_true: 'color-mix(in srgb, red 50%, green 30%, blue 20%)' is a supported value for color. expected true got false +[FAIL] Property color value 'color-mix(in srgb, red 30%, green 60%, blue 90%)' + assert_true: 'color-mix(in srgb, red 30%, green 60%, blue 90%)' is a supported value for color. expected true got false +[FAIL] Property color value 'color-mix(in srgb, red, green, blue, white)' + assert_true: 'color-mix(in srgb, red, green, blue, white)' is a supported value for color. expected true got false +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-computed-color-mix-function.html b/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-computed-color-mix-function.html index 7ded5de..91f226f1 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-computed-color-mix-function.html +++ b/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-computed-color-mix-function.html
@@ -571,6 +571,14 @@ // Carry forward hue that became powerless due to conversion of colorspace fuzzy_test_computed_color(`color-mix(in oklch, hsl(0 100% 100%), blue)`, `oklch(0.726007 0.156607 264.052)`); + + // color-mix() with 1 or more colors. + fuzzy_test_computed_color(`color-mix(in srgb, red)`, `rgb(255, 0, 0)`); + fuzzy_test_computed_color(`color-mix(in srgb, red 50%)`, `rgba(255, 0, 0, 0.5)`); + fuzzy_test_computed_color(`color-mix(in srgb, red, green, blue)`, `color(srgb 0.333333 0.167320 0.333333)`); + fuzzy_test_computed_color(`color-mix(in srgb, red 50%, green 30%, blue 20%)`, `color(srgb 0.5 0.150588 0.2)`); + fuzzy_test_computed_color(`color-mix(in srgb, red 30%, green 60%, blue 90%)`, `color(srgb 0.166667 0.167320 0.5)`); + fuzzy_test_computed_color(`color-mix(in srgb, red, green, blue, white)`, `color(srgb 0.5 0.375490 0.5)`); </script> </body> </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-invalid-color-mix-function.html b/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-invalid-color-mix-function.html index 3d6fd06..8aae9fb 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-invalid-color-mix-function.html +++ b/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-invalid-color-mix-function.html
@@ -82,6 +82,14 @@ test_invalid_value(`color`, `color-mix(in ${colorSpace}, color(${colorSpace} .1 .2 .3) color(${colorSpace} .5 .6 .7))`); // Missing comma between colors. test_invalid_value(`color`, `color-mix(color(${colorSpace} .1 .2 .3), color(${colorSpace} .5 .6 .7), in ${colorSpace})`); // Interpolation method not at the beginning. } + + // color-mix() with 1 or more colors. + test_invalid_value(`color`, `color-mix(in srgb, red 0%)`); + test_invalid_value(`color`, `color-mix(in srgb, red 0%, green 0%, blue 0%)`); + test_invalid_value(`color`, `color-mix(in srgb, red -10%, green 50%, blue)`); + test_invalid_value(`color`, `color-mix(in hsl, hsl(120deg 10% 20%) -10%, hsl(30deg 30% 40%), hsl(60deg 20% 30%))`); + test_invalid_value(`color`, `color-mix(in srgb, red 150%, green 50%, blue)`); + test_invalid_value(`color`, `color-mix(in hsl, hsl(120deg 10% 20%) 150%, hsl(30deg 30% 40%), hsl(60deg 20% 30%))`); </script> </body> </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-valid-color-mix-function-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-valid-color-mix-function-expected.txt new file mode 100644 index 0000000..5064781 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-valid-color-mix-function-expected.txt
@@ -0,0 +1,26 @@ +This is a testharness.js-based test. +Found 11 FAIL, 0 TIMEOUT, 0 NOTRUN. +[FAIL] e.style['color'] = "color-mix(in srgb, red)" should set the property value + assert_not_equals: property should be set got disallowed value "" +[FAIL] e.style['color'] = "color-mix(in srgb, red 100%)" should set the property value + assert_not_equals: property should be set got disallowed value "" +[FAIL] e.style['color'] = "color-mix(in srgb, red 50%)" should set the property value + assert_not_equals: property should be set got disallowed value "" +[FAIL] e.style['color'] = "color-mix(in srgb, red, green, blue)" should set the property value + assert_not_equals: property should be set got disallowed value "" +[FAIL] e.style['color'] = "color-mix(in hsl, red, green, blue)" should set the property value + assert_not_equals: property should be set got disallowed value "" +[FAIL] e.style['color'] = "color-mix(in srgb, red 50%, green 30%, blue 20%)" should set the property value + assert_not_equals: property should be set got disallowed value "" +[FAIL] e.style['color'] = "color-mix(in srgb, red 30%, green 60%, blue 90%)" should set the property value + assert_not_equals: property should be set got disallowed value "" +[FAIL] e.style['color'] = "color-mix(in srgb, red 50%, green, blue)" should set the property value + assert_not_equals: property should be set got disallowed value "" +[FAIL] e.style['color'] = "color-mix(in srgb, red, green 25%, blue 25%)" should set the property value + assert_not_equals: property should be set got disallowed value "" +[FAIL] e.style['color'] = "color-mix(in srgb, red, green, blue, white)" should set the property value + assert_not_equals: property should be set got disallowed value "" +[FAIL] e.style['color'] = "color-mix(in srgb, currentcolor, red, blue)" should set the property value + assert_not_equals: property should be set got disallowed value "" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-valid-color-mix-function.html b/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-valid-color-mix-function.html index 17a6b0c..6819a07 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-valid-color-mix-function.html +++ b/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-valid-color-mix-function.html
@@ -455,6 +455,19 @@ fuzzy_test_valid_color(`color-mix(in srgb, red, blue 90%)`, `color-mix(in srgb, red 10%, blue)`) // only p2 specified fuzzy_test_valid_color(`color-mix(in srgb, red, blue calc(50%))`, `color-mix(in srgb, red, blue calc(50%))`) // only p2 specified, is `calc()` fuzzy_test_valid_color(`color-mix(in srgb, red, blue)`, `color-mix(in srgb, red, blue)`) // neither is specified + + // color-mix() with 1 or more colors. + fuzzy_test_valid_color(`color-mix(in srgb, red)`, `color-mix(in srgb, red)`); + fuzzy_test_valid_color(`color-mix(in srgb, red 100%)`, `color-mix(in srgb, red)`); + fuzzy_test_valid_color(`color-mix(in srgb, red 50%)`, `color-mix(in srgb, red 50%)`); + fuzzy_test_valid_color(`color-mix(in srgb, red, green, blue)`, `color-mix(in srgb, red, green, blue)`); + fuzzy_test_valid_color(`color-mix(in hsl, red, green, blue)`, `color-mix(in hsl, red, green, blue)`); + fuzzy_test_valid_color(`color-mix(in srgb, red 50%, green 30%, blue 20%)`, `color-mix(in srgb, red 50%, green 30%, blue 20%)`); + fuzzy_test_valid_color(`color-mix(in srgb, red 30%, green 60%, blue 90%)`, `color-mix(in srgb, red 30%, green 60%, blue 90%)`); + fuzzy_test_valid_color(`color-mix(in srgb, red 50%, green, blue)`, `color-mix(in srgb, red 50%, green 25%, blue 25%)`); + fuzzy_test_valid_color(`color-mix(in srgb, red, green 25%, blue 25%)`, `color-mix(in srgb, red 50%, green 25%, blue 25%)`); + fuzzy_test_valid_color(`color-mix(in srgb, red, green, blue, white)`, `color-mix(in srgb, red, green, blue, white)`); + fuzzy_test_valid_color(`color-mix(in srgb, currentcolor, red, blue)`, `color-mix(in srgb, currentcolor, red, blue)`); </script> </body> </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-conditional/container-queries/crashtests/chrome-bug-491994185-crash.html b/third_party/blink/web_tests/external/wpt/css/css-conditional/container-queries/crashtests/chrome-bug-491994185-crash.html new file mode 100644 index 0000000..cf27c578 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-conditional/container-queries/crashtests/chrome-bug-491994185-crash.html
@@ -0,0 +1,32 @@ +<!DOCTYPE html> +<title>Crash Test: Layout subtree root becoming display:none</title> +<link rel="help" href="https://issues.chromium.org/issues/491994185"> +<style> + #container { + container-type: inline-size; + } + @container (min-width: 300px) { + #victim { display: none; } + } +</style> +<div style="contain:strict;"> + <div id="herring"></div> +</div> +<div> + <div style="contain:strict; width:400px;"> + <div id="containerResizer" style="width:10px;"> + <div id="container"> + <div id="victim" style="contain:strict;"> + <div id="innerElm"></div> + </div> + </div> + </div> + </div> +</div> +<script> + document.body.offsetTop; + innerElm.style.height = '40px'; + herring.style.height = '60px'; + containerResizer.style.width = '400px'; + document.body.offsetTop; +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-font-loading/fontface-from-arraybuffer-ref.html b/third_party/blink/web_tests/external/wpt/css/css-font-loading/fontface-from-arraybuffer-ref.html new file mode 100644 index 0000000..bd1289e7 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-font-loading/fontface-from-arraybuffer-ref.html
@@ -0,0 +1,24 @@ +<!DOCTYPE html> +<html class="reftest-wait"> + <head> + <script src="/common/reftest-wait.js"></script> + </head> + <body> + <canvas id="canvas" width="500px" height="500px"></canvas> + <script> + const ahem_font = new FontFace( + "FontFamily AhemTest", + "url(/fonts/Ahem.ttf)", + ); + document.fonts.add(ahem_font); + ahem_font.load().then( + () => { + const ctx = canvas.getContext("2d"); + ctx.font = '36px "FontFamily AhemTest"'; + ctx.fillText("Ahem font loaded", 20, 50); + takeScreenshot(); + }, + ); + </script> + </body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-font-loading/fontface-from-arraybuffer.html b/third_party/blink/web_tests/external/wpt/css/css-font-loading/fontface-from-arraybuffer.html new file mode 100644 index 0000000..24195a2 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-font-loading/fontface-from-arraybuffer.html
@@ -0,0 +1,33 @@ +<!DOCTYPE html> +<html class="reftest-wait"> + <head> + <title>Constructing a FontFace from an ArrayBuffer should be equivalent to loading the same data from an URL</title> + <link rel="help" href="https://drafts.csswg.org/css-font-loading/#font-face-constructor"> + <link rel="author" title="Simon Wülker" href="simon.wuelker@arcor.de"> + <link rel=match href=fontface-from-arraybuffer-ref.html> + <link rel="help" href="https://github.com/servo/servo/issues/39657"> + <script src="/common/reftest-wait.js"></script> + </head> + <body> + <canvas id="canvas" width="500px" height="500px"></canvas> + <script> + fetch("/fonts/Ahem.ttf") + .then(res => res.arrayBuffer()) + .then(arrayBuffer => { + const ahem_font = new FontFace( + "FontFamily AhemTest", + arrayBuffer, + ); + document.fonts.add(ahem_font); + ahem_font.load().then( + () => { + const ctx = canvas.getContext("2d"); + ctx.font = '36px "FontFamily AhemTest"'; + ctx.fillText("Ahem font loaded", 20, 50); + takeScreenshot(); + } + ); + }); + </script> + </body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-font-loading/fontface-invalid-arraybuffer.html b/third_party/blink/web_tests/external/wpt/css/css-font-loading/fontface-invalid-arraybuffer.html new file mode 100644 index 0000000..458a3a2 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-font-loading/fontface-invalid-arraybuffer.html
@@ -0,0 +1,21 @@ +<!DOCTYPE html> +<html> + + <title>Constructing a FontFace from an ArrayBuffer should reject with a SyntaxError</title> + <link rel="help" href="https://drafts.csswg.org/css-font-loading/#font-face-constructor"> + <link rel="author" title="Simon Wülker" href="simon.wuelker@arcor.de"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + + <script> + promise_test(function(t) { + const bogus_font = new FontFace( + "FontFamily AhemTest", + new ArrayBuffer(8), + ); + document.fonts.add(bogus_font); + return promise_rejects_dom(t, 'SyntaxError', bogus_font.loaded); + }) + </script> + +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/item-placement/dense-packing/column-fill-reverse-dense-packing-definite-size-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/item-placement/dense-packing/column-fill-reverse-dense-packing-definite-size-001-ref.html new file mode 100644 index 0000000..d791d90 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/item-placement/dense-packing/column-fill-reverse-dense-packing-definite-size-001-ref.html
@@ -0,0 +1,61 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <link rel="stylesheet" type="text/css" href="/fonts/ahem.css"> + <style> + .container { + display: grid; + grid-template-columns: repeat(4, 100px); + grid-template-rows: 1fr; + column-gap: 10px; + height: 500px; + margin-top: 100px; + border: solid 2px blue; + width: min-content; + font-family: Ahem; + font-size: 10px; + } + .column { + display: flex; + flex-direction: column-reverse; + row-gap: 10px; + } + </style> +</head> +<body> + <div class="container"> + <!-- Column 1: block, spanner, (120px gap for items in other columns), spanner --> + <div class="column"> + <div style="background-color: lightcoral; height: 100px;">block</div> + <div style="background-color: lightcoral; height: 10px; width: 430px;">spanner</div> + <div style="height: 100px;"></div> + <div style="background-color: lightcoral; height: 10px; width: 430px;">spanner</div> + </div> + <!-- Column 2: Item 1, Item 5, Item 8, [spanner gap], Item 6, [spanner gap], Item 9, Item 10 --> + <div class="column"> + <div style="background-color: lightgreen; height: 30px;">Item 1</div> + <div style="background-color: lightgreen; height: 30px;">Item 5</div> + <div style="background-color: lightblue; height: 15px;">Item 8</div> + <div style="height: 10px;"></div><!-- spanner space --> + <div style="background-color: lightblue; height: 100px; margin-bottom: 5px;">Item 6</div> + <div style="height: 10px;"></div><!-- spanner space --> + <div style="background-color: lightblue; height: 40px;">Item 9</div> + <div style="background-color: steelblue; height: 45px;">Item 10</div> + </div> + <!-- Column 3: Item 2, [spanner gap], Item 4 --> + <div class="column"> + <div style="background-color: lightblue; height: 100px;">Item 2</div> + <div style="height: 10px;"></div><!-- spanner space --> + <div style="background-color: lightblue; height: 90px;">Item 4</div> + </div> + <!-- Column 4: Item 3, [spanner gap], Item 7, block2, [spanner gap] --> + <div class="column"> + <div style="background-color: lightgreen; height: 30px;">Item 3</div> + <div style="background-color: lightgreen; height: 30px;">Item 7</div> + <div style="background-color: lightcoral; height: 100px; margin-bottom: 50px;">block</div> + <div style="height: 20px;"></div><!-- spanner space --> + </div> + </div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/item-placement/dense-packing/column-fill-reverse-dense-packing-definite-size-001.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/item-placement/dense-packing/column-fill-reverse-dense-packing-definite-size-001.html new file mode 100644 index 0000000..0124ec3 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/item-placement/dense-packing/column-fill-reverse-dense-packing-definite-size-001.html
@@ -0,0 +1,45 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <title>CSS Grid Lanes: Fill-reverse with dense-packing</title> + <link rel="help" href="https://drafts.csswg.org/css-grid-3/"> + <link rel="match" href="column-fill-reverse-dense-packing-definite-size-001-ref.html"> + <link rel="author" title="Celeste Pan" href="mailto:celestepan@microsoft.com"> + <link rel="stylesheet" type="text/css" href="/fonts/ahem.css"> + <style> + .grid-lanes { + display: grid-lanes; + grid-template-columns: repeat(4, 100px); + grid-auto-flow: dense; + grid-lanes-pack: dense; + grid-lanes-direction: column fill-reverse; + gap: 10px; + margin-top: 100px; + border: solid 2px blue; + width: min-content; + font-family: Ahem; + font-size: 10px; + height: 500px; + } + </style> +</head> +<body> + <div class="grid-lanes"> + <div style="background-color: lightcoral; height: 100px;">block</div> + <div style="grid-column: span 4; background-color: lightcoral; height: 10px;">spanner</div> + <div style="background-color: lightgreen; height: 30px;">Item 1</div> + <div style="background-color: lightblue; height: 100px;">Item 2</div> + <div style="background-color: lightgreen; height: 30px;">Item 3</div> + <div style="background-color: lightblue; height: 90px; grid-column: 3;">Item 4</div> + <div style="background-color: lightgreen; height: 30px;">Item 5</div> + <div style="background-color: lightblue; height: 100px;">Item 6</div> + <div style="background-color: lightcoral; height: 100px;">block</div> + <div style="grid-column: span 4; background-color: lightcoral; height: 10px;">spanner</div> + <div style="background-color: lightgreen; height: 30px;">Item 7</div> + <div style="background-color: lightblue; height: 15px;">Item 8</div> + <div style="background-color: lightblue; grid-column: 2; height: 40px;">Item 9</div> + <div style="background-color: steelblue; grid-column: 2; height: 45px;">Item 10</div> + </div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/item-placement/dense-packing/row-fill-reverse-dense-packing-definite-size-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/item-placement/dense-packing/row-fill-reverse-dense-packing-definite-size-001-ref.html new file mode 100644 index 0000000..1dde7d21 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/item-placement/dense-packing/row-fill-reverse-dense-packing-definite-size-001-ref.html
@@ -0,0 +1,60 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <link rel="stylesheet" type="text/css" href="/fonts/ahem.css"> + <style> + .container { + display: grid; + grid-template-rows: repeat(4, 100px); + grid-template-columns: 1fr; + row-gap: 10px; + width: 500px; + margin-left: 100px; + border: solid 2px blue; + font-family: Ahem; + font-size: 10px; + } + .row { + display: flex; + flex-direction: row-reverse; + column-gap: 10px; + } + </style> +</head> +<body> + <div class="container"> + <!-- Row 1: block, spanner, spanner --> + <div class="row"> + <div style="background-color: lightcoral; width: 100px;">block</div> + <div style="background-color: lightcoral; width: 10px; height: 430px;">spanner</div> + <div style="background-color: lightcoral; width: 10px; height: 430px; margin-right: 110px;">spanner</div> + </div> + <!-- Row 2: Item 1, Item 5, Item 8, [spanner gap], Item 6, [spanner gap], Item 9, Item 10 --> + <div class="row"> + <div style="background-color: lightgreen; width: 30px;">Item 1</div> + <div style="background-color: lightgreen; width: 30px;">Item 5</div> + <div style="background-color: lightblue; width: 15px;">Item 8</div> + <div style="width: 10px;"></div><!-- spanner space --> + <div style="background-color: lightblue; width: 100px; margin-right: 5px;">Item 6</div> + <div style="width: 10px;"></div><!-- spanner space --> + <div style="background-color: lightblue; width: 40px;">Item 9</div> + <div style="background-color: steelblue; width: 45px;">Item 10</div> + </div> + <!-- Row 3: Item 2, [spanner gap], Item 4 --> + <div class="row"> + <div style="background-color: lightblue; width: 100px;">Item 2</div> + <div style="width: 10px;"></div><!-- spanner space --> + <div style="background-color: lightblue; width: 90px;">Item 4</div> + </div> + <!-- Row 4: Item 3, [spanner gap], Item 7, block2, [spanner gap] --> + <div class="row"> + <div style="background-color: lightgreen; width: 30px;">Item 3</div> + <div style="width: 10px;"></div><!-- spanner space --> + <div style="background-color: lightgreen; width: 30px; margin-right: -20px;">Item 7</div> + <div style="background-color: lightcoral; width: 100px; margin-right: 50px;">block</div> + <div style="width: 20px;"></div><!-- spanner space --> + </div> + </div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/item-placement/dense-packing/row-fill-reverse-dense-packing-definite-size-001.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/item-placement/dense-packing/row-fill-reverse-dense-packing-definite-size-001.html new file mode 100644 index 0000000..c30f6d0c --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/item-placement/dense-packing/row-fill-reverse-dense-packing-definite-size-001.html
@@ -0,0 +1,44 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <title>CSS Grid Lanes: Fill-reverse with dense-packing</title> + <link rel="help" href="https://drafts.csswg.org/css-grid-3/"> + <link rel="match" href="row-fill-reverse-dense-packing-definite-size-001-ref.html"> + <link rel="author" title="Celeste Pan" href="mailto:celestepan@microsoft.com"> + <link rel="stylesheet" type="text/css" href="/fonts/ahem.css"> + <style> + .grid-lanes { + display: grid-lanes; + grid-template-rows: repeat(4, 100px); + grid-lanes-direction: row fill-reverse; + grid-auto-flow: dense; + grid-lanes-pack: dense; + gap: 10px; + margin-left: 100px; + border: solid 2px blue; + width: 500px; + font-family: Ahem; + font-size: 10px; + } + </style> +</head> +<body> + <div class="grid-lanes"> + <div style="background-color: lightcoral; width: 100px;">block</div> + <div style="grid-row: span 4; background-color: lightcoral; width: 10px;">spanner</div> + <div style="background-color: lightgreen; width: 30px;">Item 1</div> + <div style="background-color: lightblue; width: 100px;">Item 2</div> + <div style="background-color: lightgreen; width: 30px;">Item 3</div> + <div style="background-color: lightblue; width: 90px; grid-row: 3;">Item 4</div> + <div style="background-color: lightgreen; width: 30px;">Item 5</div> + <div style="background-color: lightblue; width: 100px;">Item 6</div> + <div style="background-color: lightcoral; width: 100px;">block</div> + <div style="grid-row: span 4; background-color: lightcoral; width: 10px;">spanner</div> + <div style="background-color: lightgreen; width: 30px;">Item 7</div> + <div style="background-color: lightblue; width: 15px;">Item 8</div> + <div style="background-color: lightblue; grid-row: 2; width: 40px;">Item 9</div> + <div style="background-color: steelblue; grid-row: 2; width: 45px;">Item 10</div> + </div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/tentative/item-placement/column-fill-reverse-definite-size-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/tentative/item-placement/column-fill-reverse-definite-size-001-ref.html new file mode 100644 index 0000000..42d87e4 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/tentative/item-placement/column-fill-reverse-definite-size-001-ref.html
@@ -0,0 +1,45 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <style> + .container { + display: grid; + grid-template-columns: repeat(3, 50px); + column-gap: 10px; + height: 200px; + width: min-content; + border: solid blue; + } + .column { + display: flex; + flex-direction: column-reverse; + row-gap: 10px; + } + </style> +</head> +<body> + <p>Test that grid-lanes items with fill-reverse placement are correctly positioned + within a definite-size container.</p> + <div class="container"> + <div class="column"> + <div style="background: lavender; height: 20px;">1</div> + <div style="background: lightpink; height: 25px; width: 110px; margin-bottom: 10px;">4</div> + <div style="background: lightgreen; height: 20px;">7</div> + <div style="background: coral; height: 30px; margin-top: -10px;">9</div> + </div> + <div class="column"> + <div style="background: lightskyblue; height: 30px;">2</div> + <div style="background: lightpink; height: 40px; margin-bottom: 35px;">8</div> + <div style="background: tomato; height: 15px;">11</div> + <div style="background: orchid; height: 15px; margin-bottom: -125px; z-index: 1;">12</div> + </div> + <div class="column"> + <div style="background: lightgreen; height: 20px;">3</div> + <div style="background: lavender; height: 20px; margin-top: 10px;">5</div> + <div style="background: lightskyblue; height: 35px;">6</div> + <div style="background: gold; height: 30px; margin-bottom: -10px;">10</div> + </div> + </div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/tentative/item-placement/column-fill-reverse-definite-size-001.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/tentative/item-placement/column-fill-reverse-definite-size-001.html new file mode 100644 index 0000000..a3a98e7 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/tentative/item-placement/column-fill-reverse-definite-size-001.html
@@ -0,0 +1,44 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <title>CSS Grid Lanes: Column fill-reverse with definite size</title> + <link rel="help" href="https://drafts.csswg.org/css-grid-3"> + <link rel="match" href="column-fill-reverse-definite-size-001-ref.html"> + <link rel="author" title="Celeste Pan" href="mailto:celestepan@microsoft.com"> + <style> + .grid-lanes { + display: grid-lanes; + flow-tolerance: 0; + grid-template-columns: repeat(3, 50px); + gap: 10px; + height: 200px; + width: min-content; + border: solid blue; + grid-lanes-direction: column fill-reverse; + } + </style> +</head> +<body> + <p>Test that grid-lanes items with fill-reverse placement are correctly positioned + within a definite-size container.</p> + <div class="grid-lanes"> + <div style="background: lavender; height: 20px;">1</div> + <div style="background: lightskyblue; height: 30px;">2</div> + <div style="background: lightgreen; height: 20px;">3</div> + <div style="background: lightpink; grid-column: span 2; height: 25px;">4</div> + <div style="background: lavender; height: 20px; margin-top: 10px;">5</div> + <div style="background: lightskyblue; height: 35px;">6</div> + <div style="background: lightgreen; height: 20px;">7</div> + <div style="background: lightpink; height: 40px;">8</div> + <!-- Negative margin-top, less than item size --> + <div style="background: coral; height: 30px; margin-top: -10px;">9</div> + <!-- Negative margin-bottom, less than item size --> + <div style="background: gold; height: 30px; margin-bottom: -10px;">10</div> + <!-- Negative margin-top, greater than item size --> + <div style="background: tomato; height: 15px; margin-top: -25px;">11</div> + <!-- The lowest the item can go is 40px above where item 9 starts --> + <div style="background: orchid; height: 15px; margin-bottom: -100px;">12</div> + </div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/tentative/item-placement/column-fill-reverse-definite-size-002-ref.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/tentative/item-placement/column-fill-reverse-definite-size-002-ref.html new file mode 100644 index 0000000..29a0bc1d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/tentative/item-placement/column-fill-reverse-definite-size-002-ref.html
@@ -0,0 +1,46 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <style> + .container { + display: grid; + grid-template-columns: repeat(3, 50px); + column-gap: 10px; + height: 120px; + width: min-content; + border: solid blue; + } + .column { + display: flex; + flex-direction: column-reverse; + row-gap: 10px; + margin-top: -40px; + } + </style> +</head> +<body> + <p>Test that grid-lanes items with fill-reverse placement are correctly positioned + when overflowing a definite-size container.</p> + <div class="container"> + <div class="column"> + <div style="background: lavender; height: 20px;">1</div> + <div style="background: lightpink; height: 25px; width: 110px; margin-bottom: 10px;">4</div> + <div style="background: lightgreen; height: 20px;">7</div> + <div style="background: coral; height: 30px; margin-top: -10px;">9</div> + </div> + <div class="column"> + <div style="background: lightskyblue; height: 30px;">2</div> + <div style="background: lightpink; height: 40px; margin-bottom: 35px;">8</div> + <div style="background: tomato; height: 15px;">11</div> + <div style="background: orchid; height: 15px; margin-bottom: -125px; z-index: 1;">12</div> + </div> + <div class="column"> + <div style="background: lightgreen; height: 20px;">3</div> + <div style="background: lavender; height: 20px; margin-top: 10px;">5</div> + <div style="background: lightskyblue; height: 35px;">6</div> + <div style="background: gold; height: 30px; margin-bottom: -10px;">10</div> + </div> + </div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/tentative/item-placement/column-fill-reverse-definite-size-002.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/tentative/item-placement/column-fill-reverse-definite-size-002.html new file mode 100644 index 0000000..dedef6c --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/tentative/item-placement/column-fill-reverse-definite-size-002.html
@@ -0,0 +1,44 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <title>CSS Grid Lanes: Column fill-reverse where items overflow the definite size</title> + <link rel="help" href="https://drafts.csswg.org/css-grid-3"> + <link rel="match" href="column-fill-reverse-definite-size-002-ref.html"> + <link rel="author" title="Celeste Pan" href="mailto:celestepan@microsoft.com"> + <style> + .grid-lanes { + display: grid-lanes; + flow-tolerance: 0; + grid-template-columns: repeat(3, 50px); + gap: 10px; + height: 120px; + width: min-content; + border: solid blue; + grid-lanes-direction: column fill-reverse; + } + </style> +</head> +<body> + <p>Test that grid-lanes items with fill-reverse placement are correctly positioned + when overflowing a definite-size container.</p> + <div class="grid-lanes"> + <div style="background: lavender; height: 20px;">1</div> + <div style="background: lightskyblue; height: 30px;">2</div> + <div style="background: lightgreen; height: 20px;">3</div> + <div style="background: lightpink; grid-column: span 2; height: 25px;">4</div> + <div style="background: lavender; height: 20px; margin-top: 10px;">5</div> + <div style="background: lightskyblue; height: 35px;">6</div> + <div style="background: lightgreen; height: 20px;">7</div> + <div style="background: lightpink; height: 40px;">8</div> + <!-- Negative margin-top, less than item size --> + <div style="background: coral; height: 30px; margin-top: -10px;">9</div> + <!-- Negative margin-bottom, less than item size --> + <div style="background: gold; height: 30px; margin-bottom: -10px;">10</div> + <!-- Negative margin-top, greater than item size --> + <div style="background: tomato; height: 15px; margin-top: -25px;">11</div> + <!-- The lowest the item can go is 40px above where item 9 starts --> + <div style="background: orchid; height: 15px; margin-bottom: -100px;">12</div> + </div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/tentative/item-placement/column-fill-reverse-track-reverse-definite-size-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/tentative/item-placement/column-fill-reverse-track-reverse-definite-size-001-ref.html new file mode 100644 index 0000000..f4ef0ec --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/tentative/item-placement/column-fill-reverse-track-reverse-definite-size-001-ref.html
@@ -0,0 +1,52 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <style> + .container { + display: grid; + grid-template-columns: repeat(3, 50px); + column-gap: 10px; + height: 200px; + width: min-content; + border: solid blue; + } + + .track { + display: flex; + flex-direction: column; + height: 200px; + padding-bottom: 50px; + } + + .item { + width: 50px; + box-sizing: border-box; + } + </style> +</head> +<body> + <p>Test that grid-lanes items with fill-reverse and track-reverse placement are correctly positioned + within a definite-size container.</p> + <div class="container"> + <div class="track"> + <div class="item" style="background: gold; margin-top: 65px; height: 30px;">10</div> + <div class="item" style="background: lightskyblue; height: 35px;">6</div> + <div class="item" style="background: lavender; margin-top: 20px; height: 20px;">5</div> + <div class="item" style="background: lightgreen; margin-top: 10px; height: 20px;">3</div> + </div> + <div class="track"> + <div class="item" style="background: tomato; margin-top: 60px; height: 15px;">11</div> + <div class="item" style="background: lightpink; margin-top: 10px; height: 40px;">8</div> + <div class="item" style="background: lightpink; margin-top: 10px; width: 110px; height: 25px;">4</div> + <div class="item" style="background: orchid; margin-top: 10px; height: 15px; z-index: 1;">12</div> + <div class="item" style="background: lightskyblue; height: 15px; overflow: hidden;"></div> + </div> + <div class="track"> + <div class="item" style="background: coral; margin-top: 65px; height: 30px;">9</div> + <div class="item" style="background: lightgreen; margin-top: 10px; height: 20px;">7</div> + <div class="item" style="background: lavender; margin-top: 55px; height: 20px;">1</div> + </div> + </div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/tentative/item-placement/column-fill-reverse-track-reverse-definite-size-001.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/tentative/item-placement/column-fill-reverse-track-reverse-definite-size-001.html new file mode 100644 index 0000000..dc3d278 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/tentative/item-placement/column-fill-reverse-track-reverse-definite-size-001.html
@@ -0,0 +1,40 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <title>CSS Grid Lanes: Column fill-reverse and track-reverse with definite size</title> + <link rel="help" href="https://drafts.csswg.org/css-grid-3"> + <link rel="match" href="column-fill-reverse-track-reverse-definite-size-001-ref.html"> + <link rel="author" title="Celeste Pan" href="mailto:celestepan@microsoft.com"> + <style> + .grid-lanes { + display: grid-lanes; + flow-tolerance: 0; + grid-template-columns: repeat(3, 50px); + gap: 10px; + height: 200px; + width: min-content; + border: solid blue; + grid-lanes-direction: column fill-reverse track-reverse; + } + </style> +</head> +<body> + <p>Test that grid-lanes items with fill-reverse and track-reverse placement are correctly positioned + within a definite-size container.</p> + <div class="grid-lanes"> + <div style="background: lavender; height: 20px;">1</div> + <div style="background: lightskyblue; height: 30px;">2</div> + <div style="background: lightgreen; height: 20px;">3</div> + <div style="background: lightpink; grid-column: span 2; height: 25px;">4</div> + <div style="background: lavender; height: 20px; margin-top: 10px;">5</div> + <div style="background: lightskyblue; height: 35px;">6</div> + <div style="background: lightgreen; height: 20px;">7</div> + <div style="background: lightpink; height: 40px;">8</div> + <div style="background: coral; height: 30px; margin-top: -10px;">9</div> + <div style="background: gold; height: 30px; margin-bottom: -10px;">10</div> + <div style="background: tomato; height: 15px; margin-top: -25px;">11</div> + <div style="background: orchid; height: 15px; margin-bottom: -110px;">12</div> + </div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/tentative/item-placement/row-fill-reverse-definite-size-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/tentative/item-placement/row-fill-reverse-definite-size-001-ref.html new file mode 100644 index 0000000..1de6dad --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/tentative/item-placement/row-fill-reverse-definite-size-001-ref.html
@@ -0,0 +1,47 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <style> + .container { + display: grid; + grid-template-rows: repeat(3, 50px); + row-gap: 10px; + width: 200px; + border: solid blue; + } + .row { + display: flex; + flex-direction: row-reverse; + column-gap: 10px; + } + </style> +</head> +<body> + <p>Test that grid-lanes items with fill-reverse placement are correctly positioned + within a definite-size row container.</p> + <div class="container"> + <!-- Row 1: items 1, 4, 7, 9 --> + <div class="row"> + <div style="background: lavender; width: 20px;">1</div> + <div style="background: lightpink; width: 25px; height: 110px; margin-right: 10px;">4</div> + <div style="background: lightgreen; width: 20px;">7</div> + <div style="background: coral; width: 30px; margin-left: -10px;">9</div> + </div> + <!-- Row 2: items 2, 8, 11, 12 --> + <div class="row"> + <div style="background: lightskyblue; width: 30px;">2</div> + <div style="background: lightpink; width: 40px; margin-right: 35px;">8</div> + <div style="background: tomato; width: 15px;">11</div> + <div style="background: orchid; width: 15px; margin-right: -125px; z-index: 1;">12</div> + </div> + <!-- Row 3: items 3, 5, 6, 10 --> + <div class="row"> + <div style="background: lightgreen; width: 20px;">3</div> + <div style="background: lavender; width: 20px; margin-left: 10px;">5</div> + <div style="background: lightskyblue; width: 35px;">6</div> + <div style="background: gold; width: 30px; margin-right: -10px;">10</div> + </div> + </div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/tentative/item-placement/row-fill-reverse-definite-size-001.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/tentative/item-placement/row-fill-reverse-definite-size-001.html new file mode 100644 index 0000000..9070fa6f --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/tentative/item-placement/row-fill-reverse-definite-size-001.html
@@ -0,0 +1,43 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <title>CSS Grid Lanes: Row fill-reverse with definite size</title> + <link rel="help" href="https://drafts.csswg.org/css-grid-3"> + <link rel="match" href="row-fill-reverse-definite-size-001-ref.html"> + <link rel="author" title="Celeste Pan" href="mailto:celestepan@microsoft.com"> + <style> + .grid-lanes { + display: grid-lanes; + flow-tolerance: 0; + grid-template-rows: repeat(3, 50px); + gap: 10px; + width: 200px; + border: solid blue; + grid-lanes-direction: row fill-reverse; + } + </style> +</head> +<body> + <p>Test that grid-lanes items with fill-reverse placement are correctly positioned + within a definite-size row container.</p> + <div class="grid-lanes"> + <div style="background: lavender; width: 20px;">1</div> + <div style="background: lightskyblue; width: 30px;">2</div> + <div style="background: lightgreen; width: 20px;">3</div> + <div style="background: lightpink; grid-row: span 2; width: 25px;">4</div> + <div style="background: lavender; width: 20px; margin-left: 10px;">5</div> + <div style="background: lightskyblue; width: 35px;">6</div> + <div style="background: lightgreen; width: 20px;">7</div> + <div style="background: lightpink; width: 40px;">8</div> + <!-- Negative margin-left, less than item size --> + <div style="background: coral; width: 30px; margin-left: -10px;">9</div> + <!-- Negative margin-right, less than item size --> + <div style="background: gold; width: 30px; margin-right: -10px;">10</div> + <!-- Negative margin-left, greater than item size --> + <div style="background: tomato; width: 15px; margin-left: -25px;">11</div> + <!-- The furthest right the item can go is 40px to the left of where item 9 starts --> + <div style="background: orchid; width: 15px; margin-right: -100px;">12</div> + </div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/tentative/item-placement/row-fill-reverse-definite-size-002-ref.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/tentative/item-placement/row-fill-reverse-definite-size-002-ref.html new file mode 100644 index 0000000..b5a2df9 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/tentative/item-placement/row-fill-reverse-definite-size-002-ref.html
@@ -0,0 +1,45 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <style> + .container { + display: grid; + grid-template-rows: repeat(3, 50px); + row-gap: 10px; + width: 120px; + border: solid blue; + } + .row { + display: flex; + flex-direction: row-reverse; + column-gap: 10px; + margin-left: -40px; + } + </style> +</head> +<body> + <p>Test that grid-lanes items with fill-reverse placement are correctly positioned + when overflowing a definite-size row container.</p> + <div class="container"> + <div class="row"> + <div style="background: lavender; width: 20px;">1</div> + <div style="background: lightpink; width: 25px; height: 110px; margin-right: 10px;">4</div> + <div style="background: lightgreen; width: 20px;">7</div> + <div style="background: coral; width: 30px; margin-left: -10px;">9</div> + </div> + <div class="row"> + <div style="background: lightskyblue; width: 30px;">2</div> + <div style="background: lightpink; width: 40px; margin-right: 35px;">8</div> + <div style="background: tomato; width: 15px;">11</div> + <div style="background: orchid; width: 15px; margin-right: -125px; z-index: 1;">12</div> + </div> + <div class="row"> + <div style="background: lightgreen; width: 20px;">3</div> + <div style="background: lavender; width: 20px; margin-left: 10px;">5</div> + <div style="background: lightskyblue; width: 35px;">6</div> + <div style="background: gold; width: 30px; margin-right: -10px;">10</div> + </div> + </div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/tentative/item-placement/row-fill-reverse-definite-size-002.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/tentative/item-placement/row-fill-reverse-definite-size-002.html new file mode 100644 index 0000000..f50d93fed --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/tentative/item-placement/row-fill-reverse-definite-size-002.html
@@ -0,0 +1,43 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <title>CSS Grid Lanes: Row fill-reverse where items overflow the definite size</title> + <link rel="help" href="https://drafts.csswg.org/css-grid-3"> + <link rel="match" href="row-fill-reverse-definite-size-002-ref.html"> + <link rel="author" title="Celeste Pan" href="mailto:celestepan@microsoft.com"> + <style> + .grid-lanes { + display: grid-lanes; + flow-tolerance: 0; + grid-template-rows: repeat(3, 50px); + gap: 10px; + width: 120px; + border: solid blue; + grid-lanes-direction: row fill-reverse; + } + </style> +</head> +<body> + <p>Test that grid-lanes items with fill-reverse placement are correctly positioned + when overflowing a definite-size row container.</p> + <div class="grid-lanes"> + <div style="background: lavender; width: 20px;">1</div> + <div style="background: lightskyblue; width: 30px;">2</div> + <div style="background: lightgreen; width: 20px;">3</div> + <div style="background: lightpink; grid-row: span 2; width: 25px;">4</div> + <div style="background: lavender; width: 20px; margin-left: 10px;">5</div> + <div style="background: lightskyblue; width: 35px;">6</div> + <div style="background: lightgreen; width: 20px;">7</div> + <div style="background: lightpink; width: 40px;">8</div> + <!-- Negative margin-left, less than item size --> + <div style="background: coral; width: 30px; margin-left: -10px;">9</div> + <!-- Negative margin-right, less than item size --> + <div style="background: gold; width: 30px; margin-right: -10px;">10</div> + <!-- Negative margin-left, greater than item size --> + <div style="background: tomato; width: 15px; margin-left: -25px;">11</div> + <!-- The furthest right the item can go is 40px to the left of where item 9 starts --> + <div style="background: orchid; width: 15px; margin-right: -100px;">12</div> + </div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/tentative/item-placement/row-fill-reverse-track-reverse-definite-size-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/tentative/item-placement/row-fill-reverse-track-reverse-definite-size-001-ref.html new file mode 100644 index 0000000..ed9080b --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/tentative/item-placement/row-fill-reverse-track-reverse-definite-size-001-ref.html
@@ -0,0 +1,50 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <style> + .container { + display: grid; + grid-template-rows: repeat(3, 50px); + row-gap: 10px; + width: 200px; + border: solid blue; + } + + .track { + display: flex; + width: 200px; + height: 50px; + } + + .item { + height: 50px; + box-sizing: border-box; + } + </style> +</head> +<body> + <p>Test that grid-lanes items with fill-reverse and track-reverse placement are correctly positioned + within a definite-size row container.</p> + <div class="container"> + <div class="track"> + <div class="item" style="background: gold; margin-left: 65px; width: 30px;">10</div> + <div class="item" style="background: lightskyblue; width: 35px;">6</div> + <div class="item" style="background: lavender; margin-left: 20px; width: 20px;">5</div> + <div class="item" style="background: lightgreen; margin-left: 10px; width: 20px;">3</div> + </div> + <div class="track"> + <div class="item" style="background: tomato; margin-left: 60px; width: 15px;">11</div> + <div class="item" style="background: lightpink; margin-left: 10px; width: 40px;">8</div> + <div class="item" style="background: lightpink; margin-left: 10px; width: 25px; height: 110px;">4</div> + <div class="item" style="background: orchid; margin-left: 10px; width: 15px; z-index: 1;">12</div> + <div class="item" style="background: lightskyblue; width: 15px; overflow: hidden;"></div> + </div> + <div class="track"> + <div class="item" style="background: coral; margin-left: 65px; width: 30px;">9</div> + <div class="item" style="background: lightgreen; margin-left: 10px; width: 20px;">7</div> + <div class="item" style="background: lavender; margin-left: 55px; width: 20px;">1</div> + </div> + </div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/tentative/item-placement/row-fill-reverse-track-reverse-definite-size-001.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/tentative/item-placement/row-fill-reverse-track-reverse-definite-size-001.html new file mode 100644 index 0000000..75d695a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-lanes/tentative/item-placement/row-fill-reverse-track-reverse-definite-size-001.html
@@ -0,0 +1,39 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <title>CSS Grid Lanes: Row fill-reverse and track-reverse with definite size</title> + <link rel="help" href="https://drafts.csswg.org/css-grid-3"> + <link rel="match" href="row-fill-reverse-track-reverse-definite-size-001-ref.html"> + <link rel="author" title="Celeste Pan" href="mailto:celestepan@microsoft.com"> + <style> + .grid-lanes { + display: grid-lanes; + flow-tolerance: 0; + grid-template-rows: repeat(3, 50px); + gap: 10px; + width: 200px; + border: solid blue; + grid-lanes-direction: row fill-reverse track-reverse; + } + </style> +</head> +<body> + <p>Test that grid-lanes items with fill-reverse and track-reverse placement are correctly positioned + within a definite-size row container.</p> + <div class="grid-lanes"> + <div style="background: lavender; width: 20px;">1</div> + <div style="background: lightskyblue; width: 30px;">2</div> + <div style="background: lightgreen; width: 20px;">3</div> + <div style="background: lightpink; grid-row: span 2; width: 25px;">4</div> + <div style="background: lavender; width: 20px; margin-left: 10px;">5</div> + <div style="background: lightskyblue; width: 35px;">6</div> + <div style="background: lightgreen; width: 20px;">7</div> + <div style="background: lightpink; width: 40px;">8</div> + <div style="background: coral; width: 30px; margin-left: -10px;">9</div> + <div style="background: gold; width: 30px; margin-right: -10px;">10</div> + <div style="background: tomato; width: 15px; margin-left: -25px;">11</div> + <div style="background: orchid; width: 15px; margin-right: -110px;">12</div> + </div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-highlight-api/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/css/css-highlight-api/WEB_FEATURES.yml index 0ce5201..3f486eb 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-highlight-api/WEB_FEATURES.yml +++ b/third_party/blink/web_tests/external/wpt/css/css-highlight-api/WEB_FEATURES.yml
@@ -1,3 +1,8 @@ features: - name: highlight - files: "**" + files: + - "*" + - "!HighlightRegistry-highlightsFromPoint*" +- name: highlightsfrompoint + files: + - HighlightRegistry-highlightsFromPoint*
diff --git a/third_party/blink/web_tests/external/wpt/css/css-highlight-api/crashtests/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/css/css-highlight-api/crashtests/WEB_FEATURES.yml new file mode 100644 index 0000000..0ce5201 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-highlight-api/crashtests/WEB_FEATURES.yml
@@ -0,0 +1,3 @@ +features: +- name: highlight + files: "**"
diff --git a/third_party/blink/web_tests/external/wpt/css/css-highlight-api/painting/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/css/css-highlight-api/painting/WEB_FEATURES.yml new file mode 100644 index 0000000..0ce5201 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-highlight-api/painting/WEB_FEATURES.yml
@@ -0,0 +1,3 @@ +features: +- name: highlight + files: "**"
diff --git a/third_party/blink/web_tests/external/wpt/css/css-lists/outside-marker-covered-by-relpos-block-link-ref.html b/third_party/blink/web_tests/external/wpt/css/css-lists/outside-marker-covered-by-relpos-block-link-ref.html new file mode 100644 index 0000000..d22d018 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-lists/outside-marker-covered-by-relpos-block-link-ref.html
@@ -0,0 +1,38 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Reference: outside marker covered by relatively positioned block link</title> +<link rel="author" title="Jason Leo" href="mailto:m.jason.liu@outlook.com"> +<style> +body { + background: white; + font: 16px/1.4 sans-serif; +} + +ul { + list-style-position: outside; + padding-inline-start: 40px; +} + +.hide-marker::marker { + color: transparent; +} + +.LinkContainer { + width: 290px; +} + +.faqviewmore { + background-color: #efefef; + display: block; + left: -22px; + padding-left: 22px; + position: relative; +} +</style> + +<div class="LinkContainer"> + <ul> + <li><a href="#">Why doesn't my map print?</a></li> + <li class="hide-marker"><a class="faqviewmore" href="#">View more questions</a></li> + </ul> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-lists/outside-marker-covered-by-relpos-block-link.html b/third_party/blink/web_tests/external/wpt/css/css-lists/outside-marker-covered-by-relpos-block-link.html new file mode 100644 index 0000000..25c35fd --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-lists/outside-marker-covered-by-relpos-block-link.html
@@ -0,0 +1,38 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Lists: outside marker covered by relatively positioned block link</title> +<link rel="author" title="CGQAQ" href="mailto:cgqaq@chromium.org"> +<link rel="help" href="https://www.w3.org/TR/CSS22/generate.html#lists"> +<link rel="help" href="https://bugs.webkit.org/show_bug.cgi?id=18289"> +<link rel="match" href="outside-marker-covered-by-relpos-block-link-ref.html"> +<meta name="assert" content="An outside list marker must not remain visibly painted when a relatively positioned display:block link extends into the marker area and paints over it."> +<style> +body { + background: white; + font: 16px/1.4 sans-serif; +} + +ul { + list-style-position: outside; + padding-inline-start: 40px; +} + +.LinkContainer { + width: 290px; +} + +.faqviewmore { + background-color: #efefef; + display: block; + left: -22px; + padding-left: 22px; + position: relative; +} +</style> + +<div class="LinkContainer"> + <ul> + <li><a href="#">Why doesn't my map print?</a></li> + <li><a class="faqviewmore" href="#">View more questions</a></li> + </ul> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/css/css-multicol/WEB_FEATURES.yml index 9f4475fa7..c0158be 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-multicol/WEB_FEATURES.yml +++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/WEB_FEATURES.yml
@@ -135,12 +135,6 @@ - column-height-003.html - column-height-008.html - column-height-009.html - - "!column-height-010.html" - - "!column-height-011.html" - - "!column-height-015.html" - - "!column-height-021.html" - - "!column-height-022.html" - - "!column-height-023.html" - "!column-rule-002.html" - "!columnfill-auto-max-height-*" - "!equal-gap-and-rule.html" @@ -157,7 +151,6 @@ - "!multicol-br-inside-avoidcolumn-001.xht" - "!multicol-break-*" - "!multicol-breaking-*" - - "!multicol-breaking-*" - "!multicol-containing-003.html" - "!multicol-fill-000.xht" - "!multicol-fill-001.xht" @@ -174,7 +167,6 @@ - "!multicol-height-*" - "!multicol-list-item-008.html" - "!multicol-margin-*" - - "!multicol-margin-002.xht" - multicol-margin-003.html - "!multicol-nested-*" - multicol-nested-002.xht @@ -214,8 +206,6 @@ - "!intrinsic-size-003.html" - "!intrinsic-size-004.html" - "!intrinsic-size-005.html" - - "!multicol-fill-auto-block-children-001.xht" - - "!multicol-fill-auto-block-children-002.xht" - "!multicol-width-004.html" - "!multicol-width-005.html" - "!spanning-legend-*"
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-011.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-011.html similarity index 82% rename from third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-011.tentative.html rename to third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-011.html index 69effbc..a409ea19 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-011.tentative.html +++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-011.html
@@ -4,7 +4,7 @@ <link rel="author" title="Andreu Botella" href="mailto:abotella@igalia.com"> <link rel="help" href="https://drafts.csswg.org/css-overflow-4/#line-clamp"> <link rel="match" href="reference/line-clamp-011-ref.html"> -<meta name="assert" content="When line-clamp is used with a number of lines while also having a set block size, whichever comes earlier takes precedence."> +<meta name="assert" content="When line-clamp is used with a number of lines while also having a set block size, only the line number affects the clamping; content beyond the block size, if any, overflows."> <style> .clamp { line-clamp: 4; @@ -20,4 +20,3 @@ Line 3 Line 4 Line 5</div> -<p>Following content.</p>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-011.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-035.html similarity index 80% copy from third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-011.tentative.html copy to third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-035.html index 69effbc..90513d78 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-011.tentative.html +++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-035.html
@@ -4,12 +4,12 @@ <link rel="author" title="Andreu Botella" href="mailto:abotella@igalia.com"> <link rel="help" href="https://drafts.csswg.org/css-overflow-4/#line-clamp"> <link rel="match" href="reference/line-clamp-011-ref.html"> -<meta name="assert" content="When line-clamp is used with a number of lines while also having a set block size, whichever comes earlier takes precedence."> +<meta name="assert" content="When line-clamp is used with a number of lines while also having a max block size, only the line number affects the clamping; content beyond the block size, if any, overflows."> <style> .clamp { line-clamp: 4; font: 16px / 32px serif; - height: 3lh; + max-height: 3lh; padding: 0 4px; white-space: pre; background-color: yellow; @@ -20,4 +20,3 @@ Line 3 Line 4 Line 5</div> -<p>Following content.</p>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-035.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-035.tentative.html deleted file mode 100644 index feb4aac6..0000000 --- a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-035.tentative.html +++ /dev/null
@@ -1,24 +0,0 @@ -<!DOCTYPE html> -<meta charset="utf-8"> -<title>CSS Overflow: `line-clamp` with a number and a smaller max-height</title> -<link rel="author" title="Andreu Botella" href="mailto:abotella@igalia.com"> -<link rel="help" href="https://drafts.csswg.org/css-overflow-4/#line-clamp"> -<link rel="match" href="reference/webkit-line-clamp-005-ref.html"> -<meta name="assert" content="If line-clamp is set to a number, and there is a (max-)height, the line-clamp container will clamp to whichever comes earlier."> -<style> -.clamp { - line-clamp: 6; - max-height: 4lh; - font: 16px / 32px serif; - white-space: pre; - background-color: yellow; - padding: 0 4px; -} -</style> -<div class="clamp">Line 1 -Line 2 -Line 3 -Line 4 -Line 5 -Line 6 -Line 7</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-001.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-001.html similarity index 100% rename from third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-001.tentative.html rename to third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-001.html
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-002.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-002.html similarity index 100% rename from third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-002.tentative.html rename to third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-002.html
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-003.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-003.html similarity index 100% rename from third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-003.tentative.html rename to third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-003.html
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-004.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-004.html similarity index 100% rename from third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-004.tentative.html rename to third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-004.html
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-005.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-005.html similarity index 83% rename from third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-005.tentative.html rename to third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-005.html index 9689a83..81831a5e 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-005.tentative.html +++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-005.html
@@ -4,12 +4,12 @@ <link rel="author" title="Andreu Botella" href="mailto:abotella@igalia.com"> <link rel="help" href="https://drafts.csswg.org/css-overflow-4/#line-clamp"> <link rel="match" href="reference/line-clamp-with-floats-005-ref.html"> -<meta name="assert" content="Floats in an inline formatting context inside a line-clamp container are not hidden if they come before the clamp point, even if they extend beyond that point"> +<meta name="assert" content="Floats in an inline formatting context before the clamp point are not hidden, but they are clipped to the line-clamp container's content edge"> <style> .clamp { line-clamp: 4; font: 16px / 32px serif; - padding: 0 4px; + padding: 4px; white-space: pre; background-color: yellow; }
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-006.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-006.html similarity index 77% rename from third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-006.tentative.html rename to third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-006.html index 0a709bf..c5608159 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-006.tentative.html +++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-006.html
@@ -3,13 +3,13 @@ <title>CSS Overflow: float in line-clamp before clamp point which extends past it</title> <link rel="author" title="Andreu Botella" href="mailto:abotella@igalia.com"> <link rel="help" href="https://drafts.csswg.org/css-overflow-4/#line-clamp"> -<link rel="match" href="reference/line-clamp-with-floats-006-ref.html"> -<meta name="assert" content="Floats in a block formatting context inside a line-clamp container are not hidden if they come before the clamp point, even if they extend beyond that point"> +<link rel="match" href="reference/line-clamp-with-floats-005-ref.html"> +<meta name="assert" content="Floats in a block formatting context before the clamp point are not hidden, but they are clipped to the line-clamp container's content edge"> <style> .clamp { line-clamp: 4; font: 16px / 32px serif; - padding: 0 4px; + padding: 4px; background-color: yellow; } .float {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-007.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-007.html similarity index 90% rename from third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-007.tentative.html rename to third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-007.html index 7ee286f..b6b7e1c 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-007.tentative.html +++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-007.html
@@ -9,7 +9,7 @@ .clamp { line-clamp: 4; font: 16px / 32px serif; - padding: 0 4px; + padding: 4px; white-space: pre; background-color: yellow; } @@ -18,14 +18,15 @@ margin: 4px; white-space: pre; background-color: skyblue; + line-height: 1em; } </style> <div class="clamp">Line 1 Line 2 -Line 3 -Line 4<div class="float">Line A +Line 3<div class="float">Line A Line B Line C Line D Line E</div> +Line 4 Line 5</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-008.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-008.html deleted file mode 100644 index 9ee8a05..0000000 --- a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-008.html +++ /dev/null
@@ -1,31 +0,0 @@ -<!DOCTYPE html> -<meta charset="utf-8"> -<title>CSS Overflow: line-clamp IFC with floats extending past the clamp point</title> -<link rel="author" title="Andreu Botella" href="mailto:abotella@igalia.com"> -<link rel="help" href="https://drafts.csswg.org/css-overflow-4/#line-clamp"> -<link rel="match" href="reference/line-clamp-with-floats-008-ref.html"> -<meta name="assert" content="Line-clamp containers create an independent formatting context, so they will clear contained floats before the clamp point, even if they extend beyond the last line. Lines past the clamp point will remain hidden."> -<style> -.clamp { - line-clamp: 4; - font: 16px / 32px serif; - padding: 0 4px; - white-space: pre; - background-color: yellow; -} -.float { - /* Floats create a parallel fragmentation context, and the forced break that - * line-clamp causes on the main context should not cause the float to - * fragment. */ - float: left; - width: 50px; - height: 50px; - margin: 4px; - background-color: skyblue; -} -</style> -<div class="clamp">Line 1 -Line 2 -Line 3 -<div class="float"></div>Line 4 -Line 5</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-009.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-009.tentative.html deleted file mode 100644 index f25ac381..0000000 --- a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-009.tentative.html +++ /dev/null
@@ -1,29 +0,0 @@ -<!DOCTYPE html> -<meta charset="utf-8"> -<title>CSS Overflow: line-clamp IFC with floats after the clamp point</title> -<link rel="author" title="Andreu Botella" href="mailto:abotella@igalia.com"> -<link rel="help" href="https://drafts.csswg.org/css-overflow-4/#line-clamp"> -<link rel="match" href="reference/webkit-line-clamp-005-ref.html"> -<meta name="assert" content="If the line-clamp container is an independent formatting context, it will not clear any floats after the clamp point."> -<style> -.clamp { - display: flow-root; - line-clamp: 4; - font: 16px / 32px serif; - padding: 0 4px; - white-space: pre; - background-color: yellow; -} -.float { - float: left; - width: 50px; - height: 50px; - margin: 4px; - background-color: skyblue; -} -</style> -<div class="clamp">Line 1 -Line 2 -Line 3 -Line 4 -Line 5<div class="float"></div></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-010.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-010.html similarity index 70% rename from third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-010.tentative.html rename to third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-010.html index a00ff60..c74f75d9e 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-010.tentative.html +++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-010.html
@@ -1,13 +1,13 @@ <!DOCTYPE html> <meta charset="utf-8"> -<title>CSS Overflow: line-clamp hidden floats should count as ink overflow</title> +<title>CSS Overflow: line-clamp hidden and clipped floats don't count as scrollable overflow</title> <link rel="author" title="Andreu Botella" href="mailto:abotella@igalia.com"> <link rel="help" href="https://drafts.csswg.org/css-overflow-4/#line-clamp"> <link rel="match" href="reference/line-clamp-with-floats-010-ref.html"> -<meta name="assert" content="Any overflowing content hidden from paint by line-clamp is treated as ink overflow, including floats, and therefore doesn't cause the scrollable overflow rectangle to grow. Meanwhile, non-hidden floats count as scrollable overflow."> +<meta name="assert" content="Neither floats entirely hidden from paint by line-clamp, nor pieces of floats that get clipped away from the line-clamp container's padding edge count as scrollable overflow. Therefore, they don't increase the scrollable overflow area."> <style> #scrollContainer { - overflow: scroll; + overflow: hidden; font: 16px / 32px serif; height: 4lh; border: 1px solid black;
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/line-clamp-011-ref.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/line-clamp-011-ref.html index 02ef71d..d318a3e66 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/line-clamp-011-ref.html +++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/line-clamp-011-ref.html
@@ -2,15 +2,17 @@ <meta charset="utf-8"> <title>CSS Reference</title> <style> -.clamp { +div { font: 16px / 32px serif; white-space: pre; - height: 3lh; padding: 0 4px; +} +.clamp { + height: 3lh; background-color: yellow; } </style> <div class="clamp">Line 1 Line 2 -Line 3…</div> -<p>Following content.</p> +Line 3</div> +<div>Line 4…</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/line-clamp-with-floats-005-ref.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/line-clamp-with-floats-005-ref.html index d20d6c53..e3ebd7ba 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/line-clamp-with-floats-005-ref.html +++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/line-clamp-with-floats-005-ref.html
@@ -2,22 +2,27 @@ <meta charset="utf-8"> <title>CSS Reference</title> <style> -.clamp { - display: flow-root; - font: 16px / 32px serif; - padding: 0 4px; - white-space: pre; +.parent { + padding: 4px; background-color: yellow; } +.clamp { + font: 16px / 32px serif; + white-space: pre; + overflow: clip; +} .float { float: left; width: 50px; height: 50px; margin: 4px; + margin-bottom: 0; background-color: skyblue; } </style> +<div class="parent"> <div class="clamp">Line 1 Line 2 Line 3 Line 4…<div class="float"></div></div> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/line-clamp-with-floats-006-ref.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/line-clamp-with-floats-006-ref.html deleted file mode 100644 index 9288c4e..0000000 --- a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/line-clamp-with-floats-006-ref.html +++ /dev/null
@@ -1,28 +0,0 @@ -<!DOCTYPE html> -<meta charset="utf-8"> -<title>CSS Reference</title> -<style> -.clamp { - display: flow-root; - font: 16px / 32px serif; - padding: 0 4px; - background-color: yellow; -} -.float { - float: left; - width: 50px; - height: 75px; - margin: 4px; - background-color: skyblue; -} -.pre { - white-space: pre; -} -</style> -<div class="clamp"> -<div class="pre">Line 1 -Line 2 -Line 3</div> -<div class="float"></div> -<div class="pre">Line 4…</div> -</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/line-clamp-with-floats-007-ref.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/line-clamp-with-floats-007-ref.html index 6d539024..56a74d9 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/line-clamp-with-floats-007-ref.html +++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/line-clamp-with-floats-007-ref.html
@@ -2,25 +2,30 @@ <meta charset="utf-8"> <title>CSS Reference</title> <style> -.clamp { - display: flow-root; - font: 16px / 32px serif; - padding: 0 4px; - white-space: pre; +.parent { + padding: 4px; background-color: yellow; } +.clamp { + font: 16px / 32px serif; + white-space: pre; + overflow: clip; +} .float { float: left; margin: 4px; white-space: pre; background-color: skyblue; + line-height: 1em; } </style> +<div class="parent"> <div class="clamp">Line 1 Line 2 -Line 3 -Line 4…<div class="float">Line A +Line 3<div class="float">Line A Line B Line C Line D -Line E</div></div> +Line E</div> +Line 4…</div> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/line-clamp-with-floats-008-ref.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/line-clamp-with-floats-008-ref.html deleted file mode 100644 index 50b3d53..0000000 --- a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/line-clamp-with-floats-008-ref.html +++ /dev/null
@@ -1,23 +0,0 @@ -<!DOCTYPE html> -<meta charset="utf-8"> -<title>CSS Reference</title> -<style> -.clamp { - display: flow-root; - font: 16px / 32px serif; - padding: 0 4px; - white-space: pre; - background-color: yellow; -} -.float { - float: left; - width: 50px; - height: 50px; - margin: 4px; - background-color: skyblue; -} -</style> -<div class="clamp">Line 1 -Line 2 -Line 3 -<div class="float"></div>Line 4…</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/line-clamp-with-floats-010-ref.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/line-clamp-with-floats-010-ref.html index 12b8cdc4..d4fbf4b4 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/line-clamp-with-floats-010-ref.html +++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/line-clamp-with-floats-010-ref.html
@@ -3,13 +3,15 @@ <title>CSS Reference</title> <style> #scrollContainer { - overflow: scroll; + overflow: hidden; font: 16px / 32px serif; - height: 4lh; border: 1px solid black; } +.parent { + overflow: hidden; + height: 4lh; +} .clamp { - display: flow-root; padding: 0 4px; white-space: pre; background-color: yellow; @@ -24,14 +26,9 @@ </style> <div id="scrollContainer"> +<div class="parent"> <div class="clamp">Line 1 Line 2 Line 3 Line 4…<div class="float"></div></div> - -<script> - window.addEventListener("load", () => { - const scrollContainer = document.getElementById("scrollContainer"); - scrollContainer.scrollTop = scrollContainer.scrollHeight; - }); -</script> +</div></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-044.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-044.html deleted file mode 100644 index 981e09b4..0000000 --- a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-044.html +++ /dev/null
@@ -1,35 +0,0 @@ -<!DOCTYPE html> -<meta charset="UTF-8"> -<title>CSS Overflow: -webkit-line-clamp creates an IFC</title> -<link rel="author" title="Andreu Botella" href="mailto:abotella@igalia.com"> -<link rel="help" href="https://drafts.csswg.org/css-overflow-4/#line-clamp"> -<link rel="match" href="reference/webkit-line-clamp-044-ref.html"> -<meta name="assert" content="-webkit-line-clamp always creates an independent formatting context, even without overflow: hidden, which causes the height to grow to the clearance of floats."> -<style> - .clamp { - display: -webkit-box; - -webkit-box-orient: vertical; - -webkit-line-clamp: 5; - /* no overflow: hidden */ - background-color: yellow; - padding: 0.5em; - font-size: 16px / 32px serif; - white-space: pre; - } - .float { - /* Floats create a parallel fragmentation context, and even if - * -webkit-line-clamp caused a forced break in the main context, that should - * not cause the float to fragment. */ - float: left; - background-color: orange; - padding: 0.5em; - height: 100px; - width: 100px; - } -</style> - -<div class="clamp"><div>Line 1 -Line 2 -Line 3 -Line 4 -<div class="float"></div>Line 5</div></div> \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-047.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-047.html deleted file mode 100644 index cb66eb7..0000000 --- a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-047.html +++ /dev/null
@@ -1,38 +0,0 @@ -<!DOCTYPE html> -<meta charset="UTF-8"> -<title>CSS Overflow: -webkit-line-clamp creates an IFC</title> -<link rel="author" title="Andreu Botella" href="mailto:abotella@igalia.com"> -<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net"> -<link rel="help" href="https://drafts.csswg.org/css-overflow-4/#line-clamp"> -<link rel="match" href="reference/webkit-line-clamp-047-ref.html"> -<meta name="assert" content="-webkit-line-clamp always creates an independent formatting context, even without overflow: hidden, which causes the height to grow to the clearance of floats."> -<style> - .clamp { - display: -webkit-box; - -webkit-box-orient: vertical; - -webkit-line-clamp: 5; - /* no overflow: hidden */ - background-color: yellow; - padding: 0.5em; - font: 16px / 32px serif; - white-space: pre; - } - .float { - /* Floats create a parallel fragmentation context, and even if - * -webkit-line-clamp caused a forced break in the main context, that should - * not cause the float to fragment. */ - float: left; - background-color: orange; - padding: 0.5em; - height: 100px; - width: 100px; - } -</style> - -<div class="clamp"><div>Line 1 -Line 2 -Line 3 -Line 4 -<div class="float"></div>Line 5</div> -Line 6 -Line 7</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-with-max-height.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-with-max-height.html similarity index 72% rename from third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-with-max-height.tentative.html rename to third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-with-max-height.html index 410fbef9..e6be329 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-with-max-height.tentative.html +++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-with-max-height.html
@@ -3,19 +3,18 @@ <title>CSS Overflow: -webkit-line-clamp with max-height</title> <link rel="author" title="Andreu Botella" href="mailto:abotella@igalia.com"> <link rel="help" href="https://drafts.csswg.org/css-overflow-4/#line-clamp"> -<link rel="match" href="reference/webkit-line-clamp-005-ref.html"> -<meta name="assert" content="If the -webkit-line-clamp property is set on an element where max-height is also specified, they will interact the same as for line-clamp: that is, the container will clamp after the line given by -webkit-line-clamp, or the last that fully fits in the height, whichever comes earlier."> +<link rel="match" href="reference/line-clamp-011-ref.html"> +<meta name="assert" content="If the -webkit-line-clamp property is set on an element where max-height is also specified, they will interact the same as for line-clamp: that is, the container will clamp after the line given by -webkit-line-clamp, and if the block is too small, excess content overflows."> <style> .clamp { display: -webkit-box; -webkit-box-orient: vertical; - -webkit-line-clamp: 5; + -webkit-line-clamp: 4; font: 16px / 32px serif; white-space: pre; padding: 0 4px; background-color: yellow; - overflow: hidden; - max-height: 4.5lh; + max-height: 3lh; } </style>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-position/sticky/position-sticky-on-minimum-scale-ref.html b/third_party/blink/web_tests/external/wpt/css/css-position/sticky/position-sticky-on-minimum-scale-ref.html new file mode 100644 index 0000000..0a030b0 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-position/sticky/position-sticky-on-minimum-scale-ref.html
@@ -0,0 +1,28 @@ +<!DOCTYPE html> +<html class="reftest-wait"> +<meta charset="utf-8"> +<meta name="viewport" content="width=device-width initial-scale=1"> +<style> +html { + scrollbar-width: none; +} +body { + width: 200vw; + margin: 0px; +} +div { + width: 50vw; + height: 100px; + display: inline-block; + background: blue; +} +.last { + background: red; +} +</style> +<div></div><div></div><div></div><div class="last"></div> +<script> +document.querySelector(".last").scrollIntoView({ behavior: "instant" }); +document.documentElement.classList.remove("reftest-wait"); +</script> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-position/sticky/position-sticky-on-minimum-scale.html b/third_party/blink/web_tests/external/wpt/css/css-position/sticky/position-sticky-on-minimum-scale.html new file mode 100644 index 0000000..5fca173 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-position/sticky/position-sticky-on-minimum-scale.html
@@ -0,0 +1,32 @@ +<!DOCTYPE html> +<html class="reftest-wait"> +<meta charset="utf-8"> +<meta name="viewport" content="width=device-width initial-scale=1"> +<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=2005857"> +<link rel="match" href="position-sticky-on-minimum-scale-ref.html"> +<style> +html { + scrollbar-width: none; +} +body { + width: 200vw; + margin: 0px; +} +div { + width: 50vw; + height: 100px; + display: inline-block; + background: blue; +} +.sticky { + position: sticky; + right: 0; + background: red; +} +</style> +<div></div><div></div><div></div><div class="sticky"></div> +<script> +document.querySelector(".sticky").scrollIntoView({ behavior: "instant" }); +document.documentElement.classList.remove("reftest-wait"); +</script> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/register-property-syntax-parsing-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/register-property-syntax-parsing-expected.txt new file mode 100644 index 0000000..e29a142 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/register-property-syntax-parsing-expected.txt
@@ -0,0 +1,14 @@ +This is a testharness.js-based test. +Found 5 FAIL, 0 TIMEOUT, 0 NOTRUN. +[FAIL] syntax:'--foo', initialValue:'--foo' is valid + Failed to execute 'registerProperty' on 'CSS': The syntax provided is not a valid custom property syntax. +[FAIL] syntax:'--foo | <color>', initialValue:'--foo' is valid + Failed to execute 'registerProperty' on 'CSS': The syntax provided is not a valid custom property syntax. +[FAIL] syntax:'--foo | <color>', initialValue:'red' is valid + Failed to execute 'registerProperty' on 'CSS': The syntax provided is not a valid custom property syntax. +[FAIL] syntax:'--foo+', initialValue:'--foo --foo' is valid + Failed to execute 'registerProperty' on 'CSS': The syntax provided is not a valid custom property syntax. +[FAIL] syntax:'--a | --b | --c', initialValue:'--b' is valid + Failed to execute 'registerProperty' on 'CSS': The syntax provided is not a valid custom property syntax. +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/register-property-syntax-parsing.html b/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/register-property-syntax-parsing.html index 1f9f1325..9043fcdf 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/register-property-syntax-parsing.html +++ b/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/register-property-syntax-parsing.html
@@ -10,6 +10,13 @@ let assert_valid = test_initial_value_valid; let assert_invalid = test_initial_value_invalid; +// Dashed idents as syntax component names (bug 1939501) +assert_valid("--foo", "--foo"); +assert_valid("--foo | <color>", "--foo"); +assert_valid("--foo | <color>", "red"); +assert_valid("--foo+", "--foo --foo"); +assert_valid("--a | --b | --c", "--b"); + assert_valid("*", "a"); assert_valid(" * ", "b"); assert_valid("<length>", "2px");
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/stretch/grid-item-height-001.html b/third_party/blink/web_tests/external/wpt/css/css-sizing/stretch/grid-item-height-001.html new file mode 100644 index 0000000..246687f0 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/stretch/grid-item-height-001.html
@@ -0,0 +1,31 @@ +<!DOCTYPE html> +<link rel="help" href="https://drafts.csswg.org/css-sizing-4/#stretch-fit-sizing"> +<script src='/resources/testharness.js'></script> +<script src='/resources/testharnessreport.js'></script> +<script src="/resources/check-layout-th.js"></script> +<meta name="assert" content="Checks the behaviour of height: stretch on grid items."> +<style> +.content { + width: 20px; + height: 20px; + background: lime; +} +</style> +<body onload="checkLayout('[data-expected-height]')"> + +<!-- Grid item with stretch in an indefinite-height grid with definite row tracks. + The grid area provides a definite height even though the grid container doesn't. --> +<div style="display: grid; grid-template-rows: 80px;"> + <div data-expected-height=80 style="height: stretch;"> + <div class=content></div> + </div> +</div> + +<!-- Grid item with stretch in an indefinite-height grid with auto row tracks. + The grid area height is indefinite, so stretch falls back to auto. --> +<div style="display: grid;"> + <div data-expected-height=20 style="height: stretch;"> + <div class=content></div> + </div> +</div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/container-name-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/container-name-expected.txt index c272ee2f..054c553 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/container-name-expected.txt +++ b/third_party/blink/web_tests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/container-name-expected.txt
@@ -1,7 +1,5 @@ This is a testharness.js-based test. [FAIL] Can set 'container-name' to the 'my-container' keyword: my-container Failed to execute 'set' on 'StylePropertyMap': Invalid type for property -[FAIL] 'container-type' does not support 'name1 name2' - assert_class_string: Unsupported value must be a CSSStyleValue and not one of its subclasses expected "[object CSSStyleValue]" but got "[object Undefined]" Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/container-name.html b/third_party/blink/web_tests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/container-name.html index 45d9cbc..420a830 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/container-name.html +++ b/third_party/blink/web_tests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/container-name.html
@@ -18,7 +18,7 @@ { syntax: 'my-container' }, ]); -runUnsupportedPropertyTests('container-type', [ +runUnsupportedPropertyTests('container-name', [ 'name1 name2' ]);
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/parsing/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/css/selectors/parsing/WEB_FEATURES.yml index a9f7cca..dc908b1f 100644 --- a/third_party/blink/web_tests/external/wpt/css/selectors/parsing/WEB_FEATURES.yml +++ b/third_party/blink/web_tests/external/wpt/css/selectors/parsing/WEB_FEATURES.yml
@@ -6,7 +6,6 @@ - '!parse-has.html' - '!parse-has-*' - '!parse-state.html' - - '!parse-has-slotted.tentative.html' - '!parse-not.html' - '!parse-part.html' - '!parse-heading.html' @@ -22,6 +21,7 @@ files: - parse-has.html - parse-has-* + - '!parse-has-slotted.tentative.html' - name: state files: - parse-state.html
diff --git a/third_party/blink/web_tests/external/wpt/dom/nodes/remove-next-sibling-during-replace-with.html b/third_party/blink/web_tests/external/wpt/dom/nodes/remove-next-sibling-during-replace-with.html new file mode 100644 index 0000000..46481c0e --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/dom/nodes/remove-next-sibling-during-replace-with.html
@@ -0,0 +1,15 @@ +<!DOCTYPE html> +<meta name="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<div id="container"><div id="target"></div><b></b></div> +<template><span>New </span><script>document.querySelector('b').remove();</script><span>content</span></template> + +<script> + test(() => { + target.replaceWith(document.querySelector('template').content.cloneNode(true)); + container.querySelector('script').remove(); + assert_equals(container.innerHTML, '<span>New </span><span>content</span>'); + }); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/fenced-frame/client-hints-meta.https.html b/third_party/blink/web_tests/external/wpt/fenced-frame/client-hints-meta.https.html deleted file mode 100644 index 7a370f45..0000000 --- a/third_party/blink/web_tests/external/wpt/fenced-frame/client-hints-meta.https.html +++ /dev/null
@@ -1,40 +0,0 @@ -<!DOCTYPE html> -<meta http-equiv="Accept-CH" - content="sec-ch-viewport-width"/> -<meta http-equiv="Feature-Policy" - content="ch-viewport-width *"/> -<title>Client hints in fenced frames test</title> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="/resources/testdriver.js"></script> -<script src="/resources/testdriver-vendor.js"></script> -<script src="resources/utils.js"></script> -<script src="resources/client-hints-common.sub.js"></script> -<script src="/common/get-host-info.sub.js"></script> -<script src="/common/utils.js"></script> -<script src="/common/dispatcher/dispatcher.js"></script> -<script src="/resources/testdriver-actions.js"></script> -<body> -<script> -promise_test(async () => { - const key = token(); - const url = generateURL('resources/client-hints-meta-inner.sub.https.html', [key]); - const remote_url = getRemoteOriginURL(url); - attachFencedFrame(remote_url); - const result = JSON.parse(await nextValueFromServer(key)); - - // We should not see client hints for the fenced frame root or subframes // - // within the fenced frame tree due to the reject-all permission policy used by - // fenced frames. - const headers = ['root-fenced-frame-headers', 'iframe-headers']; - const hints = [ - 'sec-ch-viewport-width', 'sec-ch-ua-mobile', - ]; - headers.forEach(header => { - hints.forEach(hint => { - assert_equals(result[header][hint], ''); - }); - }); -}, 'fenced frames not send client hints'); -</script> -</body>
diff --git a/third_party/blink/web_tests/external/wpt/fenced-frame/resources/client-hints-meta-iframe-inner.sub.https.html b/third_party/blink/web_tests/external/wpt/fenced-frame/resources/client-hints-meta-iframe-inner.sub.https.html deleted file mode 100644 index a195b28..0000000 --- a/third_party/blink/web_tests/external/wpt/fenced-frame/resources/client-hints-meta-iframe-inner.sub.https.html +++ /dev/null
@@ -1,14 +0,0 @@ -<!DOCTYPE html> -<meta http-equiv="Accept-CH" - content="sec-ch-viewport-width"/> -<meta http-equiv="Feature-Policy" - content="ch-viewport-width *"/> -<title>Client Hint Echoing Iframe</title> -<body> -<script> -window.parent.postMessage({'headers': { - 'sec-ch-viewport-width': '{{header_or_default(sec-ch-viewport-width, )}}', - 'sec-ch-ua-mobile': '{{header_or_default(sec-ch-ua-mobile, )}}', -}}, '*'); -</script> -</body>
diff --git a/third_party/blink/web_tests/external/wpt/fenced-frame/resources/client-hints-meta-iframe-inner.sub.https.html.headers b/third_party/blink/web_tests/external/wpt/fenced-frame/resources/client-hints-meta-iframe-inner.sub.https.html.headers deleted file mode 100644 index b7952e5d..0000000 --- a/third_party/blink/web_tests/external/wpt/fenced-frame/resources/client-hints-meta-iframe-inner.sub.https.html.headers +++ /dev/null
@@ -1,2 +0,0 @@ - -Supports-Loading-Mode: fenced-frame
diff --git a/third_party/blink/web_tests/external/wpt/fenced-frame/resources/client-hints-meta-inner.sub.https.html b/third_party/blink/web_tests/external/wpt/fenced-frame/resources/client-hints-meta-inner.sub.https.html deleted file mode 100644 index 6f215d04..0000000 --- a/third_party/blink/web_tests/external/wpt/fenced-frame/resources/client-hints-meta-inner.sub.https.html +++ /dev/null
@@ -1,30 +0,0 @@ -<!DOCTYPE html> -<meta http-equiv="Accept-CH" - content="sec-ch-viewport-width"/> -<meta http-equiv="Feature-Policy" - content="ch-viewport-width *"/> -<script src="/resources/testharness.js"></script> -<script src="utils.js"></script> -<title>Client Hints Helper</title> -<body> -<script type="module"> -const [key] = parseKeylist(); -let iframe = document.createElement('iframe'); -let p = new Promise((resolve, reject) => { - window.addEventListener('message', e => { - resolve(e.data); - }); -}); -iframe.src = 'client-hints-meta-iframe-inner.sub.https.html'; -document.body.appendChild(iframe); -const response = await p; -const result = { - 'root-fenced-frame-headers': { - 'sec-ch-viewport-width': '{{header_or_default(sec-ch-viewport-width, )}}', - 'sec-ch-ua-mobile': '{{header_or_default(sec-ch-ua-mobile, )}}', - }, - 'iframe-headers': response.headers, -}; -writeValueToServer(key, JSON.stringify(result)); -</script> -</body>
diff --git a/third_party/blink/web_tests/external/wpt/fenced-frame/resources/client-hints-meta-inner.sub.https.html.headers b/third_party/blink/web_tests/external/wpt/fenced-frame/resources/client-hints-meta-inner.sub.https.html.headers deleted file mode 100644 index afe7b4f3..0000000 --- a/third_party/blink/web_tests/external/wpt/fenced-frame/resources/client-hints-meta-inner.sub.https.html.headers +++ /dev/null
@@ -1,2 +0,0 @@ -Supports-Loading-Mode: fenced-frame -Access-Control-Allow-Origin: *
diff --git a/third_party/blink/web_tests/external/wpt/font-access/permissions-policy/local-fonts-supported-by-permissions-policy-expected.txt b/third_party/blink/web_tests/external/wpt/font-access/permissions-policy/local-fonts-supported-by-permissions-policy-expected.txt new file mode 100644 index 0000000..1a120ef2 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/font-access/permissions-policy/local-fonts-supported-by-permissions-policy-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] document.permissionsPolicy.features should advertise local-fonts. + Cannot read properties of undefined (reading 'features') +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/font-access/permissions-policy/local-fonts-supported-by-permissions-policy.html b/third_party/blink/web_tests/external/wpt/font-access/permissions-policy/local-fonts-supported-by-permissions-policy.html index 671c0fa..f6541d2 100644 --- a/third_party/blink/web_tests/external/wpt/font-access/permissions-policy/local-fonts-supported-by-permissions-policy.html +++ b/third_party/blink/web_tests/external/wpt/font-access/permissions-policy/local-fonts-supported-by-permissions-policy.html
@@ -6,6 +6,6 @@ <script src="/resources/testharnessreport.js"></script> <script> test(() => { - assert_in_array('local-fonts', document.featurePolicy.features()); - }, 'document.featurePolicy.features should advertise local-fonts.'); + assert_in_array('local-fonts', document.permissionsPolicy.features()); + }, 'document.permissionsPolicy.features should advertise local-fonts.'); </script> \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/gamepad/gamepad-default-permissions-policy.https.sub.html b/third_party/blink/web_tests/external/wpt/gamepad/gamepad-default-permissions-policy.https.sub.html index 062b741a..9ad3d4d 100644 --- a/third_party/blink/web_tests/external/wpt/gamepad/gamepad-default-permissions-policy.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/gamepad/gamepad-default-permissions-policy.https.sub.html
@@ -6,12 +6,12 @@ <script src=util/utils.js></script> <script> "use strict"; - const relative_path = "/gamepad/feature-policy-gamepad.html"; + const relative_path = "/gamepad/permissions-policy-gamepad.html"; const base_src = "/permissions-policy/resources/redirect-on-load.html#"; const sub = "https://{{domains[www]}}:{{ports[https][0]}}"; const same_origin_src = base_src + relative_path; const cross_origin_src = sub + relative_path; - const header = 'Feature-Policy allow="gamepad"'; + const header = 'Permissions-Policy allow="gamepad"'; async_test((t) => { test_feature_availability(
diff --git a/third_party/blink/web_tests/external/wpt/gamepad/feature-policy-gamepad.html b/third_party/blink/web_tests/external/wpt/gamepad/permissions-policy-gamepad.html similarity index 100% rename from third_party/blink/web_tests/external/wpt/gamepad/feature-policy-gamepad.html rename to third_party/blink/web_tests/external/wpt/gamepad/permissions-policy-gamepad.html
diff --git a/third_party/blink/web_tests/external/wpt/generic-sensor/generic-sensor-feature-policy-test.sub.js b/third_party/blink/web_tests/external/wpt/generic-sensor/generic-sensor-permissions-policy-test.sub.js similarity index 100% rename from third_party/blink/web_tests/external/wpt/generic-sensor/generic-sensor-feature-policy-test.sub.js rename to third_party/blink/web_tests/external/wpt/generic-sensor/generic-sensor-permissions-policy-test.sub.js
diff --git a/third_party/blink/web_tests/external/wpt/generic-sensor/generic-sensor-tests.js b/third_party/blink/web_tests/external/wpt/generic-sensor/generic-sensor-tests.js index 894fc7d..555896fe 100644 --- a/third_party/blink/web_tests/external/wpt/generic-sensor/generic-sensor-tests.js +++ b/third_party/blink/web_tests/external/wpt/generic-sensor/generic-sensor-tests.js
@@ -13,12 +13,12 @@ // Its length should match |readings|'. // |verificationFunction| is called to verify that a given reading matches a // value in |expectedReadings|. -// |featurePolicies| represents |sensorName|'s associated sensor feature name. +// |permissionsPolicyNames| represents |sensorName|'s associated sensor permissions policy names. function runGenericSensorTests(sensorData, readingData) { validate_sensor_data(sensorData); validate_reading_data(readingData); - const {sensorName, permissionName, testDriverName, featurePolicyNames} = + const {sensorName, permissionName, testDriverName, permissionsPolicyNames} = sensorData; const sensorType = self[sensorName]; @@ -155,7 +155,7 @@ sensor_test(async t => { const iframe = document.createElement('iframe'); - iframe.allow = featurePolicyNames.join(' \'none\'; ') + ' \'none\';'; + iframe.allow = permissionsPolicyNames.join(' \'none\'; ') + ' \'none\';'; iframe.srcdoc = '<script>' + ' window.onmessage = message => {' + ' if (message.data === "LOADED") {' + @@ -177,11 +177,11 @@ const message = await windowWatcher.wait_for('message'); assert_equals(message.data, 'PASS: got SecurityError'); }, `${sensorName}: Test that sensor cannot be constructed within iframe\ - disallowed to use feature policy.`); + disallowed to use permissions policy.`); sensor_test(async t => { const iframe = document.createElement('iframe'); - iframe.allow = featurePolicyNames.join(';') + ';'; + iframe.allow = permissionsPolicyNames.join(';') + ';'; iframe.srcdoc = '<script>' + ' window.onmessage = message => {' + ' if (message.data === "LOADED") {' + @@ -203,7 +203,7 @@ const message = await windowWatcher.wait_for('message'); assert_equals(message.data, 'PASS'); }, `${sensorName}: Test that sensor can be constructed within an iframe\ - allowed to use feature policy.`); + allowed to use permissions policy.`); sensor_test(async (t, readings, expectedReadings) => { await test_driver.bidi.permissions.set_permission(
diff --git a/third_party/blink/web_tests/external/wpt/generic-sensor/resources/generic-sensor-helpers.js b/third_party/blink/web_tests/external/wpt/generic-sensor/resources/generic-sensor-helpers.js index 146f4292..c135ea5 100644 --- a/third_party/blink/web_tests/external/wpt/generic-sensor/resources/generic-sensor-helpers.js +++ b/third_party/blink/web_tests/external/wpt/generic-sensor/resources/generic-sensor-helpers.js
@@ -76,9 +76,9 @@ if (!('testDriverName' in sensorData)) { throw new TypeError('sensorData.testDriverName is missing'); } - if (sensorData.featurePolicyNames !== undefined && - !Array.isArray(sensorData.featurePolicyNames)) { - throw new TypeError('sensorData.featurePolicyNames must be an array'); + if (sensorData.permissionsPolicyNames !== undefined && + !Array.isArray(sensorData.permissionsPolicyNames)) { + throw new TypeError('sensorData.permissionsPolicyNames must be an array'); } }
diff --git a/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-disabled-by-feature-policy.https-expected.txt b/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-disabled-by-feature-policy.https-expected.txt deleted file mode 100644 index 61adf8f3..0000000 --- a/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-disabled-by-feature-policy.https-expected.txt +++ /dev/null
@@ -1,7 +0,0 @@ -This is a testharness.js-based test. -[FAIL] Gyroscope: Permissions-Policy header gyroscope=() disallows same-origin iframes. - test_feature_availability is not defined -[FAIL] Gyroscope: Permissions-Policy header gyroscope=() disallows cross-origin iframes. - test_feature_availability is not defined -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-disabled-by-feature-policy.https.html b/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-disabled-by-feature-policy.https.html deleted file mode 100644 index d8dd8dc..0000000 --- a/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-disabled-by-feature-policy.https.html +++ /dev/null
@@ -1,13 +0,0 @@ -<!DOCTYPE html> -<body> -<title>Gyroscope Permissions Policy Test: Disabled</title> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="/feature-policy/resources/featurepolicy.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> -<script> -"use strict"; - -run_permissions_policy_tests_disabled('Gyroscope'); -</script> -</body>
diff --git a/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-disabled-by-feature-policy.https.html.headers b/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-disabled-by-feature-policy.https.html.headers deleted file mode 100644 index 3d91d58..0000000 --- a/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-disabled-by-feature-policy.https.html.headers +++ /dev/null
@@ -1 +0,0 @@ -Feature-Policy: gyroscope 'none'
diff --git a/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-disabled-by-permissions-policy.https.html b/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-disabled-by-permissions-policy.https.html index 1aa666b..6929299 100644 --- a/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-disabled-by-permissions-policy.https.html +++ b/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-disabled-by-permissions-policy.https.html
@@ -4,7 +4,7 @@ <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="/permissions-policy/resources/permissions-policy.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> +<script src="/generic-sensor/generic-sensor-permissions-policy-test.sub.js"></script> <script> "use strict";
diff --git a/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-enabled-by-feature-policy-attribute-redirect-on-load.https-expected.txt b/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-enabled-by-feature-policy-attribute-redirect-on-load.https-expected.txt deleted file mode 100644 index 2a10034..0000000 --- a/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-enabled-by-feature-policy-attribute-redirect-on-load.https-expected.txt +++ /dev/null
@@ -1,7 +0,0 @@ -This is a testharness.js-based test. -[FAIL] Gyroscope: Permissions-Policy allow='gyroscope' attribute allows same-origin relocation - test_feature_availability is not defined -[FAIL] Gyroscope: Permissions-Policy allow='gyroscope' attribute disallows cross-origin relocation - test_feature_availability is not defined -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-enabled-by-feature-policy-attribute-redirect-on-load.https.html b/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-enabled-by-feature-policy-attribute-redirect-on-load.https.html deleted file mode 100644 index 34e5700c..0000000 --- a/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-enabled-by-feature-policy-attribute-redirect-on-load.https.html +++ /dev/null
@@ -1,13 +0,0 @@ -<!DOCTYPE html> -<body> -<title>Gyroscope Permissions Policy Test: Enabled by attribute redirect on load</title> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="/feature-policy/resources/featurepolicy.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> -<script> -"use strict"; - -run_permissions_policy_tests_enabled_by_attribute_redirect_on_load('Gyroscope'); -</script> -</body>
diff --git a/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-enabled-by-feature-policy-attribute.https-expected.txt b/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-enabled-by-feature-policy-attribute.https-expected.txt deleted file mode 100644 index 83e406d..0000000 --- a/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-enabled-by-feature-policy-attribute.https-expected.txt +++ /dev/null
@@ -1,7 +0,0 @@ -This is a testharness.js-based test. -[FAIL] Gyroscope: Permissions-Policy allow='gyroscope' attribute allows same-origin iframe - test_feature_availability is not defined -[FAIL] Gyroscope: Permissions-Policy allow='gyroscope' attribute allows cross-origin iframe - test_feature_availability is not defined -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-enabled-by-feature-policy-attribute.https.html b/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-enabled-by-feature-policy-attribute.https.html deleted file mode 100644 index dfe318d5..0000000 --- a/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-enabled-by-feature-policy-attribute.https.html +++ /dev/null
@@ -1,13 +0,0 @@ -<!DOCTYPE html> -<body> -<title>Gyroscope Permissions Policy Test: Enabled by attribute</title> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="/feature-policy/resources/featurepolicy.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> -<script> -"use strict"; - -run_permissions_policy_tests_enabled_by_attribute('Gyroscope'); -</script> -</body>
diff --git a/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-enabled-by-feature-policy.https-expected.txt b/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-enabled-by-feature-policy.https-expected.txt deleted file mode 100644 index 390cd8e..0000000 --- a/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-enabled-by-feature-policy.https-expected.txt +++ /dev/null
@@ -1,7 +0,0 @@ -This is a testharness.js-based test. -[FAIL] Gyroscope: Permissions-Policy header gyroscope=* allows same-origin iframes. - test_feature_availability is not defined -[FAIL] Gyroscope: Permissions-Policy header gyroscope=* allows cross-origin iframes. - test_feature_availability is not defined -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-enabled-by-feature-policy.https.html b/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-enabled-by-feature-policy.https.html deleted file mode 100644 index 2c36d41..0000000 --- a/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-enabled-by-feature-policy.https.html +++ /dev/null
@@ -1,13 +0,0 @@ -<!DOCTYPE html> -<body> -<title>Gyroscope Permissions Policy Test: Enabled</title> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="/feature-policy/resources/featurepolicy.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> -<script> -"use strict"; - -run_permissions_policy_tests_enabled('Gyroscope'); -</script> -</body>
diff --git a/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-enabled-by-feature-policy.https.html.headers b/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-enabled-by-feature-policy.https.html.headers deleted file mode 100644 index 0fd938b..0000000 --- a/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-enabled-by-feature-policy.https.html.headers +++ /dev/null
@@ -1 +0,0 @@ -Feature-Policy: gyroscope *
diff --git a/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-enabled-by-permissions-policy-attribute-redirect-on-load.https.html b/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-enabled-by-permissions-policy-attribute-redirect-on-load.https.html index 54193e05..a94f1152 100644 --- a/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-enabled-by-permissions-policy-attribute-redirect-on-load.https.html +++ b/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-enabled-by-permissions-policy-attribute-redirect-on-load.https.html
@@ -4,7 +4,7 @@ <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="/permissions-policy/resources/permissions-policy.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> +<script src="/generic-sensor/generic-sensor-permissions-policy-test.sub.js"></script> <script> "use strict";
diff --git a/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-enabled-by-permissions-policy-attribute.https.html b/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-enabled-by-permissions-policy-attribute.https.html index cfaae59..8712b21 100644 --- a/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-enabled-by-permissions-policy-attribute.https.html +++ b/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-enabled-by-permissions-policy-attribute.https.html
@@ -4,7 +4,7 @@ <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="/permissions-policy/resources/permissions-policy.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> +<script src="/generic-sensor/generic-sensor-permissions-policy-test.sub.js"></script> <script> "use strict";
diff --git a/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-enabled-by-permissions-policy.https.html b/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-enabled-by-permissions-policy.https.html index ec35eaba..d501ad8 100644 --- a/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-enabled-by-permissions-policy.https.html +++ b/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-enabled-by-permissions-policy.https.html
@@ -4,7 +4,7 @@ <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="/permissions-policy/resources/permissions-policy.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> +<script src="/generic-sensor/generic-sensor-permissions-policy-test.sub.js"></script> <script> "use strict";
diff --git a/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-enabled-on-self-origin-by-feature-policy.https-expected.txt b/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-enabled-on-self-origin-by-feature-policy.https-expected.txt deleted file mode 100644 index 4c527575..0000000 --- a/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-enabled-on-self-origin-by-feature-policy.https-expected.txt +++ /dev/null
@@ -1,7 +0,0 @@ -This is a testharness.js-based test. -[FAIL] Gyroscope: Permissions-Policy header gyroscope=(self) allows same-origin iframes. - test_feature_availability is not defined -[FAIL] Gyroscope: Permissions-Policy header gyroscope=(self) disallows cross-origin iframes. - test_feature_availability is not defined -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-enabled-on-self-origin-by-feature-policy.https.html b/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-enabled-on-self-origin-by-feature-policy.https.html deleted file mode 100644 index 8e789c18..0000000 --- a/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-enabled-on-self-origin-by-feature-policy.https.html +++ /dev/null
@@ -1,13 +0,0 @@ -<!DOCTYPE html> -<body> -<title>Gyroscope Permissions Policy Test: Enabled on self origin</title> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="/feature-policy/resources/featurepolicy.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> -<script> -"use strict"; - -run_permissions_policy_tests_enabled_on_self_origin('Gyroscope'); -</script> -</body>
diff --git a/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-enabled-on-self-origin-by-feature-policy.https.html.headers b/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-enabled-on-self-origin-by-feature-policy.https.html.headers deleted file mode 100644 index 7cf4fd8..0000000 --- a/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-enabled-on-self-origin-by-feature-policy.https.html.headers +++ /dev/null
@@ -1 +0,0 @@ -Feature-Policy: gyroscope 'self'
diff --git a/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-enabled-on-self-origin-by-permissions-policy.https.html b/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-enabled-on-self-origin-by-permissions-policy.https.html index f0e3366..6984ef5 100644 --- a/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-enabled-on-self-origin-by-permissions-policy.https.html +++ b/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-enabled-on-self-origin-by-permissions-policy.https.html
@@ -4,7 +4,7 @@ <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="/permissions-policy/resources/permissions-policy.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> +<script src="/generic-sensor/generic-sensor-permissions-policy-test.sub.js"></script> <script> "use strict";
diff --git a/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-iframe-access.https.html b/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-iframe-access.https.html index 9856006d..6c45842 100644 --- a/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-iframe-access.https.html +++ b/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-iframe-access.https.html
@@ -10,7 +10,7 @@ <script src="/resources/testdriver-vendor.js"></script> <script src="/generic-sensor/resources/generic-sensor-helpers.js"></script> <script src="/generic-sensor/generic-sensor-iframe-tests.sub.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> +<script src="/generic-sensor/generic-sensor-permissions-policy-test.sub.js"></script> <script src="resources/sensor-data.js"></script> <div id="log"></div> <script>
diff --git a/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-supported-by-feature-policy.html b/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-supported-by-feature-policy.html deleted file mode 100644 index 06a4137..0000000 --- a/third_party/blink/web_tests/external/wpt/gyroscope/Gyroscope-supported-by-feature-policy.html +++ /dev/null
@@ -1,11 +0,0 @@ -<!DOCTYPE html> -<title>Test that gyroscope is advertised in the feature list</title> -<link rel="help" href="https://w3c.github.io/webappsec-feature-policy/#dom-featurepolicy-features"> -<link rel="help" href="https://w3c.github.io/sensors/#feature-policy-api"> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script> -test(() => { - assert_in_array('gyroscope', document.featurePolicy.features()); -}, 'document.featurePolicy.features should advertise gyroscope.'); -</script>
diff --git a/third_party/blink/web_tests/external/wpt/gyroscope/resources/sensor-data.js b/third_party/blink/web_tests/external/wpt/gyroscope/resources/sensor-data.js index 409ffef9..9b25665f0 100644 --- a/third_party/blink/web_tests/external/wpt/gyroscope/resources/sensor-data.js +++ b/third_party/blink/web_tests/external/wpt/gyroscope/resources/sensor-data.js
@@ -4,7 +4,7 @@ sensorName: 'Gyroscope', permissionName: 'gyroscope', testDriverName: 'gyroscope', - featurePolicyNames: ['gyroscope'] + permissionsPolicyNames: ['gyroscope'] }; // Due to the gyroscope input values being rounded using a precision of
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/scroll-to-fragid/resources/scroll-restore-on-reload-non-ascii-fragment-target.html b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/scroll-to-fragid/resources/scroll-restore-on-reload-non-ascii-fragment-target.html new file mode 100644 index 0000000..94f3923 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/scroll-to-fragid/resources/scroll-restore-on-reload-non-ascii-fragment-target.html
@@ -0,0 +1,10 @@ +<!doctype html> +<meta charset=utf-8> +<style> + .spacer { height: 200vh; } +</style> +<div class="spacer"></div> +<div id="ascii">ASCII anchor</div> +<div class="spacer"></div> +<div id="䏿–‡">Non-ASCII anchor</div> +<div class="spacer"></div>
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/scroll-to-fragid/scroll-restore-on-reload-non-ascii-fragment.html b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/scroll-to-fragid/scroll-restore-on-reload-non-ascii-fragment.html new file mode 100644 index 0000000..8aa726c --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/scroll-to-fragid/scroll-restore-on-reload-non-ascii-fragment.html
@@ -0,0 +1,58 @@ +<!doctype html> +<title>Reload preserves scroll position for non-ASCII fragment</title> +<meta name=timeout content=long> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<body> +<script> +// Regression test: reloading a page with a non-ASCII fragment identifier +// should preserve the scroll position, just like it does for ASCII fragments. + +function waitForLoad(iframe) { + return new Promise(resolve => { + iframe.addEventListener("load", resolve, { once: true }); + }); +} + +async function testScrollRestoreOnReload(fragment, description) { + const iframe = document.createElement("iframe"); + iframe.style.width = "300px"; + iframe.style.height = "300px"; + document.body.appendChild(iframe); + + const url = "resources/scroll-restore-on-reload-non-ascii-fragment-target.html#" + fragment; + iframe.src = url; + await waitForLoad(iframe); + + const win = iframe.contentWindow; + + // Verify we scrolled to the fragment. + assert_greater_than(win.scrollY, 0, "should have scrolled to the fragment"); + + // Scroll to the top. + win.scrollTo(0, 0); + assert_equals(win.scrollY, 0, "should be at the top after scrollTo"); + + // Reload and wait for load. + const loadPromise = waitForLoad(iframe); + win.location.reload(); + await loadPromise; + + // After reload, scroll position should be restored (to the top, where we + // scrolled before reloading), NOT scrolled back to the fragment. + assert_equals(iframe.contentWindow.scrollY, 0, + "scroll position should be preserved after reload, not scrolled to fragment"); + + iframe.remove(); +} + +promise_test(async t => { + await testScrollRestoreOnReload("ascii", "ASCII fragment"); +}, "Reload preserves scroll position for ASCII fragment"); + +promise_test(async t => { + await testScrollRestoreOnReload(encodeURIComponent("\u4e2d\u6587"), "non-ASCII fragment"); +}, "Reload preserves scroll position for non-ASCII fragment"); +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/media-elements/autoplay-allowed-by-permissions-policy-attribute-redirect-on-load.https.sub.html b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/media-elements/autoplay-allowed-by-permissions-policy-attribute-redirect-on-load.https.sub.html index 417fc50..ef064ad 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/media-elements/autoplay-allowed-by-permissions-policy-attribute-redirect-on-load.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/media-elements/autoplay-allowed-by-permissions-policy-attribute-redirect-on-load.https.sub.html
@@ -14,7 +14,7 @@ const same_origin_src = base_src + relative_path; const cross_origin_src = base_src + 'https://{{domains[www]}}:{{ports[https][0]}}' + relative_path; - const header = 'Feature-Policy allow="autoplay"'; + const header = 'Permissions-Policy allow="autoplay"'; async_test(t => { simulateGesture(t, () => {
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/media-elements/autoplay-allowed-by-permissions-policy.https.sub.html b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/media-elements/autoplay-allowed-by-permissions-policy.https.sub.html index 5d3d252b..ae810b14 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/media-elements/autoplay-allowed-by-permissions-policy.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/media-elements/autoplay-allowed-by-permissions-policy.https.sub.html
@@ -12,7 +12,7 @@ const same_origin_src = '/permissions-policy/resources/permissions-policy-autoplay.html'; const cross_origin_src = 'https://{{domains[www]}}:{{ports[https][0]}}' + same_origin_src; - const header = 'Feature-Policy header: autoplay *'; + const header = 'Permissions-Policy header: autoplay *'; async_test(t => { simulateGesture(t, () => {
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/media-elements/autoplay-disabled-by-permissions-policy.https.sub.html b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/media-elements/autoplay-disabled-by-permissions-policy.https.sub.html index 3f5f530..a668849 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/media-elements/autoplay-disabled-by-permissions-policy.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/media-elements/autoplay-disabled-by-permissions-policy.https.sub.html
@@ -12,7 +12,7 @@ const same_origin_src = '/permissions-policy/resources/permissions-policy-autoplay.html'; const cross_origin_src = 'https://{{domains[www]}}:{{ports[https][0]}}' + same_origin_src; - const header = 'Feature-Policy header: autoplay "none"'; + const header = 'Permissions-Policy header: autoplay "none"'; async_test(t => { simulateGesture(t, () => {
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-iframe-element/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-iframe-element/WEB_FEATURES.yml index 7cae7ee0..ec2f814 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-iframe-element/WEB_FEATURES.yml +++ b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-iframe-element/WEB_FEATURES.yml
@@ -2,6 +2,7 @@ - name: loading-lazy files: - iframe-loading-lazy* + - "!iframe-loading-lazy-base-url*" - name: base files: - iframe-loading-lazy-base-url* @@ -22,7 +23,6 @@ files: - "*" - "!iframe-loading-lazy*" - - "!iframe-loading-lazy-base-url*" - "!iframe-with-base.html" - "!srcdoc*" - "!iframe_sandbox_*"
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-iframe-element/same-origin-contextual-fragment.html b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-iframe-element/same-origin-contextual-fragment.html new file mode 100644 index 0000000..9ac407b4f --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-iframe-element/same-origin-contextual-fragment.html
@@ -0,0 +1,38 @@ +<!doctype html> +<html> + <head> + <title> + HTML5 Sandbox: an iframe with same-origin and no allow-scripts does not + run scripts from a contextual fragment. + </title> + <meta content="text/html; charset=UTF-8" http-equiv="Content-Type" /> + <link + rel="help" + href="http://dev.w3.org/html5/spec/Overview.html#attr-iframe-sandbox" + /> + <meta + name="assert" + content="an iframe with same-origin and no allow-scripts does not run scripts from a contextual fragment." + /> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script type="text/javascript"> + test((t) => { + const iframe = document.createElement("iframe"); + iframe.sandbox = "allow-same-origin"; + document.body.appendChild(iframe); + const doc = iframe.contentDocument; + const html = + `<script>window.did_run_script = true</` + + `script><noscript><div id=nos></div>`; + iframe.contentWindow.did_run_script = false; + const fragment = doc.createRange().createContextualFragment(html); + doc.body.appendChild(fragment); + assert_false(iframe.contentWindow.did_run_script); + assert_not_equals(doc.getElementById("nos"), null); + }); + </script> + </body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/WEB_FEATURES.yml index c87bd96a..837d826 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/WEB_FEATURES.yml +++ b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/WEB_FEATURES.yml
@@ -15,7 +15,6 @@ - "!document-adopt-base-url.html" - "!document-base-url.html" - "!image-base-url.html" - - "!image-loading-lazy-base-url.html" # Exclude `srcset`. Keep in sync with `srcset` mappings below. - "!responsive-image-select-print.html" - "!update-the-source-set.html" @@ -31,6 +30,7 @@ - relevant-mutations-lazy.html - remove-element-and-scroll.html - scrolling-below-viewport-image-lazy-loading-in-iframe.html + - "!image-loading-lazy-base-url.html" - name: base files: # Keep in sync with `img` mappings.
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-select-element/customizable-select/select-picker-pseudo-target-text.html b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-select-element/customizable-select/select-picker-pseudo-target-text.html index 02159e7e..8e008fc4 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-select-element/customizable-select/select-picker-pseudo-target-text.html +++ b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-select-element/customizable-select/select-picker-pseudo-target-text.html
@@ -26,12 +26,12 @@ </select> <script> -window.location.hash = "#:~:text=Hello"; - (async () => { await test_driver.bless(); document.querySelector("select").showPicker(); await new Promise(requestAnimationFrame); + window.location.hash = "#:~:text=Hello"; + await new Promise(r => requestAnimationFrame(() => requestAnimationFrame(r))); document.documentElement.classList.remove("reftest-wait"); })(); </script>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/interactive-elements/the-details-element/details-name-exclusivity-fragment-insertion.html b/third_party/blink/web_tests/external/wpt/html/semantics/interactive-elements/the-details-element/details-name-exclusivity-fragment-insertion.html new file mode 100644 index 0000000..2558458 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/semantics/interactive-elements/the-details-element/details-name-exclusivity-fragment-insertion.html
@@ -0,0 +1,108 @@ +<!DOCTYPE html> +<html> +<head> +<meta name="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org"> +<link rel="help" href="https://html.spec.whatwg.org/multipage/interactive-elements.html#the-details-element"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<script> + +test(() => { + + const container = document.createElement("div"); + document.body.appendChild(container); + + const fragment = document.createDocumentFragment(); + + const details1 = document.createElement("details"); + details1.setAttribute("name", "group"); + details1.setAttribute("open", ""); + details1.textContent = "Details 1"; + fragment.appendChild(details1); + + const details2 = document.createElement("details"); + details2.setAttribute("name", "group"); + details2.setAttribute("open", ""); + details2.textContent = "Details 2"; + fragment.appendChild(details2); + + container.appendChild(fragment); + + // Exactly one should remain open. The first in tree order keeps its open + // attribute; later ones see the conflict during post-insertion steps and + // close themselves. + let openCount = 0; + if (details1.hasAttribute("open")) + openCount++; + if (details2.hasAttribute("open")) + openCount++; + + assert_equals(openCount, 1); + assert_true(details1.hasAttribute('open')); + assert_false(details2.hasAttribute('open')); + + // Also test with three open details in a fragment. + const container2 = document.createElement("div"); + document.body.appendChild(container2); + + const fragment2 = document.createDocumentFragment(); + + const detailsA = document.createElement("details"); + detailsA.setAttribute("name", "group2"); + detailsA.setAttribute("open", ""); + fragment2.appendChild(detailsA); + + const detailsB = document.createElement("details"); + detailsB.setAttribute("name", "group2"); + detailsB.setAttribute("open", ""); + fragment2.appendChild(detailsB); + + const detailsC = document.createElement("details"); + detailsC.setAttribute("name", "group2"); + detailsC.setAttribute("open", ""); + fragment2.appendChild(detailsC); + + container2.appendChild(fragment2); + + openCount = 0; + if (detailsA.hasAttribute("open")) + openCount++; + if (detailsB.hasAttribute("open")) + openCount++; + if (detailsC.hasAttribute("open")) + openCount++; + + assert_equals(openCount, 1); + assert_true(detailsA.hasAttribute('open')); + + // Test inserting into a container that already has an open details with the same name. + const container3 = document.createElement("div"); + document.body.appendChild(container3); + + const existing = document.createElement("details"); + existing.setAttribute("name", "group3"); + existing.setAttribute("open", ""); + container3.appendChild(existing); + + const fragment3 = document.createDocumentFragment(); + + const detailsD = document.createElement("details"); + detailsD.setAttribute("name", "group3"); + detailsD.setAttribute("open", ""); + fragment3.appendChild(detailsD); + + container3.appendChild(fragment3); + + assert_false(detailsD.hasAttribute('open')); + assert_true(existing.hasAttribute('open')); + + container.remove(); + container2.remove(); + container3.remove(); +}, "Test that inserting two open details elements with the same name via DocumentFragment results in exactly one being open."); + +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/execution-timing/148-expected.txt b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/execution-timing/148-expected.txt deleted file mode 100644 index ba5676d67..0000000 --- a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/execution-timing/148-expected.txt +++ /dev/null
@@ -1,5 +0,0 @@ -This is a testharness.js-based test. -[FAIL] scheduler: insert multiple inline scripts; first script deletes subsequent script - assert_array_equals: lengths differ, expected array ["inline script #1", "inline script #2", "inline script #3", "inline script #4"] length 4, got ["inline script #1", "inline script #2", "inline script #4"] length 3 -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/execution-timing/148.html b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/execution-timing/148.html index e2da8e8f..992f019 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/execution-timing/148.html +++ b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/execution-timing/148.html
@@ -32,7 +32,7 @@ }); onload = t.step_func(function() { - assert_array_equals(eventOrder, ["inline script #1", "inline script #2", "inline script #3", "inline script #4"]); + assert_array_equals(eventOrder, ["inline script #1", "inline script #2", "inline script #4"]); t.done(); }); </script>
diff --git a/third_party/blink/web_tests/external/wpt/idle-detection/idle-detection-allowed-by-permissions-policy.https.sub.html b/third_party/blink/web_tests/external/wpt/idle-detection/idle-detection-allowed-by-permissions-policy.https.sub.html index 6fae367..410b857 100644 --- a/third_party/blink/web_tests/external/wpt/idle-detection/idle-detection-allowed-by-permissions-policy.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/idle-detection/idle-detection-allowed-by-permissions-policy.https.sub.html
@@ -18,6 +18,8 @@ promise_setup(async () => { await test_driver.set_permission({ name: 'idle-detection' }, 'granted'); + await fetch_tests_from_worker(new Worker( + 'resources/idle-detection-allowed-by-permissions-policy-worker.js')); }); promise_test(async t => { @@ -50,8 +52,5 @@ }, 'Permissions-Policy idle-detection=* explicity set by top-level ' + 'frame allows workers in cross-origin iframes.'); -fetch_tests_from_worker(new Worker( - 'resources/idle-detection-allowed-by-permissions-policy-worker.js')) - </script> </body>
diff --git a/third_party/blink/web_tests/external/wpt/idle-detection/resources/idle-detection-allowed-by-permissions-policy-worker.js b/third_party/blink/web_tests/external/wpt/idle-detection/resources/idle-detection-allowed-by-permissions-policy-worker.js index 1fe410e..1c45c30c 100644 --- a/third_party/blink/web_tests/external/wpt/idle-detection/resources/idle-detection-allowed-by-permissions-policy-worker.js +++ b/third_party/blink/web_tests/external/wpt/idle-detection/resources/idle-detection-allowed-by-permissions-policy-worker.js
@@ -2,6 +2,10 @@ importScripts('/resources/testharness.js'); +setup(function() { + assert_true(typeof IdleDetector !== 'undefined', 'IdleDetector must be defined'); +}); + let workerType; if (typeof postMessage === 'function') {
diff --git a/third_party/blink/web_tests/external/wpt/largest-contentful-paint/broken-image-icon-expected.txt b/third_party/blink/web_tests/external/wpt/largest-contentful-paint/broken-image-icon-expected.txt new file mode 100644 index 0000000..177669c10 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/largest-contentful-paint/broken-image-icon-expected.txt
@@ -0,0 +1,4 @@ +This is a testharness.js-based test. +Harness Error. harness_status.status = 1 , harness_status.message = Uncaught Error: assert_equals: Got LCP entry from colors-16x8.png. expected 1 but got 0 +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/largest-contentful-paint/broken-image-icon.html b/third_party/blink/web_tests/external/wpt/largest-contentful-paint/broken-image-icon.html index 8ca55b41..e27e3281 100644 --- a/third_party/blink/web_tests/external/wpt/largest-contentful-paint/broken-image-icon.html +++ b/third_party/blink/web_tests/external/wpt/largest-contentful-paint/broken-image-icon.html
@@ -9,7 +9,7 @@ <body> <img src="../non-existent-image.jpg"> - <img src="/css/css-images/support/colors-16x8.png"> + <img src="/css/css-images/support/colors-16x8.png?pipe=trickle(d2)"> <script> promise_test(async () => {
diff --git a/third_party/blink/web_tests/external/wpt/lint.ignore b/third_party/blink/web_tests/external/wpt/lint.ignore index a7c03c5..4620815 100644 --- a/third_party/blink/web_tests/external/wpt/lint.ignore +++ b/third_party/blink/web_tests/external/wpt/lint.ignore
@@ -408,7 +408,6 @@ SET TIMEOUT: css/css-fonts/font-display/font-display-preload.html SET TIMEOUT: css/css-view-transitions/no-painting-while-render-blocked.html SET TIMEOUT: document-policy/font-display/override-to-optional.tentative.html -SET TIMEOUT: feature-policy/experimental-features/resources/focus-without-user-activation-iframe-tentative.html SET TIMEOUT: geolocation/watchposition-timeout.https.window.js SET TIMEOUT: permissions-policy/experimental-features/resources/focus-without-user-activation-iframe-tentative.html SET TIMEOUT: html/browsers/windows/auxiliary-browsing-contexts/resources/close-opener.html
diff --git a/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-disabled-by-feature-policy.https-expected.txt b/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-disabled-by-feature-policy.https-expected.txt deleted file mode 100644 index 1f265cd..0000000 --- a/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-disabled-by-feature-policy.https-expected.txt +++ /dev/null
@@ -1,9 +0,0 @@ -This is a testharness.js-based test. -[FAIL] UncalibratedMagnetometer: Feature-Policy header magnetometer 'none' disallows the top-level document. - assert_implements: UncalibratedMagnetometer is not supported. undefined -[FAIL] UncalibratedMagnetometer: Feature-Policy header magnetometer 'none' disallows same-origin iframes. - assert_implements: UncalibratedMagnetometer is not supported. undefined -[FAIL] UncalibratedMagnetometer: Feature-Policy header magnetometer 'none' disallows cross-origin iframes. - assert_implements: UncalibratedMagnetometer is not supported. undefined -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-disabled-by-feature-policy.https.html b/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-disabled-by-feature-policy.https.html deleted file mode 100644 index 33ece4e..0000000 --- a/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-disabled-by-feature-policy.https.html +++ /dev/null
@@ -1,14 +0,0 @@ -<!DOCTYPE html> -<body> -<title>Magnetometer Permissions Policy Test: Disabled</title> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="/feature-policy/resources/featurepolicy.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> -<script> -"use strict"; - -run_permissions_policy_tests_disabled('Magnetometer'); -run_permissions_policy_tests_disabled('UncalibratedMagnetometer'); -</script> -</body>
diff --git a/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-disabled-by-feature-policy.https.html.headers b/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-disabled-by-feature-policy.https.html.headers deleted file mode 100644 index afbd4546..0000000 --- a/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-disabled-by-feature-policy.https.html.headers +++ /dev/null
@@ -1 +0,0 @@ -Feature-Policy: magnetometer 'none'
diff --git a/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-disabled-by-permissions-policy.https.html b/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-disabled-by-permissions-policy.https.html index 2dac0031..9b9cb8d 100644 --- a/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-disabled-by-permissions-policy.https.html +++ b/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-disabled-by-permissions-policy.https.html
@@ -4,7 +4,7 @@ <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="/permissions-policy/resources/permissions-policy.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> +<script src="/generic-sensor/generic-sensor-permissions-policy-test.sub.js"></script> <script> "use strict";
diff --git a/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-enabled-by-feature-policy-attribute-redirect-on-load.https-expected.txt b/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-enabled-by-feature-policy-attribute-redirect-on-load.https-expected.txt deleted file mode 100644 index 6ae2ba9..0000000 --- a/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-enabled-by-feature-policy-attribute-redirect-on-load.https-expected.txt +++ /dev/null
@@ -1,7 +0,0 @@ -This is a testharness.js-based test. -[FAIL] UncalibratedMagnetometer: Feature-Policy allow='magnetometer' attribute allows same-origin relocation - assert_implements: UncalibratedMagnetometer is not supported. undefined -[FAIL] UncalibratedMagnetometer: Feature-Policy allow='magnetometer' attribute disallows cross-origin relocation - assert_implements: UncalibratedMagnetometer is not supported. undefined -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-enabled-by-feature-policy-attribute-redirect-on-load.https.html b/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-enabled-by-feature-policy-attribute-redirect-on-load.https.html deleted file mode 100644 index bcd3f1a..0000000 --- a/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-enabled-by-feature-policy-attribute-redirect-on-load.https.html +++ /dev/null
@@ -1,14 +0,0 @@ -<!DOCTYPE html> -<body> -<title>Magnetometer Permissions Policy Test: Enabled by attribute redirect on load</title> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="/feature-policy/resources/featurepolicy.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> -<script> -"use strict"; - -run_permissions_policy_tests_enabled_by_attribute_redirect_on_load('Magnetometer'); -run_permissions_policy_tests_enabled_by_attribute_redirect_on_load('UncalibratedMagnetometer'); -</script> -</body>
diff --git a/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-enabled-by-feature-policy-attribute.https-expected.txt b/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-enabled-by-feature-policy-attribute.https-expected.txt deleted file mode 100644 index 4749b53..0000000 --- a/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-enabled-by-feature-policy-attribute.https-expected.txt +++ /dev/null
@@ -1,7 +0,0 @@ -This is a testharness.js-based test. -[FAIL] UncalibratedMagnetometer: Feature-Policy allow='magnetometer' attribute allows same-origin iframe - assert_implements: UncalibratedMagnetometer is not supported. undefined -[FAIL] UncalibratedMagnetometer: Feature-Policy allow='magnetometer' attribute allows cross-origin iframe - assert_implements: UncalibratedMagnetometer is not supported. undefined -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-enabled-by-feature-policy-attribute.https.html b/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-enabled-by-feature-policy-attribute.https.html deleted file mode 100644 index c8bb992..0000000 --- a/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-enabled-by-feature-policy-attribute.https.html +++ /dev/null
@@ -1,14 +0,0 @@ -<!DOCTYPE html> -<body> -<title>Magnetometer Permissions Policy Test: Enabled by attribute</title> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="/feature-policy/resources/featurepolicy.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> -<script> -"use strict"; - -run_permissions_policy_tests_enabled_by_attribute('Magnetometer'); -run_permissions_policy_tests_enabled_by_attribute('UncalibratedMagnetometer'); -</script> -</body>
diff --git a/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-enabled-by-feature-policy.https-expected.txt b/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-enabled-by-feature-policy.https-expected.txt deleted file mode 100644 index ac7f332..0000000 --- a/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-enabled-by-feature-policy.https-expected.txt +++ /dev/null
@@ -1,9 +0,0 @@ -This is a testharness.js-based test. -[FAIL] UncalibratedMagnetometer: Feature-Policy header magnetometer * allows the top-level document. - assert_implements: UncalibratedMagnetometer is not supported. undefined -[FAIL] UncalibratedMagnetometer: Feature-Policy header magnetometer * allows same-origin iframes. - assert_implements: UncalibratedMagnetometer is not supported. undefined -[FAIL] UncalibratedMagnetometer: Feature-Policy header magnetometer * allows cross-origin iframes. - assert_implements: UncalibratedMagnetometer is not supported. undefined -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-enabled-by-feature-policy.https.html b/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-enabled-by-feature-policy.https.html deleted file mode 100644 index 635572a0..0000000 --- a/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-enabled-by-feature-policy.https.html +++ /dev/null
@@ -1,14 +0,0 @@ -<!DOCTYPE html> -<body> -<title>Magnetometer Permissions Policy Test: Enabled</title> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="/feature-policy/resources/featurepolicy.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> -<script> -"use strict"; - -run_permissions_policy_tests_enabled('Magnetometer'); -run_permissions_policy_tests_enabled('UncalibratedMagnetometer'); -</script> -</body>
diff --git a/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-enabled-by-feature-policy.https.html.headers b/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-enabled-by-feature-policy.https.html.headers deleted file mode 100644 index 64ec55e..0000000 --- a/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-enabled-by-feature-policy.https.html.headers +++ /dev/null
@@ -1 +0,0 @@ -Feature-Policy: magnetometer *
diff --git a/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-enabled-by-permissions-policy-attribute-redirect-on-load.https.html b/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-enabled-by-permissions-policy-attribute-redirect-on-load.https.html index a41653c..a26a904af 100644 --- a/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-enabled-by-permissions-policy-attribute-redirect-on-load.https.html +++ b/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-enabled-by-permissions-policy-attribute-redirect-on-load.https.html
@@ -4,7 +4,7 @@ <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="/permissions-policy/resources/permissions-policy.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> +<script src="/generic-sensor/generic-sensor-permissions-policy-test.sub.js"></script> <script> "use strict";
diff --git a/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-enabled-by-permissions-policy-attribute.https.html b/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-enabled-by-permissions-policy-attribute.https.html index 1936468..d307abcc 100644 --- a/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-enabled-by-permissions-policy-attribute.https.html +++ b/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-enabled-by-permissions-policy-attribute.https.html
@@ -4,7 +4,7 @@ <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="/permissions-policy/resources/permissions-policy.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> +<script src="/generic-sensor/generic-sensor-permissions-policy-test.sub.js"></script> <script> "use strict";
diff --git a/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-enabled-by-permissions-policy.https.html b/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-enabled-by-permissions-policy.https.html index ff658c7..7e7aeeca 100644 --- a/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-enabled-by-permissions-policy.https.html +++ b/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-enabled-by-permissions-policy.https.html
@@ -4,7 +4,7 @@ <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="/permissions-policy/resources/permissions-policy.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> +<script src="/generic-sensor/generic-sensor-permissions-policy-test.sub.js"></script> <script> "use strict";
diff --git a/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-enabled-on-self-origin-by-feature-policy.https-expected.txt b/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-enabled-on-self-origin-by-feature-policy.https-expected.txt deleted file mode 100644 index 68c1f74..0000000 --- a/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-enabled-on-self-origin-by-feature-policy.https-expected.txt +++ /dev/null
@@ -1,9 +0,0 @@ -This is a testharness.js-based test. -[FAIL] UncalibratedMagnetometer: Feature-Policy header magnetometer 'self' allows the top-level document. - assert_implements: UncalibratedMagnetometer is not supported. undefined -[FAIL] UncalibratedMagnetometer: Feature-Policy header magnetometer 'self' allows same-origin iframes. - assert_implements: UncalibratedMagnetometer is not supported. undefined -[FAIL] UncalibratedMagnetometer: Feature-Policy header magnetometer 'self' disallows cross-origin iframes. - assert_implements: UncalibratedMagnetometer is not supported. undefined -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-enabled-on-self-origin-by-feature-policy.https.html b/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-enabled-on-self-origin-by-feature-policy.https.html deleted file mode 100644 index 666b64c..0000000 --- a/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-enabled-on-self-origin-by-feature-policy.https.html +++ /dev/null
@@ -1,14 +0,0 @@ -<!DOCTYPE html> -<body> -<title>Magnetometer Permissions Policy Test: Enabled on self origin</title> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="/feature-policy/resources/featurepolicy.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> -<script> -"use strict"; - -run_permissions_policy_tests_enabled_on_self_origin('Magnetometer'); -run_permissions_policy_tests_enabled_on_self_origin('UncalibratedMagnetometer'); -</script> -</body>
diff --git a/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-enabled-on-self-origin-by-feature-policy.https.html.headers b/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-enabled-on-self-origin-by-feature-policy.https.html.headers deleted file mode 100644 index 4223f53f..0000000 --- a/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-enabled-on-self-origin-by-feature-policy.https.html.headers +++ /dev/null
@@ -1 +0,0 @@ -Feature-Policy: magnetometer 'self'
diff --git a/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-enabled-on-self-origin-by-permissions-policy.https.html b/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-enabled-on-self-origin-by-permissions-policy.https.html index 30a4c61..8739e63 100644 --- a/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-enabled-on-self-origin-by-permissions-policy.https.html +++ b/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-enabled-on-self-origin-by-permissions-policy.https.html
@@ -4,7 +4,7 @@ <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="/permissions-policy/resources/permissions-policy.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> +<script src="/generic-sensor/generic-sensor-permissions-policy-test.sub.js"></script> <script> "use strict";
diff --git a/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-iframe-access.https.html b/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-iframe-access.https.html index 455a06b0..81f24400 100644 --- a/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-iframe-access.https.html +++ b/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-iframe-access.https.html
@@ -9,7 +9,7 @@ <script src="/resources/testdriver-vendor.js"></script> <script src="/generic-sensor/resources/generic-sensor-helpers.js"></script> <script src="/generic-sensor/generic-sensor-iframe-tests.sub.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> +<script src="/generic-sensor/generic-sensor-permissions-policy-test.sub.js"></script> <script src="resources/sensor-data.js"></script> <div id="log"></div> <script>
diff --git a/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-supported-by-feature-policy.html b/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-supported-by-feature-policy.html deleted file mode 100644 index a049363..0000000 --- a/third_party/blink/web_tests/external/wpt/magnetometer/Magnetometer-supported-by-feature-policy.html +++ /dev/null
@@ -1,11 +0,0 @@ -<!DOCTYPE html> -<title>Test that magnetometer is advertised in the feature list</title> -<link rel="help" href="https://w3c.github.io/webappsec-feature-policy/#dom-featurepolicy-features"> -<link rel="help" href="https://w3c.github.io/sensors/#feature-policy-api"> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script> -test(() => { - assert_in_array('magnetometer', document.featurePolicy.features()); -}, 'document.featurePolicy.features should advertise magnetometer.'); -</script>
diff --git a/third_party/blink/web_tests/external/wpt/magnetometer/resources/sensor-data.js b/third_party/blink/web_tests/external/wpt/magnetometer/resources/sensor-data.js index 32c2b1e..7024c708 100644 --- a/third_party/blink/web_tests/external/wpt/magnetometer/resources/sensor-data.js +++ b/third_party/blink/web_tests/external/wpt/magnetometer/resources/sensor-data.js
@@ -4,14 +4,14 @@ sensorName: 'Magnetometer', permissionName: 'magnetometer', testDriverName: 'magnetometer', - featurePolicyNames: ['magnetometer'] + permissionsPolicyNames: ['magnetometer'] }; const kUncalibratedMagnetometerSensorData = { sensorName: 'UncalibratedMagnetometer', permissionName: 'magnetometer', testDriverName: 'magnetometer', - featurePolicyNames: ['magnetometer'] + permissionsPolicyNames: ['magnetometer'] }; const kMagnetometerReadings = {
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/mrow/inferred-mrow-stretchy.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/mrow/inferred-mrow-stretchy.html index b0455ac..5711953 100644 --- a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/mrow/inferred-mrow-stretchy.html +++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/mrow/inferred-mrow-stretchy.html
@@ -46,21 +46,26 @@ <body> <div id="log"></div> <p> - <math><mrow><mo id="moMrow">↨</mo><mspace width="1px" height="100px" style="background: blue"></mspace></mrow></math> - <math><msqrt><mo id="moSqrt">↨</mo><mspace width="1px" height="100px" style="background: magenta"></mspace></msqrt></math> - <math><mstyle><mo id="moStyle">↨</mo><mspace width="1px" height="100px" style="background: magenta"></mspace></mstyle></math> - <math><merror><mo id="moError">↨</mo><mspace width="1px" height="100px" style="background: magenta"></mspace></merror></math> - <math><mphantom><mo style="visibilty: visible;" id="moPhantom">↨</mo><mspace width="1px" height="100px" style="background: magenta"></mspace></mphantom></math> - <math><mo id="moMath">↨</mo><mspace width="1px" height="100px" style="background: magenta"></mspace></math> +<!-- mo operators below should stretch to cover the height of the mspace + sibling. The mn element ensures its parent is not an embellished operator, + so that this test really verifies the stretching is performed during the + layout of the parent and not as part of the stretching of an embellished + operator during the layout of the <math> ancestor. --> + <math><mrow><mo id="moMrow">↨</mo><mspace width="1px" height="100px" style="background: blue"></mspace><mn></mn></mrow></math> + <math><msqrt><mo id="moSqrt">↨</mo><mspace width="1px" height="100px" style="background: magenta"></mspace><mn></mn></msqrt></math> + <math><mstyle><mo id="moStyle">↨</mo><mspace width="1px" height="100px" style="background: magenta"></mspace><mn></mn></mstyle></math> + <math><merror><mo id="moError">↨</mo><mspace width="1px" height="100px" style="background: magenta"></mspace><mn></mn></merror></math> + <math><mphantom><mo style="visibilty: visible;" id="moPhantom">↨</mo><mspace width="1px" height="100px" style="background: magenta"></mspace><mn></mn></mphantom></math> + <math><mo id="moMath">↨</mo><mspace width="1px" height="100px" style="background: magenta"></mspace><mn></mn></math> <!-- menclose is treated as <unknown> in MathML Core --> - <math><menclose notation="box"><mo id="moMenclose">↨</mo><mspace width="1px" height="100px" style="background: magenta"></mspace></menclose></math> - <math><mpadded lspace="10px"><mo id="moMpadded">↨</mo><mspace width="1px" height="100px" style="background: magenta"></mspace></mpadded></math> - <math><unknown><mo id="moUnknown">↨</mo><mspace width="1px" height="100px" style="background: magenta"></mspace></unknown></math> - <math><mtable><mtr><mtd><mo id="moMtd">↨</mo><mspace width="1px" height="100px" style="background: magenta"></mspace></mtd></mtr></mtable></math> - <math><none><mo id="moNone">↨</mo><mspace width="1px" height="100px" style="background: magenta"></mspace></none></math> - <math><mprescripts><mo id="moMprescripts">↨</mo><mspace width="1px" height="100px" style="background: magenta"></mspace></mprescripts></math> - <math><mfenced><mo id="moMfenced">↨</mo><mspace width="1px" height="100px" style="background: magenta"></mspace></mfenced></math> - <math><a><mo id="moA">↨</mo><mspace width="1px" height="100px" style="background: magenta"></mspace></a></math> + <math><menclose notation="box"><mo id="moMenclose">↨</mo><mspace width="1px" height="100px" style="background: magenta"></mspace><mn></mn></menclose></math> + <math><mpadded lspace="10px"><mo id="moMpadded">↨</mo><mspace width="1px" height="100px" style="background: magenta"></mspace><mn></mn></mpadded></math> + <math><unknown><mo id="moUnknown">↨</mo><mspace width="1px" height="100px" style="background: magenta"></mspace><mn></mn></unknown></math> + <math><mtable><mtr><mtd><mo id="moMtd">↨</mo><mspace width="1px" height="100px" style="background: magenta"></mspace><mn></mn></mtd></mtr></mtable></math> + <math><none><mo id="moNone">↨</mo><mspace width="1px" height="100px" style="background: magenta"></mspace><mn></mn></none></math> + <math><mprescripts><mo id="moMprescripts">↨</mo><mspace width="1px" height="100px" style="background: magenta"></mspace><mn></mn></mprescripts></math> + <math><mfenced><mo id="moMfenced">↨</mo><mspace width="1px" height="100px" style="background: magenta"></mspace><mn></mn></mfenced></math> + <math><a><mo id="moA">↨</mo><mspace width="1px" height="100px" style="background: magenta"></mspace><mn></mn></a></math> </p> </body> </html>
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/operators/embellished-operator-004.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/operators/embellished-operator-004.html new file mode 100644 index 0000000..1d5c45ee --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/operators/embellished-operator-004.html
@@ -0,0 +1,74 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>Stretching of core operator with various levels of nested mrows</title> +<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=236963"> +<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=2020658"> +<link rel="help" href="https://w3c.github.io/mathml-core/#embellished-operators"> +<link rel="help" href="https://w3c.github.io/mathml-core/#layout-of-mrow"> +<link rel="help" href="https://w3c.github.io/mathml-core/#the-top-level-math-element"> +<link rel="help" href="https://w3c.github.io/mathml-core/#algorithm-for-stretching-operators-along-the-block-axis"> +<meta name="assert" content="Operators stretch with various levels of nested mrow."> +<script src="/mathml/support/feature-detection.js"></script> +<script src="/mathml/support/fonts.js"></script> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<style> + mo { + font-size: 10px; + font-family: axisheight5000-verticalarrow14000; + } + @font-face { + font-family: axisheight5000-verticalarrow14000; + src: url("/fonts/math/axisheight5000-verticalarrow14000.woff"); + } +</style> +<script type="text/javascript"> + setup({ explicit_done: true }); + window.addEventListener("load", () => { loadAllFonts().then(runTests); }); + function runTests() + { + Array.from(document.querySelectorAll("[data-title]")).forEach(mo => { + test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + assert_greater_than_equal(mo.getBoundingClientRect().height, 100); + }, `Vertical stretching performed for ${mo.dataset.title}.`); + }); + done(); + } +</script> +</head> +<body> + <div id="log"></div> + <p> + <!-- The <math> element uses mrow layout. The <mo> child should stretch to + at least the size of the <mspace> sibling. + --> + <math><mo data-title="math > mo">↨</mo><mspace width="1px" height="100px" style="background: lightblue"></mspace></math> + <math display="block"><mo data-title="Stretching for math[display=block] > mo">↨</mo><mspace width="1px" height="100px" style="background: lightblue"></mspace></math> + + <!-- The <mrow> child of the <math> element is an embellished operator. Per + the "algorithm for stretching operators along the block axis", it + should first be laid out with block stretch constraint (ascent=0, + descent=0) and then laid out again with a stretch constraint that + includes at least the size of the <mspace> descendant. So again the + <mo> descendant should stretch at least to the size of the <mspace>. + --> + <math><mrow><mo data-title="math > mrow > mo">↨</mo><mspace width="1px" height="100px" style="background: lightblue"></mspace></mrow></math> + <math display="block"><mrow><mo data-title="Stretching for math[display=block] > mrow > mo">↨</mo><mspace width="1px" height="100px" style="background: lightblue"></mspace></mrow></math> + + <!-- Same with two nested <mrow>. --> + <math><mrow><mrow><mo data-title="math > mrow > mrow > mo">↨</mo><mspace width="1px" height="100px" style="background: lightblue"></mspace></mrow></mrow></math> + <math display="block"><mrow><mrow><mo data-title="Stretching for math[display=block] > mrow > mrow > mo">↨</mo><mspace width="1px" height="100px" style="background: lightblue"></mspace></mrow></mrow></math> + + <!-- Same with three nested <mrow>. --> + <math><mrow><mrow><mrow><mo data-title="math > mrow > mrow > mrow > mo">↨</mo><mspace width="1px" height="100px" style="background: lightblue"></mspace></mrow></mrow></mrow></math> + <math display="block"><mrow><mrow><mrow><mo data-title="Stretching for math[display=block] > mrow > mrow > mrow > mo">↨</mo><mspace width="1px" height="100px" style="background: lightblue"></mspace></mrow></mrow></mrow></math> + + <!-- Same with four nested <mrow>. --> + <math><mrow><mrow><mrow><mrow><mo data-title="math > mrow > mrow > mrow > mrow > mo">↨</mo><mspace width="1px" height="100px" style="background: lightblue"></mspace></mrow></mrow></mrow></mrow></math> + <math display="block"><mrow><mrow><mrow><mrow><mo data-title="Stretching for math[display=block] > mrow > mrow > mrow > mrow > mo">↨</mo><mspace width="1px" height="100px" style="background: lightblue"></mspace></mrow></mrow></mrow></mrow></math> + </p> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/navigate-event/navigate-history-traversal-during-onnavigate-should-reject.html b/third_party/blink/web_tests/external/wpt/navigation-api/navigate-event/navigate-history-traversal-during-onnavigate-should-reject.html index 911fc6bf..51c44c7 100644 --- a/third_party/blink/web_tests/external/wpt/navigation-api/navigate-event/navigate-history-traversal-during-onnavigate-should-reject.html +++ b/third_party/blink/web_tests/external/wpt/navigation-api/navigate-event/navigate-history-traversal-during-onnavigate-should-reject.html
@@ -9,7 +9,7 @@ await new Promise(resolve => w.onload = resolve); await test_driver.bless("navigate", async function() { - w.navigation.navigate("resources/navigate-during-onnavigate-should-reject-helper.html"); + w.navigation.navigate("../navigation-api/navigate-event/resources/navigate-during-onnavigate-should-reject-helper.html"); }); await new Promise(resolve => onmessage = resolve);
diff --git a/third_party/blink/web_tests/external/wpt/orientation-sensor/AbsoluteOrientationSensor-disabled-by-permissions-policy.https.html b/third_party/blink/web_tests/external/wpt/orientation-sensor/AbsoluteOrientationSensor-disabled-by-permissions-policy.https.html index 982eaf6e..785ea99 100644 --- a/third_party/blink/web_tests/external/wpt/orientation-sensor/AbsoluteOrientationSensor-disabled-by-permissions-policy.https.html +++ b/third_party/blink/web_tests/external/wpt/orientation-sensor/AbsoluteOrientationSensor-disabled-by-permissions-policy.https.html
@@ -4,7 +4,7 @@ <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="/permissions-policy/resources/permissions-policy.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> +<script src="/generic-sensor/generic-sensor-permissions-policy-test.sub.js"></script> <script> "use strict";
diff --git a/third_party/blink/web_tests/external/wpt/orientation-sensor/AbsoluteOrientationSensor-enabled-by-permissions-policy-attribute-redirect-on-load.https.html b/third_party/blink/web_tests/external/wpt/orientation-sensor/AbsoluteOrientationSensor-enabled-by-permissions-policy-attribute-redirect-on-load.https.html index c30c478..b165f89 100644 --- a/third_party/blink/web_tests/external/wpt/orientation-sensor/AbsoluteOrientationSensor-enabled-by-permissions-policy-attribute-redirect-on-load.https.html +++ b/third_party/blink/web_tests/external/wpt/orientation-sensor/AbsoluteOrientationSensor-enabled-by-permissions-policy-attribute-redirect-on-load.https.html
@@ -4,7 +4,7 @@ <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="/permissions-policy/resources/permissions-policy.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> +<script src="/generic-sensor/generic-sensor-permissions-policy-test.sub.js"></script> <script> "use strict";
diff --git a/third_party/blink/web_tests/external/wpt/orientation-sensor/AbsoluteOrientationSensor-enabled-by-permissions-policy-attribute.https.html b/third_party/blink/web_tests/external/wpt/orientation-sensor/AbsoluteOrientationSensor-enabled-by-permissions-policy-attribute.https.html index 6057943..dcaafc7 100644 --- a/third_party/blink/web_tests/external/wpt/orientation-sensor/AbsoluteOrientationSensor-enabled-by-permissions-policy-attribute.https.html +++ b/third_party/blink/web_tests/external/wpt/orientation-sensor/AbsoluteOrientationSensor-enabled-by-permissions-policy-attribute.https.html
@@ -4,7 +4,7 @@ <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="/permissions-policy/resources/permissions-policy.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> +<script src="/generic-sensor/generic-sensor-permissions-policy-test.sub.js"></script> <script> "use strict";
diff --git a/third_party/blink/web_tests/external/wpt/orientation-sensor/AbsoluteOrientationSensor-enabled-by-permissions-policy.https.html b/third_party/blink/web_tests/external/wpt/orientation-sensor/AbsoluteOrientationSensor-enabled-by-permissions-policy.https.html index dd4dd5a..f7fc1c8 100644 --- a/third_party/blink/web_tests/external/wpt/orientation-sensor/AbsoluteOrientationSensor-enabled-by-permissions-policy.https.html +++ b/third_party/blink/web_tests/external/wpt/orientation-sensor/AbsoluteOrientationSensor-enabled-by-permissions-policy.https.html
@@ -4,7 +4,7 @@ <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="/permissions-policy/resources/permissions-policy.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> +<script src="/generic-sensor/generic-sensor-permissions-policy-test.sub.js"></script> <script> "use strict";
diff --git a/third_party/blink/web_tests/external/wpt/orientation-sensor/AbsoluteOrientationSensor-enabled-on-self-origin-by-permissions-policy.https.html b/third_party/blink/web_tests/external/wpt/orientation-sensor/AbsoluteOrientationSensor-enabled-on-self-origin-by-permissions-policy.https.html index 5f6db8f..d145672 100644 --- a/third_party/blink/web_tests/external/wpt/orientation-sensor/AbsoluteOrientationSensor-enabled-on-self-origin-by-permissions-policy.https.html +++ b/third_party/blink/web_tests/external/wpt/orientation-sensor/AbsoluteOrientationSensor-enabled-on-self-origin-by-permissions-policy.https.html
@@ -4,7 +4,7 @@ <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="/permissions-policy/resources/permissions-policy.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> +<script src="/generic-sensor/generic-sensor-permissions-policy-test.sub.js"></script> <script> "use strict";
diff --git a/third_party/blink/web_tests/external/wpt/orientation-sensor/AbsoluteOrientationSensor-iframe-access.https.html b/third_party/blink/web_tests/external/wpt/orientation-sensor/AbsoluteOrientationSensor-iframe-access.https.html index 5446e73..df446188 100644 --- a/third_party/blink/web_tests/external/wpt/orientation-sensor/AbsoluteOrientationSensor-iframe-access.https.html +++ b/third_party/blink/web_tests/external/wpt/orientation-sensor/AbsoluteOrientationSensor-iframe-access.https.html
@@ -10,7 +10,7 @@ <script src="/resources/testdriver-vendor.js"></script> <script src="/generic-sensor/resources/generic-sensor-helpers.js"></script> <script src="/generic-sensor/generic-sensor-iframe-tests.sub.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> +<script src="/generic-sensor/generic-sensor-permissions-policy-test.sub.js"></script> <script src="resources/sensor-data.js"></script> <div id="log"></div> <script>
diff --git a/third_party/blink/web_tests/external/wpt/orientation-sensor/RelativeOrientationSensor-disabled-by-permissions-policy.https.html b/third_party/blink/web_tests/external/wpt/orientation-sensor/RelativeOrientationSensor-disabled-by-permissions-policy.https.html index 2c98e890..25dd988 100644 --- a/third_party/blink/web_tests/external/wpt/orientation-sensor/RelativeOrientationSensor-disabled-by-permissions-policy.https.html +++ b/third_party/blink/web_tests/external/wpt/orientation-sensor/RelativeOrientationSensor-disabled-by-permissions-policy.https.html
@@ -4,7 +4,7 @@ <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="/permissions-policy/resources/permissions-policy.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> +<script src="/generic-sensor/generic-sensor-permissions-policy-test.sub.js"></script> <script> "use strict";
diff --git a/third_party/blink/web_tests/external/wpt/orientation-sensor/RelativeOrientationSensor-enabled-by-permissions-policy-attribute-redirect-on-load.https.html b/third_party/blink/web_tests/external/wpt/orientation-sensor/RelativeOrientationSensor-enabled-by-permissions-policy-attribute-redirect-on-load.https.html index ba0a1da..b5d1b67 100644 --- a/third_party/blink/web_tests/external/wpt/orientation-sensor/RelativeOrientationSensor-enabled-by-permissions-policy-attribute-redirect-on-load.https.html +++ b/third_party/blink/web_tests/external/wpt/orientation-sensor/RelativeOrientationSensor-enabled-by-permissions-policy-attribute-redirect-on-load.https.html
@@ -4,7 +4,7 @@ <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="/permissions-policy/resources/permissions-policy.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> +<script src="/generic-sensor/generic-sensor-permissions-policy-test.sub.js"></script> <script> "use strict";
diff --git a/third_party/blink/web_tests/external/wpt/orientation-sensor/RelativeOrientationSensor-enabled-by-permissions-policy-attribute.https.html b/third_party/blink/web_tests/external/wpt/orientation-sensor/RelativeOrientationSensor-enabled-by-permissions-policy-attribute.https.html index a846fcb0..3d9ca5e 100644 --- a/third_party/blink/web_tests/external/wpt/orientation-sensor/RelativeOrientationSensor-enabled-by-permissions-policy-attribute.https.html +++ b/third_party/blink/web_tests/external/wpt/orientation-sensor/RelativeOrientationSensor-enabled-by-permissions-policy-attribute.https.html
@@ -4,7 +4,7 @@ <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="/permissions-policy/resources/permissions-policy.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> +<script src="/generic-sensor/generic-sensor-permissions-policy-test.sub.js"></script> <script> "use strict";
diff --git a/third_party/blink/web_tests/external/wpt/orientation-sensor/RelativeOrientationSensor-enabled-by-permissions-policy.https.html b/third_party/blink/web_tests/external/wpt/orientation-sensor/RelativeOrientationSensor-enabled-by-permissions-policy.https.html index f520b87..653e686 100644 --- a/third_party/blink/web_tests/external/wpt/orientation-sensor/RelativeOrientationSensor-enabled-by-permissions-policy.https.html +++ b/third_party/blink/web_tests/external/wpt/orientation-sensor/RelativeOrientationSensor-enabled-by-permissions-policy.https.html
@@ -4,7 +4,7 @@ <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="/permissions-policy/resources/permissions-policy.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> +<script src="/generic-sensor/generic-sensor-permissions-policy-test.sub.js"></script> <script> "use strict";
diff --git a/third_party/blink/web_tests/external/wpt/orientation-sensor/RelativeOrientationSensor-enabled-on-self-origin-by-permissions-policy.https.html b/third_party/blink/web_tests/external/wpt/orientation-sensor/RelativeOrientationSensor-enabled-on-self-origin-by-permissions-policy.https.html index d69c02c..190ce8f7 100644 --- a/third_party/blink/web_tests/external/wpt/orientation-sensor/RelativeOrientationSensor-enabled-on-self-origin-by-permissions-policy.https.html +++ b/third_party/blink/web_tests/external/wpt/orientation-sensor/RelativeOrientationSensor-enabled-on-self-origin-by-permissions-policy.https.html
@@ -4,7 +4,7 @@ <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="/permissions-policy/resources/permissions-policy.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> +<script src="/generic-sensor/generic-sensor-permissions-policy-test.sub.js"></script> <script> "use strict";
diff --git a/third_party/blink/web_tests/external/wpt/orientation-sensor/RelativeOrientationSensor-iframe-access.https.html b/third_party/blink/web_tests/external/wpt/orientation-sensor/RelativeOrientationSensor-iframe-access.https.html index 10fcb50c..c314654 100644 --- a/third_party/blink/web_tests/external/wpt/orientation-sensor/RelativeOrientationSensor-iframe-access.https.html +++ b/third_party/blink/web_tests/external/wpt/orientation-sensor/RelativeOrientationSensor-iframe-access.https.html
@@ -10,7 +10,7 @@ <script src="/resources/testdriver-vendor.js"></script> <script src="/generic-sensor/resources/generic-sensor-helpers.js"></script> <script src="/generic-sensor/generic-sensor-iframe-tests.sub.js"></script> -<script src="/generic-sensor/generic-sensor-feature-policy-test.sub.js"></script> +<script src="/generic-sensor/generic-sensor-permissions-policy-test.sub.js"></script> <script src="resources/sensor-data.js"></script> <div id="log"></div> <script>
diff --git a/third_party/blink/web_tests/external/wpt/orientation-sensor/resources/sensor-data.js b/third_party/blink/web_tests/external/wpt/orientation-sensor/resources/sensor-data.js index a2886e7..3b7ee8d 100644 --- a/third_party/blink/web_tests/external/wpt/orientation-sensor/resources/sensor-data.js +++ b/third_party/blink/web_tests/external/wpt/orientation-sensor/resources/sensor-data.js
@@ -4,14 +4,14 @@ sensorName: 'AbsoluteOrientationSensor', permissionName: 'accelerometer', testDriverName: 'absolute-orientation', - featurePolicyNames: ['accelerometer', 'gyroscope', 'magnetometer'] + permissionsPolicyNames: ['accelerometer', 'gyroscope', 'magnetometer'] }; const kRelativeOrientationSensorData = { sensorName: 'RelativeOrientationSensor', permissionName: 'accelerometer', testDriverName: 'relative-orientation', - featurePolicyNames: ['accelerometer', 'gyroscope'] + permissionsPolicyNames: ['accelerometer', 'gyroscope'] }; const kOrientationReadings = {
diff --git a/third_party/blink/web_tests/external/wpt/paint-timing/first-paint-only/child-painting-first-image.html b/third_party/blink/web_tests/external/wpt/paint-timing/first-paint-only/child-painting-first-image.html index e541120f..78c95ce5 100644 --- a/third_party/blink/web_tests/external/wpt/paint-timing/first-paint-only/child-painting-first-image.html +++ b/third_party/blink/web_tests/external/wpt/paint-timing/first-paint-only/child-painting-first-image.html
@@ -30,7 +30,7 @@ } if (entriesExpectToReceive.length == 0) { - assertFirstPaint(t, 0); + assertFirstPaint(t, 30); t.done(); } }));
diff --git a/third_party/blink/web_tests/external/wpt/paint-timing/first-paint-only/first-paint-bg-color-expected.txt b/third_party/blink/web_tests/external/wpt/paint-timing/first-paint-only/first-paint-bg-color-expected.txt new file mode 100644 index 0000000..bde35b6b --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/paint-timing/first-paint-only/first-paint-bg-color-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] First paint fires due to background color. No FCP + assert_equals: FP only. expected 1 but got 0 +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/paint-timing/first-paint-only/first-paint-only-expected.txt b/third_party/blink/web_tests/external/wpt/paint-timing/first-paint-only/first-paint-only-expected.txt new file mode 100644 index 0000000..754a4f8 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/paint-timing/first-paint-only/first-paint-only-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] Performance first paint timing entry exists. No first contentful paint. + assert_equals: FP only. expected 1 but got 0 +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/paint-timing/first-paint-only/sibling-painting-first-image.html b/third_party/blink/web_tests/external/wpt/paint-timing/first-paint-only/sibling-painting-first-image.html index ca1e155..c2d0071e 100644 --- a/third_party/blink/web_tests/external/wpt/paint-timing/first-paint-only/sibling-painting-first-image.html +++ b/third_party/blink/web_tests/external/wpt/paint-timing/first-paint-only/sibling-painting-first-image.html
@@ -41,7 +41,7 @@ // Check the paint-timing entries from the listening iframe. assert_equals(e.data, '0'); // Check that current frame receives first-paint but not first-contentful-paint. - assertFirstPaint(t, 0); + assertFirstPaint(t, 30); t.done(); })); }, 'Frame ignores paint-timing events fired from sibling frame.');
diff --git a/third_party/blink/web_tests/external/wpt/paint-timing/resources/utils.js b/third_party/blink/web_tests/external/wpt/paint-timing/resources/utils.js index cfb4ef88..12ec53d 100644 --- a/third_party/blink/web_tests/external/wpt/paint-timing/resources/utils.js +++ b/third_party/blink/web_tests/external/wpt/paint-timing/resources/utils.js
@@ -17,7 +17,6 @@ t.step_timeout(function() { testFP(); }, timeout); - return; } t.step(function() { assert_equals(bufferedEntries.length, 1, "FP only.");
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/permissions-policy-header-host-wildcard.https.sub-expected.txt b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/permissions-policy-header-host-wildcard.https.sub-expected.txt new file mode 100644 index 0000000..192eccbd --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/permissions-policy-header-host-wildcard.https.sub-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] Test wildcard host policy works as expected + Cannot read properties of undefined (reading 'getAllowlistForFeature') +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/permissions-policy-header-host-wildcard.https.sub.html b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/permissions-policy-header-host-wildcard.https.sub.html index 211ca74..978bf89 100644 --- a/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/permissions-policy-header-host-wildcard.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/permissions-policy-header-host-wildcard.https.sub.html
@@ -6,9 +6,9 @@ test(function() { var wildcard_origin = 'https://*:{{ports[https][0]}}'; assert_array_equals( - document.featurePolicy.getAllowlistForFeature('fullscreen'), + document.permissionsPolicy.getAllowlistForFeature('fullscreen'), [wildcard_origin]); - assert_true(document.featurePolicy.allowsFeature('fullscreen')); + assert_true(document.permissionsPolicy.allowsFeature('fullscreen')); }, 'Test wildcard host policy works as expected'); </script> </body> \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/permissions-policy-header-port-wildcard.https.sub-expected.txt b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/permissions-policy-header-port-wildcard.https.sub-expected.txt new file mode 100644 index 0000000..990d06a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/permissions-policy-header-port-wildcard.https.sub-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] Test wildcard port policy works as expected + Cannot read properties of undefined (reading 'getAllowlistForFeature') +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/permissions-policy-header-port-wildcard.https.sub.html b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/permissions-policy-header-port-wildcard.https.sub.html index adb6570..a9938f7 100644 --- a/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/permissions-policy-header-port-wildcard.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/permissions-policy-header-port-wildcard.https.sub.html
@@ -6,9 +6,9 @@ test(function() { var wildcard_origin = 'https://{{domains[]}}:*'; assert_array_equals( - document.featurePolicy.getAllowlistForFeature('fullscreen'), + document.permissionsPolicy.getAllowlistForFeature('fullscreen'), [wildcard_origin]); - assert_true(document.featurePolicy.allowsFeature('fullscreen')); + assert_true(document.permissionsPolicy.allowsFeature('fullscreen')); }, 'Test wildcard port policy works as expected'); </script> </body>
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/permissions-policy-header-scheme-only.https.sub-expected.txt b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/permissions-policy-header-scheme-only.https.sub-expected.txt new file mode 100644 index 0000000..034e99a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/permissions-policy-header-scheme-only.https.sub-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] Test scheme only policy works as expected + Cannot read properties of undefined (reading 'getAllowlistForFeature') +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/permissions-policy-header-scheme-only.https.sub.html b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/permissions-policy-header-scheme-only.https.sub.html index eab3e8f..e528f08 100644 --- a/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/permissions-policy-header-scheme-only.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/permissions-policy-header-scheme-only.https.sub.html
@@ -6,9 +6,9 @@ test(function() { var wildcard_origin = 'https:'; assert_array_equals( - document.featurePolicy.getAllowlistForFeature('fullscreen'), + document.permissionsPolicy.getAllowlistForFeature('fullscreen'), [wildcard_origin]); - assert_true(document.featurePolicy.allowsFeature('fullscreen')); + assert_true(document.permissionsPolicy.allowsFeature('fullscreen')); }, 'Test scheme only policy works as expected'); </script> </body>
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/private-state-token-redemption-supported-by-permissions-policy.tentative-expected.txt b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/private-state-token-redemption-supported-by-permissions-policy.tentative-expected.txt new file mode 100644 index 0000000..b174ced --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/private-state-token-redemption-supported-by-permissions-policy.tentative-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] document.permissionsPolicy.features should advertise private-state-token-redemption. + Cannot read properties of undefined (reading 'features') +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/private-state-token-redemption-supported-by-permissions-policy.tentative.html b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/private-state-token-redemption-supported-by-permissions-policy.tentative.html index 0399f16..68bd6a1 100644 --- a/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/private-state-token-redemption-supported-by-permissions-policy.tentative.html +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/private-state-token-redemption-supported-by-permissions-policy.tentative.html
@@ -4,6 +4,6 @@ <script src="/resources/testharnessreport.js"></script> <script> test(() => { - assert_in_array('private-state-token-redemption', document.featurePolicy.features()); - }, 'document.featurePolicy.features should advertise private-state-token-redemption.'); + assert_in_array('private-state-token-redemption', document.permissionsPolicy.features()); + }, 'document.permissionsPolicy.features should advertise private-state-token-redemption.'); </script>
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/resources/permissions-policy-focus-without-user-activation.html b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/resources/permissions-policy-focus-without-user-activation.html index c802d6f0..d8a7e1e8 100644 --- a/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/resources/permissions-policy-focus-without-user-activation.html +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/resources/permissions-policy-focus-without-user-activation.html
@@ -6,6 +6,6 @@ } window.onload = function () { - post_result(document.featurePolicy.allowedFeatures().includes("focus-without-user-activation")); + post_result(document.permissionsPolicy.allowedFeatures().includes("focus-without-user-activation")); } </script> \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/resources/unload-helper.js b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/resources/unload-helper.js index d1bf0105..5b11a21 100644 --- a/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/resources/unload-helper.js +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/resources/unload-helper.js
@@ -5,7 +5,7 @@ async function isUnloadAllowed(remoteContextWrapper) { return remoteContextWrapper.executeScript(() => { - return document.featurePolicy.allowsFeature('unload'); + return document.permissionsPolicy.allowsFeature('unload'); }); }
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-allowed-by-default.tentative.window-expected.txt b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-allowed-by-default.tentative.window-expected.txt index 756a0f55..3ebb4a3 100644 --- a/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-allowed-by-default.tentative.window-expected.txt +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-allowed-by-default.tentative.window-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. [FAIL] 'unload' Policy : allowed by default - assert_equals: sameOriginSubframe: unload in sameOriginSubframe should be allowed expected true but got false + promise_test: Unhandled rejection with value: object "TypeError: Cannot read properties of undefined (reading 'allowsFeature')" Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-allowed-embed.tentative.window-expected.txt b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-allowed-embed.tentative.window-expected.txt new file mode 100644 index 0000000..88753df --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-allowed-embed.tentative.window-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] 'unload' Policy : allowed in frames when allowed in main frame. + promise_test: Unhandled rejection with value: object "TypeError: Cannot read properties of undefined (reading 'allowsFeature')" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-allowed-frameset.tentative.window-expected.txt b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-allowed-frameset.tentative.window-expected.txt new file mode 100644 index 0000000..88753df --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-allowed-frameset.tentative.window-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] 'unload' Policy : allowed in frames when allowed in main frame. + promise_test: Unhandled rejection with value: object "TypeError: Cannot read properties of undefined (reading 'allowsFeature')" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-allowed-headerless.tentative.window_urlType=blank-expected.txt b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-allowed-headerless.tentative.window_urlType=blank-expected.txt new file mode 100644 index 0000000..c6395f2 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-allowed-headerless.tentative.window_urlType=blank-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] 'unload' Policy : allowed in headerless doc when allowed in main frame. + promise_test: Unhandled rejection with value: object "TypeError: Cannot read properties of undefined (reading 'allowsFeature')" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-allowed-headerless.tentative.window_urlType=blob-expected.txt b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-allowed-headerless.tentative.window_urlType=blob-expected.txt new file mode 100644 index 0000000..c6395f2 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-allowed-headerless.tentative.window_urlType=blob-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] 'unload' Policy : allowed in headerless doc when allowed in main frame. + promise_test: Unhandled rejection with value: object "TypeError: Cannot read properties of undefined (reading 'allowsFeature')" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-allowed-headerless.tentative.window_urlType=data-expected.txt b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-allowed-headerless.tentative.window_urlType=data-expected.txt new file mode 100644 index 0000000..c6395f2 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-allowed-headerless.tentative.window_urlType=data-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] 'unload' Policy : allowed in headerless doc when allowed in main frame. + promise_test: Unhandled rejection with value: object "TypeError: Cannot read properties of undefined (reading 'allowsFeature')" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-allowed-headerless.tentative.window_urlType=srcdoc-expected.txt b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-allowed-headerless.tentative.window_urlType=srcdoc-expected.txt new file mode 100644 index 0000000..c6395f2 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-allowed-headerless.tentative.window_urlType=srcdoc-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] 'unload' Policy : allowed in headerless doc when allowed in main frame. + promise_test: Unhandled rejection with value: object "TypeError: Cannot read properties of undefined (reading 'allowsFeature')" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-allowed-object.tentative.window-expected.txt b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-allowed-object.tentative.window-expected.txt new file mode 100644 index 0000000..88753df --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-allowed-object.tentative.window-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] 'unload' Policy : allowed in frames when allowed in main frame. + promise_test: Unhandled rejection with value: object "TypeError: Cannot read properties of undefined (reading 'allowsFeature')" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-disallowed-embed.tentative.window-expected.txt b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-disallowed-embed.tentative.window-expected.txt new file mode 100644 index 0000000..8594516a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-disallowed-embed.tentative.window-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] 'unload' Policy : disallowed in frames when disallowed in main frame. + promise_test: Unhandled rejection with value: object "TypeError: Cannot read properties of undefined (reading 'allowsFeature')" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-disallowed-frameset.tentative.window-expected.txt b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-disallowed-frameset.tentative.window-expected.txt new file mode 100644 index 0000000..8594516a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-disallowed-frameset.tentative.window-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] 'unload' Policy : disallowed in frames when disallowed in main frame. + promise_test: Unhandled rejection with value: object "TypeError: Cannot read properties of undefined (reading 'allowsFeature')" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-disallowed-headerless.tentative.window_urlType=blank-expected.txt b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-disallowed-headerless.tentative.window_urlType=blank-expected.txt new file mode 100644 index 0000000..221146a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-disallowed-headerless.tentative.window_urlType=blank-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] 'unload' Policy : disallowed in headerless doc when disallowed in main frame. + promise_test: Unhandled rejection with value: object "TypeError: Cannot read properties of undefined (reading 'allowsFeature')" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-disallowed-headerless.tentative.window_urlType=blob-expected.txt b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-disallowed-headerless.tentative.window_urlType=blob-expected.txt new file mode 100644 index 0000000..221146a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-disallowed-headerless.tentative.window_urlType=blob-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] 'unload' Policy : disallowed in headerless doc when disallowed in main frame. + promise_test: Unhandled rejection with value: object "TypeError: Cannot read properties of undefined (reading 'allowsFeature')" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-disallowed-headerless.tentative.window_urlType=data-expected.txt b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-disallowed-headerless.tentative.window_urlType=data-expected.txt new file mode 100644 index 0000000..221146a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-disallowed-headerless.tentative.window_urlType=data-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] 'unload' Policy : disallowed in headerless doc when disallowed in main frame. + promise_test: Unhandled rejection with value: object "TypeError: Cannot read properties of undefined (reading 'allowsFeature')" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-disallowed-headerless.tentative.window_urlType=srcdoc-expected.txt b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-disallowed-headerless.tentative.window_urlType=srcdoc-expected.txt new file mode 100644 index 0000000..221146a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-disallowed-headerless.tentative.window_urlType=srcdoc-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] 'unload' Policy : disallowed in headerless doc when disallowed in main frame. + promise_test: Unhandled rejection with value: object "TypeError: Cannot read properties of undefined (reading 'allowsFeature')" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-disallowed-object.tentative.window-expected.txt b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-disallowed-object.tentative.window-expected.txt new file mode 100644 index 0000000..8594516a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-disallowed-object.tentative.window-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] 'unload' Policy : disallowed in frames when disallowed in main frame. + promise_test: Unhandled rejection with value: object "TypeError: Cannot read properties of undefined (reading 'allowsFeature')" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-disallowed-subframe.tentative.window-expected.txt b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-disallowed-subframe.tentative.window-expected.txt new file mode 100644 index 0000000..afd37aa --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-disallowed-subframe.tentative.window-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] 'unload' Policy : allowed in main frame but disallowed in subframe + promise_test: Unhandled rejection with value: object "TypeError: Cannot read properties of undefined (reading 'allowsFeature')" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-disallowed.tentative.window-expected.txt b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-disallowed.tentative.window-expected.txt new file mode 100644 index 0000000..8183b76 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/unload-disallowed.tentative.window-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] 'unload' Policy : disallowed when header is () + promise_test: Unhandled rejection with value: object "TypeError: Cannot read properties of undefined (reading 'allowsFeature')" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/vertical-scroll-main-frame-manual.tentative.html b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/vertical-scroll-main-frame-manual.tentative.html index cda6c49a..eacf69f 100644 --- a/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/vertical-scroll-main-frame-manual.tentative.html +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/vertical-scroll-main-frame-manual.tentative.html
@@ -25,7 +25,7 @@ // Sanity check. test(() => { - assert_false(document.featurePolicy.allowsFeature("vertical-scroll"), + assert_false(document.permissionsPolicy.allowsFeature("vertical-scroll"), "Expected 'vertical-scroll' to be disabled."); }, "'vertical-scroll' disabled in main document.");
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/payment-supported-by-permissions-policy.tentative-expected.txt b/third_party/blink/web_tests/external/wpt/permissions-policy/payment-supported-by-permissions-policy.tentative-expected.txt new file mode 100644 index 0000000..6ebab19 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/payment-supported-by-permissions-policy.tentative-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] document.permissionsPolicy.features should advertise payment. + Cannot read properties of undefined (reading 'features') +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/payment-supported-by-permissions-policy.tentative.html b/third_party/blink/web_tests/external/wpt/permissions-policy/payment-supported-by-permissions-policy.tentative.html index 4e8796f..825c956 100644 --- a/third_party/blink/web_tests/external/wpt/permissions-policy/payment-supported-by-permissions-policy.tentative.html +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/payment-supported-by-permissions-policy.tentative.html
@@ -6,6 +6,6 @@ <script src="/resources/testharnessreport.js"></script> <script> test(() => { - assert_in_array('payment', document.featurePolicy.features()); -}, 'document.featurePolicy.features should advertise payment.'); + assert_in_array('payment', document.permissionsPolicy.features()); +}, 'document.permissionsPolicy.features should advertise payment.'); </script>
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/permissions-policy-frame-policy-allowed-for-all.https.sub-expected.txt b/third_party/blink/web_tests/external/wpt/permissions-policy/permissions-policy-frame-policy-allowed-for-all.https.sub-expected.txt new file mode 100644 index 0000000..017813f --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/permissions-policy-frame-policy-allowed-for-all.https.sub-expected.txt
@@ -0,0 +1,160 @@ +This is a testharness.js-based test. +Found 78 FAIL, 0 TIMEOUT, 0 NOTRUN. +[FAIL] Test frame policy on same origin iframe inherit from header policy. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe does not inherit from header policy. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc iframe inherit from header policy. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc+ same origin iframe inherit from header policy. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc+ cross origin iframe inherit from header policy. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on data: URL cross origin iframe does not inherit from header policy. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "*". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "*". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc iframe with allow = "*". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + same origin iframe with allow = "*". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + cross origin iframe with allow = "*". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on data: URL cross origin iframe with allow = "*". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'self'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'self'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc iframe with allow = "'self'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + same origin iframe with allow = "'self'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + cross origin iframe with allow = "'self'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on data: URL cross origin iframe with allow = "'self'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'none'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'none'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc iframe with allow = "'none'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + same origin iframe with allow = "'none'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + cross origin iframe with allow = "'none'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on data: URL cross origin iframe with allow = "'none'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + same origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + cross origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on data: URL cross origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "*" and header policy = "Permissions-Policy: fullscreen=*;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "*" and header policy = "Permissions-Policy: fullscreen=*;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "*" and header policy = "Permissions-Policy: fullscreen=self;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "*" and header policy = "Permissions-Policy: fullscreen=self;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "*" and header policy = "Permissions-Policy: fullscreen=();". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "*" and header policy = "Permissions-Policy: fullscreen=();". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'self'" and header policy = "Permissions-Policy: fullscreen=*;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'self'" and header policy = "Permissions-Policy: fullscreen=*;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'self'" and header policy = "Permissions-Policy: fullscreen=self;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'self'" and header policy = "Permissions-Policy: fullscreen=self;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'self'" and header policy = "Permissions-Policy: fullscreen=();". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'self'" and header policy = "Permissions-Policy: fullscreen=();". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'none'" and header policy = "Permissions-Policy: fullscreen=*;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'none'" and header policy = "Permissions-Policy: fullscreen=*;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'none'" and header policy = "Permissions-Policy: fullscreen=self;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'none'" and header policy = "Permissions-Policy: fullscreen=self;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'none'" and header policy = "Permissions-Policy: fullscreen=();". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'none'" and header policy = "Permissions-Policy: fullscreen=();". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and header policy = "Permissions-Policy: fullscreen=*;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and header policy = "Permissions-Policy: fullscreen=*;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and header policy = "Permissions-Policy: fullscreen=self;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and header policy = "Permissions-Policy: fullscreen=self;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and header policy = "Permissions-Policy: fullscreen=();". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and header policy = "Permissions-Policy: fullscreen=();". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "*" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "*" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc iframe with allow = "*" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + same origin iframe with allow = "*" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + cross origin iframe with allow = "*" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on data: URL cross origin iframe with allow = "*" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'self'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'self'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc iframe with allow = "'self'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + same origin iframe with allow = "'self'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + cross origin iframe with allow = "'self'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on data: URL cross origin iframe with allow = "'self'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'none'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'none'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc iframe with allow = "'none'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + same origin iframe with allow = "'none'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + cross origin iframe with allow = "'none'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on data: URL cross origin iframe with allow = "'none'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + same origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + cross origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on data: URL cross origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/permissions-policy-frame-policy-allowed-for-self.https.sub-expected.txt b/third_party/blink/web_tests/external/wpt/permissions-policy/permissions-policy-frame-policy-allowed-for-self.https.sub-expected.txt new file mode 100644 index 0000000..de2567d9 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/permissions-policy-frame-policy-allowed-for-self.https.sub-expected.txt
@@ -0,0 +1,176 @@ +This is a testharness.js-based test. +Found 86 FAIL, 0 TIMEOUT, 0 NOTRUN. +[FAIL] Test frame policy on same origin iframe inherit from header policy. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe inherit from header policy. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc iframe inherit from header policy. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + same origin iframe inherit from header policy. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + cross origin iframe inherit from header policy. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on data: URL cross origin iframe inherit from header policy. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on sandboxed iframe with no allow attribute. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on sandboxed iframe with allow="fullscreen". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on sandboxed iframe with allow="fullscreen 'src'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on sandboxed iframe with allow="fullscreen https://www.web-platform.test:8444". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc sandboxed iframe with allow="fullscreen". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + same origin sandboxed iframe with allow="fullscreen". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + cross origin sandboxed iframe with allow="fullscreen". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on sandboxed srcdoc iframe with allow="fullscreen https://www.web-platform.test:8444". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "*". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "*". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc iframe with allow = "*". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + same origin iframe with allow = "*". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + cross origin iframe with allow = "*". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on data: URL origin iframe with allow = "*". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'self'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'self'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc iframe with allow = "'self'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + same origin iframe with allow = "'self'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + cross origin iframe with allow = "'self'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on data: URL origin iframe with allow = "'self'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'none'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'none'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc iframe with allow = "'none'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + same origin iframe with allow = "'none'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + cross origin iframe with allow = "'none'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on data: URL origin iframe with allow = "'none'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + same origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + cross origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on data: URL origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "*" and header policy = "Permissions-Policy: fullscreen=*;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "*" and header policy = "Permissions-Policy: fullscreen=*;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "*" and header policy = "Permissions-Policy: fullscreen=self;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "*" and header policy = "Permissions-Policy: fullscreen=self;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "*" and header policy = "Permissions-Policy: fullscreen=();". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "*" and header policy = "Permissions-Policy: fullscreen=();". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'self'" and header policy = "Permissions-Policy: fullscreen=*;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'self'" and header policy = "Permissions-Policy: fullscreen=*;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'self'" and header policy = "Permissions-Policy: fullscreen=self;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'self'" and header policy = "Permissions-Policy: fullscreen=self;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'self'" and header policy = "Permissions-Policy: fullscreen=();". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'self'" and header policy = "Permissions-Policy: fullscreen=();". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'none'" and header policy = "Permissions-Policy: fullscreen=*;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'none'" and header policy = "Permissions-Policy: fullscreen=*;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'none'" and header policy = "Permissions-Policy: fullscreen=self;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'none'" and header policy = "Permissions-Policy: fullscreen=self;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'none'" and header policy = "Permissions-Policy: fullscreen=();". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'none'" and header policy = "Permissions-Policy: fullscreen=();". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and header policy = "Permissions-Policy: fullscreen=*;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and header policy = "Permissions-Policy: fullscreen=*;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and header policy = "Permissions-Policy: fullscreen=self;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and header policy = "Permissions-Policy: fullscreen=self;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and header policy = "Permissions-Policy: fullscreen=();". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and header policy = "Permissions-Policy: fullscreen=();". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "*" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "*" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc iframe with allow = "*" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + same origin iframe with allow = "*" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + cross origin iframe with allow = "*" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on data: URL origin iframe with allow = "*" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'self'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'self'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc iframe with allow = "'self'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + same origin iframe with allow = "'self'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + cross origin iframe with allow = "'self'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on data: URL origin iframe with allow = "'self'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'none'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'none'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc iframe with allow = "'none'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + same origin iframe with allow = "'none'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + cross origin iframe with allow = "'none'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on data: URL origin iframe with allow = "'none'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + same origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + cross origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on data: URL origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/permissions-policy-frame-policy-allowed-for-some-override.https.sub-expected.txt b/third_party/blink/web_tests/external/wpt/permissions-policy/permissions-policy-frame-policy-allowed-for-some-override.https.sub-expected.txt new file mode 100644 index 0000000..0e9ca01f --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/permissions-policy-frame-policy-allowed-for-some-override.https.sub-expected.txt
@@ -0,0 +1,67 @@ +This is a testharness.js-based test. +[FAIL] Test frame policy on same origin iframe with allow = "*" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "*" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on another cross origin iframe with allow = "*" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc iframe with allow = "*" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + same origin iframe with allow = "*" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + cross origin iframe with allow = "*" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + another cross origin iframe with allow = "*" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on data: URL cross origin iframe with allow = "*" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'self'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'self'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on another cross origin iframe with allow = "'self'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc iframe with allow = "'self'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + same origin iframe with allow = "'self'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + cross origin iframe with allow = "'self'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + another cross origin iframe with allow = "'self'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on data: URL cross origin iframe with allow = "'self'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'none'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'none'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on another cross origin iframe with allow = "'none'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc iframe with allow = "'none'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + same origin iframe with allow = "'none'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + cross origin iframe with allow = "'none'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + another cross origin iframe with allow = "'none'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on data: URL cross origin iframe with allow = "'none'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on another cross origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + same origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + cross origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + another cross origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on data: URL cross origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/permissions-policy-frame-policy-allowed-for-some.https.sub-expected.txt b/third_party/blink/web_tests/external/wpt/permissions-policy/permissions-policy-frame-policy-allowed-for-some.https.sub-expected.txt new file mode 100644 index 0000000..85cdbf5 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/permissions-policy-frame-policy-allowed-for-some.https.sub-expected.txt
@@ -0,0 +1,156 @@ +This is a testharness.js-based test. +Found 76 FAIL, 0 TIMEOUT, 0 NOTRUN. +[FAIL] Test frame policy on same origin iframe inherit from header policy. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe inherit from header policy. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on another cross origin iframe inherit from header policy. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc iframe inherit from header policy. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + same origin iframe inherit from header policy. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + cross origin iframe inherit from header policy. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + another cross origin iframe inherit from header policy. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on data: URL cross origin iframe inherit from header policy. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "*". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "*". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on another cross origin iframe with allow = "*". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc iframe with allow = "*". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + same origin iframe with allow = "*". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + cross origin iframe with allow = "*". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + another cross origin iframe with allow = "*". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on data: URL cross origin iframe with allow = "*". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'self'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'self'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on another cross origin iframe with allow = "'self'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc iframe with allow = "'self'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + same origin iframe with allow = "'self'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + cross origin iframe with allow = "'self'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + another cross origin iframe with allow = "'self'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on data: URL cross origin iframe with allow = "'self'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'none'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'none'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on another cross origin iframe with allow = "'none'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc iframe with allow = "'none'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + same origin iframe with allow = "'none'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + cross origin iframe with allow = "'none'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + another cross origin iframe with allow = "'none'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on data: URL cross origin iframe with allow = "'none'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on another cross origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + same origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + cross origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + another cross origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on data: URL cross origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "*" and header policy = "Permissions-Policy: fullscreen=*;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "*" and header policy = "Permissions-Policy: fullscreen=*;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on another cross origin iframe with allow = "*" and header policy = "Permissions-Policy: fullscreen=*;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "*" and header policy = "Permissions-Policy: fullscreen=self;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "*" and header policy = "Permissions-Policy: fullscreen=self;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on another cross origin iframe with allow = "*" and header policy = "Permissions-Policy: fullscreen=self;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "*" and header policy = "Permissions-Policy: fullscreen=();". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "*" and header policy = "Permissions-Policy: fullscreen=();". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on another cross origin iframe with allow = "*" and header policy = "Permissions-Policy: fullscreen=();". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'self'" and header policy = "Permissions-Policy: fullscreen=*;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'self'" and header policy = "Permissions-Policy: fullscreen=*;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on another cross origin iframe with allow = "'self'" and header policy = "Permissions-Policy: fullscreen=*;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'self'" and header policy = "Permissions-Policy: fullscreen=self;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'self'" and header policy = "Permissions-Policy: fullscreen=self;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on another cross origin iframe with allow = "'self'" and header policy = "Permissions-Policy: fullscreen=self;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'self'" and header policy = "Permissions-Policy: fullscreen=();". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'self'" and header policy = "Permissions-Policy: fullscreen=();". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on another cross origin iframe with allow = "'self'" and header policy = "Permissions-Policy: fullscreen=();". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'none'" and header policy = "Permissions-Policy: fullscreen=*;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'none'" and header policy = "Permissions-Policy: fullscreen=*;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on another cross origin iframe with allow = "'none'" and header policy = "Permissions-Policy: fullscreen=*;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'none'" and header policy = "Permissions-Policy: fullscreen=self;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'none'" and header policy = "Permissions-Policy: fullscreen=self;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on another cross origin iframe with allow = "'none'" and header policy = "Permissions-Policy: fullscreen=self;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'none'" and header policy = "Permissions-Policy: fullscreen=();". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'none'" and header policy = "Permissions-Policy: fullscreen=();". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on another cross origin iframe with allow = "'none'" and header policy = "Permissions-Policy: fullscreen=();". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and header policy = "Permissions-Policy: fullscreen=*;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and header policy = "Permissions-Policy: fullscreen=*;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on another cross origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and header policy = "Permissions-Policy: fullscreen=*;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and header policy = "Permissions-Policy: fullscreen=self;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and header policy = "Permissions-Policy: fullscreen=self;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on another cross origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and header policy = "Permissions-Policy: fullscreen=self;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and header policy = "Permissions-Policy: fullscreen=();". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and header policy = "Permissions-Policy: fullscreen=();". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on another cross origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and header policy = "Permissions-Policy: fullscreen=();". + Cannot read properties of undefined (reading 'allowedFeatures') +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/permissions-policy-frame-policy-disallowed-for-all.https.sub-expected.txt b/third_party/blink/web_tests/external/wpt/permissions-policy/permissions-policy-frame-policy-disallowed-for-all.https.sub-expected.txt new file mode 100644 index 0000000..56d1320 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/permissions-policy-frame-policy-disallowed-for-all.https.sub-expected.txt
@@ -0,0 +1,160 @@ +This is a testharness.js-based test. +Found 78 FAIL, 0 TIMEOUT, 0 NOTRUN. +[FAIL] Test frame policy on same origin iframe inherit from header policy. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe inherit from header policy. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc iframe inherit from header policy. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + same origin iframe inherit from header policy. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + cross origin iframe inherit from header policy. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on data: URL cross origin iframe inherit from header policy. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "*". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "*". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc iframe with allow = "*". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + same origin iframe with allow = "*". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + cross origin iframe with allow = "*". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on data: URL cross origin iframe with allow = "*". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'self'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'self'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc iframe with allow = "'self'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + same origin iframe with allow = "'self'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + cross origin iframe with allow = "'self'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on data: URL cross origin iframe with allow = "'self'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'none'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'none'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc iframe with allow = "'none'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + same origin iframe with allow = "'none'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + cross origin iframe with allow = "'none'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on data: URL cross origin iframe with allow = "'none'". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + same origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + cross origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on data: URL cross origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "*" and header policy = "Permissions-Policy: fullscreen=*;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "*" and header policy = "Permissions-Policy: fullscreen=*;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "*" and header policy = "Permissions-Policy: fullscreen=self;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "*" and header policy = "Permissions-Policy: fullscreen=self;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "*" and header policy = "Permissions-Policy: fullscreen=();". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "*" and header policy = "Permissions-Policy: fullscreen=();". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'self'" and header policy = "Permissions-Policy: fullscreen=*;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'self'" and header policy = "Permissions-Policy: fullscreen=*;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'self'" and header policy = "Permissions-Policy: fullscreen=self;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'self'" and header policy = "Permissions-Policy: fullscreen=self;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'self'" and header policy = "Permissions-Policy: fullscreen=();". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'self'" and header policy = "Permissions-Policy: fullscreen=();". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'none'" and header policy = "Permissions-Policy: fullscreen=*;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'none'" and header policy = "Permissions-Policy: fullscreen=*;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'none'" and header policy = "Permissions-Policy: fullscreen=self;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'none'" and header policy = "Permissions-Policy: fullscreen=self;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'none'" and header policy = "Permissions-Policy: fullscreen=();". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'none'" and header policy = "Permissions-Policy: fullscreen=();". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and header policy = "Permissions-Policy: fullscreen=*;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and header policy = "Permissions-Policy: fullscreen=*;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and header policy = "Permissions-Policy: fullscreen=self;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and header policy = "Permissions-Policy: fullscreen=self;". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and header policy = "Permissions-Policy: fullscreen=();". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and header policy = "Permissions-Policy: fullscreen=();". + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "*" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "*" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc iframe with allow = "*" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + same origin iframe with allow = "*" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + cross origin iframe with allow = "*" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on data: URL cross origin iframe with allow = "*" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'self'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'self'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc iframe with allow = "'self'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + same origin iframe with allow = "'self'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + cross origin iframe with allow = "'self'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on data: URL cross origin iframe with allow = "'self'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'none'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'none'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc iframe with allow = "'none'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + same origin iframe with allow = "'none'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + cross origin iframe with allow = "'none'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on data: URL cross origin iframe with allow = "'none'" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on same origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on cross origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + same origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on srcdoc + cross origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +[FAIL] Test frame policy on data: URL cross origin iframe with allow = "'self' https://www.web-platform.test:8444 https://www.example.com" and allowfullscreen. + Cannot read properties of undefined (reading 'allowedFeatures') +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/permissions-policy-header-policy-allowed-for-all.https.sub.html b/third_party/blink/web_tests/external/wpt/permissions-policy/permissions-policy-header-policy-allowed-for-all.https.sub.html index 16a2b60c..6827bf8 100644 --- a/third_party/blink/web_tests/external/wpt/permissions-policy/permissions-policy-header-policy-allowed-for-all.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/permissions-policy-header-policy-allowed-for-all.https.sub.html
@@ -15,7 +15,7 @@ // Test that fullscreen's allowlist is ['*'] test(function() { assert_array_equals( - document.featurePolicy.getAllowlistForFeature('fullscreen'), + document.permissionsPolicy.getAllowlistForFeature('fullscreen'), ['*']); }, header_policy + ' -- test allowlist is ['*']');
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/permissions-policy-header-policy-allowed-for-malformed-wildcard.https.sub.html b/third_party/blink/web_tests/external/wpt/permissions-policy/permissions-policy-header-policy-allowed-for-malformed-wildcard.https.sub.html index 9d98d1ab..c7c4294 100644 --- a/third_party/blink/web_tests/external/wpt/permissions-policy/permissions-policy-header-policy-allowed-for-malformed-wildcard.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/permissions-policy-header-policy-allowed-for-malformed-wildcard.https.sub.html
@@ -17,7 +17,7 @@ // Test that fullscreen's allowlist lists all the malformed wildcards and self. test(function() { assert_array_equals( - document.featurePolicy.getAllowlistForFeature('fullscreen').sort(), + document.permissionsPolicy.getAllowlistForFeature('fullscreen').sort(), ["https://*.example.com", "https://{{domains[]}}:{{ports[https][0]}}"].sort()); }, header_policy + ' -- test allowlist lists all the malformed wildcards and self.');
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/permissions-policy-header-policy-allowed-for-self.https.sub.html b/third_party/blink/web_tests/external/wpt/permissions-policy/permissions-policy-header-policy-allowed-for-self.https.sub.html index 363ff0b..e1765a4 100644 --- a/third_party/blink/web_tests/external/wpt/permissions-policy/permissions-policy-header-policy-allowed-for-self.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/permissions-policy-header-policy-allowed-for-self.https.sub.html
@@ -15,7 +15,7 @@ // Test that fullscreen's allowlist is ['same_origin'] test(function() { assert_array_equals( - document.featurePolicy.getAllowlistForFeature('fullscreen'), + document.permissionsPolicy.getAllowlistForFeature('fullscreen'), [same_origin]); }, header_policy + ' -- test allowlist is [same_origin]');
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/permissions-policy-header-policy-allowed-for-some.https.sub.html b/third_party/blink/web_tests/external/wpt/permissions-policy/permissions-policy-header-policy-allowed-for-some.https.sub.html index e9d8ac14..61c73ac0 100644 --- a/third_party/blink/web_tests/external/wpt/permissions-policy/permissions-policy-header-policy-allowed-for-some.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/permissions-policy-header-policy-allowed-for-some.https.sub.html
@@ -17,7 +17,7 @@ // Test that fullscreen's allowlist is [same_origin, cross_origin, 'https://www.example.com'] test(function() { assert_array_equals( - document.featurePolicy.getAllowlistForFeature('fullscreen').sort(), + document.permissionsPolicy.getAllowlistForFeature('fullscreen').sort(), [same_origin, cross_origin, 'https://www.example.com'].sort()); }, header_policy + ' -- test allowlist is [same_origin, cross_origin, https://www.example.com]');
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/permissions-policy-header-policy-allowed-for-wildcard.https.sub.html b/third_party/blink/web_tests/external/wpt/permissions-policy/permissions-policy-header-policy-allowed-for-wildcard.https.sub.html index 713d697..70cfd38 100644 --- a/third_party/blink/web_tests/external/wpt/permissions-policy/permissions-policy-header-policy-allowed-for-wildcard.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/permissions-policy-header-policy-allowed-for-wildcard.https.sub.html
@@ -18,7 +18,7 @@ // Test that fullscreen's allowlist is [self wildcard_origin]. test(function() { assert_array_equals( - document.featurePolicy.getAllowlistForFeature('fullscreen').sort(), + document.permissionsPolicy.getAllowlistForFeature('fullscreen').sort(), [wildcard_origin, same_origin].sort()); }, header_policy + ' -- test allowlist is [self wildcard_origin].');
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/permissions-policy-header-policy-declined.https.sub.html b/third_party/blink/web_tests/external/wpt/permissions-policy/permissions-policy-header-policy-declined.https.sub.html index f02cdce7..2b48ada 100644 --- a/third_party/blink/web_tests/external/wpt/permissions-policy/permissions-policy-header-policy-declined.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/permissions-policy-header-policy-declined.https.sub.html
@@ -17,7 +17,7 @@ // Test that fullscreen's allowlist is [same_origin, cross_origin, 'https://www.example.com'] test(function() { assert_array_equals( - document.featurePolicy.getAllowlistForFeature('fullscreen'), + document.permissionsPolicy.getAllowlistForFeature('fullscreen'), [cross_origin, 'https://www.example.com'].sort()); }, header_policy + ' -- test allowlist is [cross_origin, https://www.example.com]');
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/permissions-policy-header-policy-disallowed-for-all.https.sub.html b/third_party/blink/web_tests/external/wpt/permissions-policy/permissions-policy-header-policy-disallowed-for-all.https.sub.html index f787b7d..c58375c5 100644 --- a/third_party/blink/web_tests/external/wpt/permissions-policy/permissions-policy-header-policy-disallowed-for-all.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/permissions-policy-header-policy-disallowed-for-all.https.sub.html
@@ -15,7 +15,7 @@ // Test that fullscreen's allowlist is [] test(function() { assert_array_equals( - document.featurePolicy.getAllowlistForFeature('fullscreen'), + document.permissionsPolicy.getAllowlistForFeature('fullscreen'), []); assert_false(document.fullscreenEnabled, "fullscreenEnabled should reflect permissions policy properly"); }, header_policy + ' -- test allowlist is []');
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/picture-in-picture-supported-by-permissions-policy-expected.txt b/third_party/blink/web_tests/external/wpt/permissions-policy/picture-in-picture-supported-by-permissions-policy-expected.txt new file mode 100644 index 0000000..d621817 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/picture-in-picture-supported-by-permissions-policy-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] document.permissionsPolicy.features should advertise picture-in-picture. + Cannot read properties of undefined (reading 'features') +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/picture-in-picture-supported-by-permissions-policy.html b/third_party/blink/web_tests/external/wpt/permissions-policy/picture-in-picture-supported-by-permissions-policy.html index 387a878f..a6b8bbf 100644 --- a/third_party/blink/web_tests/external/wpt/permissions-policy/picture-in-picture-supported-by-permissions-policy.html +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/picture-in-picture-supported-by-permissions-policy.html
@@ -6,6 +6,6 @@ <script src="/resources/testharnessreport.js"></script> <script> test(() => { - assert_in_array('picture-in-picture', document.featurePolicy.features()); -}, 'document.featurePolicy.features should advertise picture-in-picture.'); + assert_in_array('picture-in-picture', document.permissionsPolicy.features()); +}, 'document.permissionsPolicy.features should advertise picture-in-picture.'); </script>
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/private-state-token-issue-supported-by-permissions-policy.tentative-expected.txt b/third_party/blink/web_tests/external/wpt/permissions-policy/private-state-token-issue-supported-by-permissions-policy.tentative-expected.txt new file mode 100644 index 0000000..e49d223 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/private-state-token-issue-supported-by-permissions-policy.tentative-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] document.permissionsPolicy.features should advertise private-state-token-issuance. + Cannot read properties of undefined (reading 'features') +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/private-state-token-issue-supported-by-permissions-policy.tentative.html b/third_party/blink/web_tests/external/wpt/permissions-policy/private-state-token-issue-supported-by-permissions-policy.tentative.html index 52a392d..2ceee8f4 100644 --- a/third_party/blink/web_tests/external/wpt/permissions-policy/private-state-token-issue-supported-by-permissions-policy.tentative.html +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/private-state-token-issue-supported-by-permissions-policy.tentative.html
@@ -3,6 +3,6 @@ <script src="/resources/testharnessreport.js"></script> <script> test(() => { - assert_in_array('private-state-token-issuance', document.featurePolicy.features()); - }, 'document.featurePolicy.features should advertise private-state-token-issuance.'); + assert_in_array('private-state-token-issuance', document.permissionsPolicy.features()); + }, 'document.permissionsPolicy.features should advertise private-state-token-issuance.'); </script>
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/resources/nested-sandbox.html b/third_party/blink/web_tests/external/wpt/permissions-policy/resources/nested-sandbox.html index 4ba5121..c987e6f0 100644 --- a/third_party/blink/web_tests/external/wpt/permissions-policy/resources/nested-sandbox.html +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/resources/nested-sandbox.html
@@ -3,6 +3,6 @@ <script> "use strict"; window.onload = () => { - window.parent.postMessage(document.featurePolicy.allowedFeatures().includes("fullscreen"),"*"); + window.parent.postMessage(document.permissionsPolicy.allowedFeatures().includes("fullscreen"),"*"); }; </script>
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/resources/permissions-policy-allowedfeatures.html b/third_party/blink/web_tests/external/wpt/permissions-policy/resources/permissions-policy-allowedfeatures.html index f4b02027..48d02a6 100644 --- a/third_party/blink/web_tests/external/wpt/permissions-policy/resources/permissions-policy-allowedfeatures.html +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/resources/permissions-policy-allowedfeatures.html
@@ -2,6 +2,6 @@ 'use strict'; window.onload = function() { - parent.postMessage(document.featurePolicy.allowedFeatures(), '*'); + parent.postMessage(document.permissionsPolicy.allowedFeatures(), '*'); } </script>
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/resources/permissions-policy.js b/third_party/blink/web_tests/external/wpt/permissions-policy/resources/permissions-policy.js index a8ce97f..cfc6d3ca 100644 --- a/third_party/blink/web_tests/external/wpt/permissions-policy/resources/permissions-policy.js +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/resources/permissions-policy.js
@@ -463,7 +463,7 @@ document.body.appendChild(frame); // frame_policy should be dynamically updated as allow and allowfullscreen is // updated. - var frame_policy = frame.featurePolicy; + var frame_policy = frame.permissionsPolicy; if (typeof allow !== 'undefined') { frame.setAttribute('allow', allow); }
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/resources/sandbox-self.html b/third_party/blink/web_tests/external/wpt/permissions-policy/resources/sandbox-self.html index 8240de9..ba7a41f 100644 --- a/third_party/blink/web_tests/external/wpt/permissions-policy/resources/sandbox-self.html +++ b/third_party/blink/web_tests/external/wpt/permissions-policy/resources/sandbox-self.html
@@ -10,7 +10,7 @@ var handle_message = evt => { if (evt.source === frame.contentWindow) { window.parent.postMessage({ - "child": document.featurePolicy.allowedFeatures().includes("fullscreen"), + "child": document.permissionsPolicy.allowedFeatures().includes("fullscreen"), "grandchild": evt.data },"*"); document.body.removeChild(frame);
diff --git a/third_party/blink/web_tests/external/wpt/permissions/feature-policy-permissions-query.html b/third_party/blink/web_tests/external/wpt/permissions/permissions-policy-permissions-query.html similarity index 100% rename from third_party/blink/web_tests/external/wpt/permissions/feature-policy-permissions-query.html rename to third_party/blink/web_tests/external/wpt/permissions/permissions-policy-permissions-query.html
diff --git a/third_party/blink/web_tests/external/wpt/permissions/permissions-query-feature-policy-attribute.https.sub.html b/third_party/blink/web_tests/external/wpt/permissions/permissions-query-permissions-policy-attribute.https.sub.html similarity index 96% rename from third_party/blink/web_tests/external/wpt/permissions/permissions-query-feature-policy-attribute.https.sub.html rename to third_party/blink/web_tests/external/wpt/permissions/permissions-query-permissions-policy-attribute.https.sub.html index 1d7333d9..2e7121e 100644 --- a/third_party/blink/web_tests/external/wpt/permissions/permissions-query-feature-policy-attribute.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/permissions/permissions-query-permissions-policy-attribute.https.sub.html
@@ -30,7 +30,7 @@ } const same_origin_src = - "/permissions/feature-policy-permissions-query.html"; + "/permissions/permissions-policy-permissions-query.html"; const cross_origin_src = "https://{{domains[www]}}:{{ports[https][0]}}" + same_origin_src;
diff --git a/third_party/blink/web_tests/external/wpt/preload/preload-imagesrcset-no-href.html b/third_party/blink/web_tests/external/wpt/preload/preload-imagesrcset-no-href.html new file mode 100644 index 0000000..f7a796a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/preload/preload-imagesrcset-no-href.html
@@ -0,0 +1,78 @@ +<!DOCTYPE html> +<title>Preload with imagesrcset but no href should trigger a preload</title> +<meta name="timeout" content="long"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/preload/resources/preload_helper.js"></script> +<script> + var inlineImageLoaded = false; +</script> +<link rel=preload as=image imagesrcset="resources/square.png?inline-no-href-1x 1x, resources/square.png?inline-no-href-2x 2x" onload="inlineImageLoaded = true;"> +<body> +<script> + promise_test(async function(t) { + verifyPreloadAndRTSupport(); + + var link = document.createElement("link"); + link.as = "image"; + link.rel = "preload"; + link.imageSrcset = "resources/square.png?dynamic-w-200 200w, resources/square.png?dynamic-w-400 400w, resources/square.png?dynamic-w-800 800w"; + link.imageSizes = "400px"; + + await new Promise((resolve, reject) => { + link.onload = resolve; + link.onerror = reject; + document.body.appendChild(link); + }); + + // Only ONE of the srcset URLs should have been fetched. + var total = numberOfResourceTimingEntries("resources/square.png?dynamic-w-200") + + numberOfResourceTimingEntries("resources/square.png?dynamic-w-400") + + numberOfResourceTimingEntries("resources/square.png?dynamic-w-800"); + assert_equals(total, 1, "only one w-descriptor image should be preloaded"); + }, "Dynamically added preload with imagesrcset (w descriptors) and no href"); + + promise_test(async function(t) { + verifyPreloadAndRTSupport(); + + var link = document.createElement("link"); + link.as = "image"; + link.rel = "preload"; + link.imageSrcset = "resources/square.png?dynamic-x-1x 1x, resources/square.png?dynamic-x-2x 2x"; + + await new Promise((resolve, reject) => { + link.onload = resolve; + link.onerror = reject; + document.body.appendChild(link); + }); + + var total = numberOfResourceTimingEntries("resources/square.png?dynamic-x-1x") + + numberOfResourceTimingEntries("resources/square.png?dynamic-x-2x"); + assert_equals(total, 1, "only one x-descriptor image should be preloaded"); + }, "Dynamically added preload with imagesrcset (x descriptors) and no href"); + + promise_test(async function(t) { + verifyPreloadAndRTSupport(); + + // Wait for the inline link to have a chance to load. + if (!inlineImageLoaded) { + await new Promise(resolve => { + var check = () => { + if (inlineImageLoaded) { + resolve(); + } else { + step_timeout(check, 100); + } + }; + step_timeout(check, 100); + }); + } + + assert_true(inlineImageLoaded, "inline preload with imagesrcset and no href should fire load event"); + + var total = numberOfResourceTimingEntries("resources/square.png?inline-no-href-1x") + + numberOfResourceTimingEntries("resources/square.png?inline-no-href-2x"); + assert_equals(total, 1, "only one inline imagesrcset image should be preloaded"); + }, "Inline preload link with imagesrcset and no href fires load event"); +</script> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/screen-wake-lock/wakelock-supported-by-permissions-policy-expected.txt b/third_party/blink/web_tests/external/wpt/screen-wake-lock/wakelock-supported-by-permissions-policy-expected.txt new file mode 100644 index 0000000..86523c0b --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/screen-wake-lock/wakelock-supported-by-permissions-policy-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] document.permissionsPolicy.features should advertise screen-wake-lock. + Cannot read properties of undefined (reading 'features') +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/screen-wake-lock/wakelock-supported-by-permissions-policy.html b/third_party/blink/web_tests/external/wpt/screen-wake-lock/wakelock-supported-by-permissions-policy.html index cc0bb96..acb9747 100644 --- a/third_party/blink/web_tests/external/wpt/screen-wake-lock/wakelock-supported-by-permissions-policy.html +++ b/third_party/blink/web_tests/external/wpt/screen-wake-lock/wakelock-supported-by-permissions-policy.html
@@ -1,11 +1,11 @@ <!DOCTYPE html> <title>Test that screen-wake-lock is advertised in the feature list</title> -<link rel="help" href="https://w3c.github.io/webappsec-feature-policy/#dom-featurepolicy-features"> +<link rel="help" href="https://w3c.github.io/webappsec-permissions-policy/#dom-permissions-policy-features"> <link rel="help" href="https://w3c.github.io/screen-wake-lock/#dfn-wake-lock-feature"> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script> test(() => { - assert_in_array('screen-wake-lock', document.featurePolicy.features()); -}, 'document.featurePolicy.features should advertise screen-wake-lock.'); + assert_in_array('screen-wake-lock', document.permissionsPolicy.features()); +}, 'document.permissionsPolicy.features should advertise screen-wake-lock.'); </script>
diff --git a/third_party/blink/web_tests/external/wpt/selection/onselectstart-on-key-in-contenteditable.html b/third_party/blink/web_tests/external/wpt/selection/onselectstart-on-key-in-contenteditable.html new file mode 100644 index 0000000..1094ac13 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/selection/onselectstart-on-key-in-contenteditable.html
@@ -0,0 +1,457 @@ +<!doctype html> +<html> +<head> +<meta charset="utf-8"> +<meta name="timeout" content="long"> +<meta name="variant" content="?preventDefault=no"> +<meta name="variant" content="?preventDefault=yes"> +<title>selectstart event</title> +<link rel="help" href="https://w3c.github.io/selection-api/#selectstart-event"> +<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"; + +const searchParams = new URLSearchParams(document.location.search); +const preventDefault = searchParams.get("preventDefault") == "yes"; + +addEventListener("load", () => { + const shiftKey = "\uE008"; + const arrowLeftKey = "\uE012"; + const arrowUpKey = "\uE013"; + const arrowRightKey = "\uE014"; + const arrowDownKey = "\uE015"; + const pageUpKey = "\uE00E"; + const pageDownKey = "\uE00F"; + const endKey = "\uE010"; + const homeKey = "\uE011"; + const metaKey = "\uE03d"; + const controlKey = "\uE009"; + const accelKey = navigator.platform.includes("Mac") ? metaKey : controlKey; + const editingHost = document.querySelector("div[contenteditable]"); + const Text_abc = editingHost.firstChild; + const Text_def = Text_abc.nextSibling.nextSibling; + const Text_789 = editingHost.lastChild.previousSibling; + + function getRangeDescription(range) { + if (range === null) { + return "null"; + } + if (range === undefined) { + return "undefined"; + } + function getNodeDescription(node) { + if (!node) { + return "null"; + } + switch (node.nodeType) { + case Node.TEXT_NODE: + case Node.COMMENT_NODE: + case Node.CDATA_SECTION_NODE: + return `${node.nodeName} "${node.data.replaceAll("\n", "\\\\n")}"`; + case Node.ELEMENT_NODE: + return `<${node.nodeName.toLowerCase()}${ + node.hasAttribute("id") ? ` id="${node.getAttribute("id")}"` : "" + }${ + node.hasAttribute("class") ? ` class="${node.getAttribute("class")}"` : "" + }${ + node.hasAttribute("contenteditable") + ? ` contenteditable="${node.getAttribute("contenteditable")}"` + : "" + }${ + node.inert ? ` inert` : "" + }${ + node.hidden ? ` hidden` : "" + }${ + node.readonly ? ` readonly` : "" + }${ + node.disabled ? ` disabled` : "" + }>`; + default: + return `${node.nodeName}`; + } + } + return range.startContainer == range.endContainer && + range.startOffset == range.endOffset + ? `(${getNodeDescription(range.startContainer)}, ${range.startOffset})(collapsed)` + : `(${getNodeDescription(range.startContainer)}, ${ + range.startOffset + }) - (${getNodeDescription(range.endContainer)}, ${range.endOffset})`; + } + + let selectstartEvent = null; + document.addEventListener("selectstart", event => { + if (preventDefault) { + event.preventDefault(); + } + selectstartEvent = event; + }); + + function assert_selectstart(testName, originalRange) { + if (!originalRange.includes("(collapsed)")) { + assert_equals( + selectstartEvent, + null, + `${testName}: "selectstart" shouldn't be fired because selection was not collapsed` + ); + return; + } + if (preventDefault) { + assert_equals( + getRangeDescription(getSelection().rangeCount ? getSelection().getRangeAt(0) : null), + originalRange, + `${testName}: selection range should not be changed if preventDefault() of "selectstart" event is called` + ); + } else { + if (getSelection().isCollapsed) { + assert_equals( + selectstartEvent, + null, + `${testName}: "selectstart" shouldn't be fired because selection is still collapsed` + ); + } else { + assert_not_equals( + selectstartEvent, + null, + `${testName}: "selectstart" should be fired because selection is extended` + ); + } + } + } + + // character move + promise_test(async t => { + getSelection().collapse(Text_abc, 0); + const originalRange = getRangeDescription(getSelection().getRangeAt(0)); + selectstartEvent = null; + await new test_driver.Actions() + .keyDown(shiftKey) + .keyDown(arrowLeftKey) + .keyUp(arrowLeftKey) + .keyUp(shiftKey) + .send(); + assert_selectstart(t.name, originalRange); + }, `Shift+ArrowLeft when <div contenteditable>[]abc<br>`); + + promise_test(async t => { + getSelection().collapse(Text_abc, 1); + const originalRange = getRangeDescription(getSelection().getRangeAt(0)); + selectstartEvent = null; + await new test_driver.Actions() + .keyDown(shiftKey) + .keyDown(arrowLeftKey) + .keyUp(arrowLeftKey) + .keyUp(shiftKey) + .send(); + assert_selectstart(t.name, originalRange); + }, `Shift+ArrowLeft when <div contenteditable>a[]bc<br>`); + + promise_test(async t => { + getSelection().collapse(Text_abc, 1); + const originalRange = getRangeDescription(getSelection().getRangeAt(0)); + selectstartEvent = null; + await new test_driver.Actions() + .keyDown(shiftKey) + .keyDown(arrowRightKey) + .keyUp(arrowRightKey) + .keyUp(shiftKey) + .send(); + assert_selectstart(t.name, originalRange); + }, `Shift+ArrowRight when <div contenteditable>a[]bc<br>`); + + promise_test(async t => { + getSelection().collapse(Text_789, 3); + const originalRange = getRangeDescription(getSelection().getRangeAt(0)); + selectstartEvent = null; + await new test_driver.Actions() + .keyDown(shiftKey) + .keyDown(arrowRightKey) + .keyUp(arrowRightKey) + .keyUp(shiftKey) + .send(); + assert_selectstart(t.name, originalRange); + }, `Shift+ArrowRight when 789[]<br></div>`); + + // line move + promise_test(async t => { + getSelection().collapse(Text_abc, 0); + const originalRange = getRangeDescription(getSelection().getRangeAt(0)); + selectstartEvent = null; + await new test_driver.Actions() + .keyDown(shiftKey) + .keyDown(arrowUpKey) + .keyUp(arrowUpKey) + .keyUp(shiftKey) + .send(); + assert_selectstart(t.name, originalRange); + }, `Shift+ArrowUp when <div contenteditable>[]abc<br>`); + + promise_test(async t => { + getSelection().collapse(Text_abc, 1); + const originalRange = getRangeDescription(getSelection().getRangeAt(0)); + selectstartEvent = null; + await new test_driver.Actions() + .keyDown(shiftKey) + .keyDown(arrowUpKey) + .keyUp(arrowUpKey) + .keyUp(shiftKey) + .send(); + assert_selectstart(t.name, originalRange); + }, `Shift+ArrowUp when <div contenteditable>a[]bc<br>`); + + promise_test(async t => { + getSelection().collapse(Text_abc, 1); + const originalRange = getRangeDescription(getSelection().getRangeAt(0)); + selectstartEvent = null; + await new test_driver.Actions() + .keyDown(shiftKey) + .keyDown(arrowDownKey) + .keyUp(arrowDownKey) + .keyUp(shiftKey) + .send(); + assert_selectstart(t.name, originalRange); + }, `Shift+ArrowDown when <div contenteditable>a[]bc<br>`); + + promise_test(async t => { + getSelection().collapse(Text_789, 3); + const originalRange = getRangeDescription(getSelection().getRangeAt(0)); + selectstartEvent = null; + await new test_driver.Actions() + .keyDown(shiftKey) + .keyDown(arrowDownKey) + .keyUp(arrowDownKey) + .keyUp(shiftKey) + .send(); + assert_selectstart(t.name, originalRange); + }, `Shift+ArrowDown when 789[]<br></div>`); + + promise_test(async t => { + getSelection().collapse(Text_789, 2); + const originalRange = getRangeDescription(getSelection().getRangeAt(0)); + selectstartEvent = null; + await new test_driver.Actions() + .keyDown(shiftKey) + .keyDown(arrowDownKey) + .keyUp(arrowDownKey) + .keyUp(shiftKey) + .send(); + assert_selectstart(t.name, originalRange); + }, `Shift+ArrowDown when 78[]9<br></div>`); + + promise_test(async t => { + getSelection().collapse(Text_789, 2); + const originalRange = getRangeDescription(getSelection().getRangeAt(0)); + selectstartEvent = null; + await new test_driver.Actions() + .keyDown(shiftKey) + .keyDown(arrowUpKey) + .keyUp(arrowUpKey) + .keyUp(shiftKey) + .send(); + assert_selectstart(t.name, originalRange); + }, `Shift+ArrowUp when 78[]9<br></div>`); + + // page move + promise_test(async t => { + getSelection().collapse(Text_abc, 0); + const originalRange = getRangeDescription(getSelection().getRangeAt(0)); + selectstartEvent = null; + await new test_driver.Actions() + .keyDown(shiftKey) + .keyDown(pageUpKey) + .keyUp(pageUpKey) + .keyUp(shiftKey) + .send(); + assert_selectstart(t.name, originalRange); + }, `Shift+PageUp when <div contenteditable>[]abc<br>`); + + promise_test(async t => { + getSelection().collapse(Text_abc, 1); + const originalRange = getRangeDescription(getSelection().getRangeAt(0)); + selectstartEvent = null; + await new test_driver.Actions() + .keyDown(shiftKey) + .keyDown(pageUpKey) + .keyUp(pageUpKey) + .keyUp(shiftKey) + .send(); + assert_selectstart(t.name, originalRange); + }, `Shift+PageUp when <div contenteditable>a[]bc<br>`); + + promise_test(async t => { + getSelection().collapse(Text_abc, 1); + const originalRange = getRangeDescription(getSelection().getRangeAt(0)); + selectstartEvent = null; + await new test_driver.Actions() + .keyDown(shiftKey) + .keyDown(pageDownKey) + .keyUp(pageDownKey) + .keyUp(shiftKey) + .send(); + assert_selectstart(t.name, originalRange); + }, `Shift+PageDown when <div contenteditable>a[]bc<br>`); + + promise_test(async t => { + getSelection().collapse(Text_789, 3); + const originalRange = getRangeDescription(getSelection().getRangeAt(0)); + selectstartEvent = null; + await new test_driver.Actions() + .keyDown(shiftKey) + .keyDown(pageDownKey) + .keyUp(pageDownKey) + .keyUp(shiftKey) + .send(); + assert_selectstart(t.name, originalRange); + }, `Shift+PageDown when 789[]<br></div>`); + + promise_test(async t => { + getSelection().collapse(Text_789, 2); + const originalRange = getRangeDescription(getSelection().getRangeAt(0)); + selectstartEvent = null; + await new test_driver.Actions() + .keyDown(shiftKey) + .keyDown(pageDownKey) + .keyUp(pageDownKey) + .keyUp(shiftKey) + .send(); + assert_selectstart(t.name, originalRange); + }, `Shift+PageDown when 78[]9<br></div>`); + + promise_test(async t => { + getSelection().collapse(Text_789, 2); + const originalRange = getRangeDescription(getSelection().getRangeAt(0)); + selectstartEvent = null; + await new test_driver.Actions() + .keyDown(shiftKey) + .keyDown(pageUpKey) + .keyUp(pageUpKey) + .keyUp(shiftKey) + .send(); + assert_selectstart(t.name, originalRange); + }, `Shift+PageUp when 78[]9<br></div>`); + + // Home/End + promise_test(async t => { + getSelection().collapse(editingHost, 0); + const originalRange = getRangeDescription(getSelection().getRangeAt(0)); + selectstartEvent = null; + await new test_driver.Actions() + .keyDown(shiftKey) + .keyDown(homeKey) + .keyUp(homeKey) + .keyUp(shiftKey) + .send(); + assert_selectstart(t.name, originalRange); + }, `Shift+Home when <div contenteditable>[]abc<br>`); + + promise_test(async t => { + getSelection().collapse(editingHost, 1); + const originalRange = getRangeDescription(getSelection().getRangeAt(0)); + selectstartEvent = null; + await new test_driver.Actions() + .keyDown(shiftKey) + .keyDown(homeKey) + .keyUp(homeKey) + .keyUp(shiftKey) + .send(); + assert_selectstart(t.name, originalRange); + }, `Shift+Home when <div contenteditable>a[]bc<br>`); + + promise_test(async t => { + getSelection().collapse(editingHost, 1); + const originalRange = getRangeDescription(getSelection().getRangeAt(0)); + selectstartEvent = null; + await new test_driver.Actions() + .keyDown(shiftKey) + .keyDown(endKey) + .keyUp(endKey) + .keyUp(shiftKey) + .send(); + assert_selectstart(t.name, originalRange); + }, `Shift+End when <div contenteditable>a[]bc<br>`); + + promise_test(async t => { + getSelection().collapse(Text_789, 3); + const originalRange = getRangeDescription(getSelection().getRangeAt(0)); + selectstartEvent = null; + await new test_driver.Actions() + .keyDown(shiftKey) + .keyDown(endKey) + .keyUp(endKey) + .keyUp(shiftKey) + .send(); + assert_selectstart(t.name, originalRange); + }, `Shift+End when 789[]<br></div>`); + + // Select All + promise_test(async t => { + getSelection().collapse(Text_789, 3); + const originalRange = getRangeDescription(getSelection().getRangeAt(0)); + selectstartEvent = null; + await new test_driver.Actions() + .keyDown(accelKey) + .keyDown("a") + .keyUp("a") + .keyUp(accelKey) + .send(); + assert_selectstart(t.name, originalRange); + }, `Select All when 789[]<br></div>`); + + // not collapsed + for (const data of [ + { modifierName: "Shift", keyName: "ArrowLeft", modifier: shiftKey, key: arrowLeftKey }, + { modifierName: "Shift", keyName: "ArrowRight", modifier: shiftKey, key: arrowRightKey }, + { modifierName: "Shift", keyName: "ArrowUp", modifier: shiftKey, key: arrowUpKey }, + { modifierName: "Shift", keyName: "ArrowDown", modifier: shiftKey, key: arrowDownKey }, + { modifierName: "Shift", keyName: "PageDown", modifier: shiftKey, key: pageDownKey }, + { modifierName: "Shift", keyName: "PageUp", modifier: shiftKey, key: pageUpKey }, + { modifierName: "Shift", keyName: "Home", modifier: shiftKey, key: homeKey }, + { modifierName: "Shift", keyName: "End", modifier: shiftKey, key: endKey }, + ]) { + promise_test(async t => { + getSelection().setBaseAndExtent(Text_def, 1, Text_def, 2); + const originalRange = getRangeDescription(getSelection().getRangeAt(0)); + selectstartEvent = null; + await new test_driver.Actions() + .keyDown(data.modifier) + .keyDown(data.key) + .keyUp(data.key) + .keyUp(data.modifier) + .send(); + assert_selectstart(t.name, originalRange); + }, `${data.modifierName}+${data.keyName} when d[e]f<br>`); + } + + promise_test(async t => { + getSelection().setBaseAndExtent(Text_def, 1, Text_def, 2); + const originalRange = getRangeDescription(getSelection().getRangeAt(0)); + selectstartEvent = null; + await new test_driver.Actions() + .keyDown(accelKey) + .keyDown("a") + .keyUp("a") + .keyUp(accelKey) + .send(); + assert_selectstart(t.name, originalRange); + }, `Select All when d[e]f<br>`); +}, {once: true}); +</script> +</head> +<body> +<div contenteditable style="height:5em">abc<br +>def<br +>ghi<br +>jkl<br +>mno<br +>pqr<br +>stu<br +>vwx<br +>yz0<br +>123<br +>456<br +>789<br></div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/selection/onselectstart-on-key-in-contenteditable_preventDefault=no-expected.txt b/third_party/blink/web_tests/external/wpt/selection/onselectstart-on-key-in-contenteditable_preventDefault=no-expected.txt new file mode 100644 index 0000000..484dd4e --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/selection/onselectstart-on-key-in-contenteditable_preventDefault=no-expected.txt
@@ -0,0 +1,13 @@ +This is a testharness.js-based test. +[FAIL] Shift+PageUp when <div contenteditable>a[]bc<br> + assert_not_equals: Shift+PageUp when <div contenteditable>a[]bc<br>: "selectstart" should be fired because selection is extended got disallowed value null +[FAIL] Shift+PageDown when <div contenteditable>a[]bc<br> + assert_not_equals: Shift+PageDown when <div contenteditable>a[]bc<br>: "selectstart" should be fired because selection is extended got disallowed value null +[FAIL] Shift+PageDown when 78[]9<br></div> + assert_not_equals: Shift+PageDown when 78[]9<br></div>: "selectstart" should be fired because selection is extended got disallowed value null +[FAIL] Shift+PageUp when 78[]9<br></div> + assert_not_equals: Shift+PageUp when 78[]9<br></div>: "selectstart" should be fired because selection is extended got disallowed value null +[FAIL] Select All when d[e]f<br> + assert_equals: Select All when d[e]f<br>: "selectstart" shouldn't be fired because selection was not collapsed expected null but got object "[object Event]" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/selection/onselectstart-on-key-in-contenteditable_preventDefault=yes-expected.txt b/third_party/blink/web_tests/external/wpt/selection/onselectstart-on-key-in-contenteditable_preventDefault=yes-expected.txt new file mode 100644 index 0000000..6b6c3f4 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/selection/onselectstart-on-key-in-contenteditable_preventDefault=yes-expected.txt
@@ -0,0 +1,17 @@ +This is a testharness.js-based test. +[FAIL] Shift+PageUp when <div contenteditable>a[]bc<br> + assert_equals: Shift+PageUp when <div contenteditable>a[]bc<br>: selection range should not be changed if preventDefault() of "selectstart" event is called expected "(#text \\"abc\\", 1)(collapsed)" but got "(#text \\"abc\\", 0) - (#text \\"abc\\", 1)" +[FAIL] Shift+PageDown when <div contenteditable>a[]bc<br> + assert_equals: Shift+PageDown when <div contenteditable>a[]bc<br>: selection range should not be changed if preventDefault() of "selectstart" event is called expected "(#text \\"abc\\", 1)(collapsed)" but got "(#text \\"abc\\", 1) - (#text \\"jkl\\", 1)" +[FAIL] Shift+PageDown when 78[]9<br></div> + assert_equals: Shift+PageDown when 78[]9<br></div>: selection range should not be changed if preventDefault() of "selectstart" event is called expected "(#text \\"789\\", 2)(collapsed)" but got "(#text \\"789\\", 2) - (#text \\"789\\", 3)" +[FAIL] Shift+PageUp when 78[]9<br></div> + assert_equals: Shift+PageUp when 78[]9<br></div>: selection range should not be changed if preventDefault() of "selectstart" event is called expected "(#text \\"789\\", 2)(collapsed)" but got "(#text \\"yz0\\", 2) - (#text \\"789\\", 2)" +[FAIL] Shift+Home when <div contenteditable>[]abc<br> + assert_equals: Shift+Home when <div contenteditable>[]abc<br>: selection range should not be changed if preventDefault() of "selectstart" event is called expected "(<div contenteditable=\\"\\">, 0)(collapsed)" but got "(#text \\"abc\\", 0)(collapsed)" +[FAIL] Shift+End when <div contenteditable>a[]bc<br> + assert_equals: Shift+End when <div contenteditable>a[]bc<br>: selection range should not be changed if preventDefault() of "selectstart" event is called expected "(<div contenteditable=\\"\\">, 1)(collapsed)" but got "(#text \\"abc\\", 3)(collapsed)" +[FAIL] Select All when d[e]f<br> + assert_equals: Select All when d[e]f<br>: "selectstart" shouldn't be fired because selection was not collapsed expected null but got object "[object Event]" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/shadow-dom/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/shadow-dom/WEB_FEATURES.yml index ca2e78f4..82f6a0b 100644 --- a/third_party/blink/web_tests/external/wpt/shadow-dom/WEB_FEATURES.yml +++ b/third_party/blink/web_tests/external/wpt/shadow-dom/WEB_FEATURES.yml
@@ -10,6 +10,7 @@ - "!slotchange*.html" - "!slots*.html" - "!Document-caretPositionFromPoint.tentative.html" + - "!HighlightRegistry-highlightsFromPoint.html" # Keep mappings below in sync with `shadow-map` mapping. - name: slot-assign files: @@ -24,3 +25,6 @@ - name: document-caretpositionfrompoint files: - Document-caretPositionFromPoint.tentative.html +- name: highlightsfrompoint + files: + - HighlightRegistry-highlightsFromPoint.html
diff --git a/third_party/blink/web_tests/external/wpt/shadow-dom/inserting-fragment-under-shadow-host.html b/third_party/blink/web_tests/external/wpt/shadow-dom/inserting-fragment-under-shadow-host.html new file mode 100644 index 0000000..404ba72 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/shadow-dom/inserting-fragment-under-shadow-host.html
@@ -0,0 +1,29 @@ +<!DOCTYPE html> +<html> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + +promise_test(() => { + const host = document.createElement('span'); + document.body.appendChild(host); + const shadowRoot = host.attachShadow({mode: 'closed'}); + shadowRoot.innerHTML = '<slot></slot>'; + + let slotchangeDidFire = false; + shadowRoot.querySelector('slot').addEventListener('slotchange', () => slotchangeDidFire = true); + host.innerHTML = '<span slot="unused"></span>b<span slot="unused"></span>'; + + return new Promise((resolve) => { + queueMicrotask(() => { + assert_true(slotchangeDidFire); + host.remove(); + resolve(); + }); + }) +}, 'This tests inserting a document fragment with a mixture of elements and text nodes, which should dispatch a `slotchange` event.'); + +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/svg/animations/custom-events.html b/third_party/blink/web_tests/external/wpt/svg/animations/custom-events.html index 1c49106..c2f83a9 100644 --- a/third_party/blink/web_tests/external/wpt/svg/animations/custom-events.html +++ b/third_party/blink/web_tests/external/wpt/svg/animations/custom-events.html
@@ -1,55 +1,64 @@ <!DOCTYPE html> -<title>Custom events with the names "end" and "endEvent" and their effects on various types of event listeners</title> +<title>Custom events with SVG animation event names and their effects on various types of event listeners</title> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <svg height="0"> <rect width="100" height="100" fill="blue"> <animate attributeName="x" begin="0s" from="0" to="100" - id="targetWithAttributeHandlers" + id="endTargetWithAttributeHandlers" onend="gOnEndHandlerCallCount++" onendEvent="gNonexistentOnEndEventHandlerCallCount++"/> <animate attributeName="y" begin="0s" from="0" to="100" - id="targetWithIDLListeners"/> + id="endTargetWithIDLListeners"/> <animate attributeName="width" begin="0s" from="100" to="120" - id="targetWithRegularListeners"/> + id="endTargetWithRegularListeners"/> + <animate attributeName="x" begin="0s" from="0" to="100" + id="repeatTargetWithAttributeHandlers" + onrepeat="gOnRepeatHandlerCallCount++" + onrepeatEvent="gNonexistentOnRepeatEventHandlerCallCount++"/> + <animate attributeName="y" begin="0s" from="0" to="100" + id="repeatTargetWithIDLListeners"/> + <animate attributeName="width" begin="0s" from="100" to="120" + id="repeatTargetWithRegularListeners"/> + <animate attributeName="x" begin="0s" from="0" to="100" + id="beginTargetWithAttributeHandlers" + onbegin="gOnBeginHandlerCallCount++" + onbeginEvent="gNonexistentOnBeginEventHandlerCallCount++"/> + <animate attributeName="y" begin="0s" from="0" to="100" + id="beginTargetWithIDLListeners"/> + <animate attributeName="width" begin="0s" from="100" to="120" + id="beginTargetWithRegularListeners"/> </rect> </svg> <script> - // This test checks how various types of event handlers / listeners react to custom - // events with the names "end" and "endEvent". + // === "end" / "endEvent" tests === // The SVG spec does not define an event called "end" - the animation event is called "endEvent". // The SVG spec does not define an IDL property called "onendEvent", only one called "onend". // The SVG spec does not define an attribute called "onendEvent", only one called "onend". - // Incremented in the "onend" attribute event handler. gOnEndHandlerCallCount = 0; - // "onendEvent" is an invalid attribute name so this should never be incremented. gNonexistentOnEndEventHandlerCallCount = 0; - // Incremented in the "onend" IDL property event listener. gOnEndListenerCallCount = 0; - // "onendEvent" is an unrecognized property name so this should never be incremented. gNonexistentOnEndEventListenerCallCount = 0; - // Incremented in the "endEvent" event listener. gEndEventListenerCallCount = 0; - // Incremented in the "end" event listener. This should only happen for manually-created events with the name "end". gEndListenerCallCount = 0; - let targetWithAttributeHandlers = document.getElementById("targetWithAttributeHandlers"); - let targetWithIDLListeners = document.getElementById("targetWithIDLListeners"); - targetWithIDLListeners.onend = () => { gOnEndListenerCallCount++; }; - targetWithIDLListeners.onendEvent = () => { gNonexistentOnEndEventListenerCallCount++; }; - let targetWithRegularListeners = document.getElementById("targetWithRegularListeners"); - targetWithRegularListeners.addEventListener("endEvent", () => { gEndEventListenerCallCount++; }); - targetWithRegularListeners.addEventListener("end", () => { gEndListenerCallCount++; }); + let endTargetWithAttributeHandlers = document.getElementById("endTargetWithAttributeHandlers"); + let endTargetWithIDLListeners = document.getElementById("endTargetWithIDLListeners"); + endTargetWithIDLListeners.onend = () => { gOnEndListenerCallCount++; }; + endTargetWithIDLListeners.onendEvent = () => { gNonexistentOnEndEventListenerCallCount++; }; + let endTargetWithRegularListeners = document.getElementById("endTargetWithRegularListeners"); + endTargetWithRegularListeners.addEventListener("endEvent", () => { gEndEventListenerCallCount++; }); + endTargetWithRegularListeners.addEventListener("end", () => { gEndListenerCallCount++; }); test(t => { - targetWithAttributeHandlers.dispatchEvent(new Event("end")); + endTargetWithAttributeHandlers.dispatchEvent(new Event("end")); assert_equals(gOnEndHandlerCallCount, 0); assert_equals(gNonexistentOnEndEventHandlerCallCount, 0); - targetWithIDLListeners.dispatchEvent(new Event("end")); + endTargetWithIDLListeners.dispatchEvent(new Event("end")); assert_equals(gOnEndListenerCallCount, 0); assert_equals(gNonexistentOnEndEventListenerCallCount, 0); - targetWithRegularListeners.dispatchEvent(new Event("end")); + endTargetWithRegularListeners.dispatchEvent(new Event("end")); assert_equals(gEndEventListenerCallCount, 0); assert_equals(gEndListenerCallCount, 1); }, "custom events with the name 'end' should only call the event listener for the event 'end' and no attribute handlers or IDL listeners"); @@ -61,15 +70,115 @@ gNonexistentOnEndEventListenerCallCount = 0; gEndEventListenerCallCount = 0; gEndListenerCallCount = 0; - targetWithAttributeHandlers.dispatchEvent(new Event("endEvent")); + endTargetWithAttributeHandlers.dispatchEvent(new Event("endEvent")); assert_equals(gOnEndHandlerCallCount, 1); assert_equals(gNonexistentOnEndEventHandlerCallCount, 0); - targetWithIDLListeners.dispatchEvent(new Event("endEvent")); + endTargetWithIDLListeners.dispatchEvent(new Event("endEvent")); assert_equals(gOnEndListenerCallCount, 1); assert_equals(gNonexistentOnEndEventListenerCallCount, 0); - targetWithRegularListeners.dispatchEvent(new Event("endEvent")); + endTargetWithRegularListeners.dispatchEvent(new Event("endEvent")); assert_equals(gEndEventListenerCallCount, 1); assert_equals(gEndListenerCallCount, 0); }, "custom events with the name 'endEvent' should call 'onend' attribute handlers and IDL property listeners, and 'endEvent' listeners"); + // === "repeat" / "repeatEvent" tests === + // The SVG spec does not define an event called "repeat" - the animation event is called "repeatEvent". + // The SVG spec does not define an IDL property called "onrepeatEvent", only one called "onrepeat". + // The SVG spec does not define an attribute called "onrepeatEvent", only one called "onrepeat". + + gOnRepeatHandlerCallCount = 0; + gNonexistentOnRepeatEventHandlerCallCount = 0; + gOnRepeatListenerCallCount = 0; + gNonexistentOnRepeatEventListenerCallCount = 0; + gRepeatEventListenerCallCount = 0; + gRepeatListenerCallCount = 0; + + let repeatTargetWithAttributeHandlers = document.getElementById("repeatTargetWithAttributeHandlers"); + let repeatTargetWithIDLListeners = document.getElementById("repeatTargetWithIDLListeners"); + repeatTargetWithIDLListeners.onrepeat = () => { gOnRepeatListenerCallCount++; }; + repeatTargetWithIDLListeners.onrepeatEvent = () => { gNonexistentOnRepeatEventListenerCallCount++; }; + let repeatTargetWithRegularListeners = document.getElementById("repeatTargetWithRegularListeners"); + repeatTargetWithRegularListeners.addEventListener("repeatEvent", () => { gRepeatEventListenerCallCount++; }); + repeatTargetWithRegularListeners.addEventListener("repeat", () => { gRepeatListenerCallCount++; }); + + test(t => { + repeatTargetWithAttributeHandlers.dispatchEvent(new Event("repeat")); + assert_equals(gOnRepeatHandlerCallCount, 0); + assert_equals(gNonexistentOnRepeatEventHandlerCallCount, 0); + repeatTargetWithIDLListeners.dispatchEvent(new Event("repeat")); + assert_equals(gOnRepeatListenerCallCount, 0); + assert_equals(gNonexistentOnRepeatEventListenerCallCount, 0); + repeatTargetWithRegularListeners.dispatchEvent(new Event("repeat")); + assert_equals(gRepeatEventListenerCallCount, 0); + assert_equals(gRepeatListenerCallCount, 1); + }, "custom events with the name 'repeat' should only call the event listener for the event 'repeat' and no attribute handlers or IDL listeners"); + + test(t => { + gOnRepeatHandlerCallCount = 0; + gNonexistentOnRepeatEventHandlerCallCount = 0; + gOnRepeatListenerCallCount = 0; + gNonexistentOnRepeatEventListenerCallCount = 0; + gRepeatEventListenerCallCount = 0; + gRepeatListenerCallCount = 0; + repeatTargetWithAttributeHandlers.dispatchEvent(new Event("repeatEvent")); + assert_equals(gOnRepeatHandlerCallCount, 1); + assert_equals(gNonexistentOnRepeatEventHandlerCallCount, 0); + repeatTargetWithIDLListeners.dispatchEvent(new Event("repeatEvent")); + assert_equals(gOnRepeatListenerCallCount, 1); + assert_equals(gNonexistentOnRepeatEventListenerCallCount, 0); + repeatTargetWithRegularListeners.dispatchEvent(new Event("repeatEvent")); + assert_equals(gRepeatEventListenerCallCount, 1); + assert_equals(gRepeatListenerCallCount, 0); + }, "custom events with the name 'repeatEvent' should call 'onrepeat' attribute handlers and IDL property listeners, and 'repeatEvent' listeners"); + + // === "begin" / "beginEvent" tests === + // The SVG spec does not define an event called "begin" - the animation event is called "beginEvent". + // The SVG spec does not define an IDL property called "onbeginEvent", only one called "onbegin". + // The SVG spec does not define an attribute called "onbeginEvent", only one called "onbegin". + + gOnBeginHandlerCallCount = 0; + gNonexistentOnBeginEventHandlerCallCount = 0; + gOnBeginListenerCallCount = 0; + gNonexistentOnBeginEventListenerCallCount = 0; + gBeginEventListenerCallCount = 0; + gBeginListenerCallCount = 0; + + let beginTargetWithAttributeHandlers = document.getElementById("beginTargetWithAttributeHandlers"); + let beginTargetWithIDLListeners = document.getElementById("beginTargetWithIDLListeners"); + beginTargetWithIDLListeners.onbegin = () => { gOnBeginListenerCallCount++; }; + beginTargetWithIDLListeners.onbeginEvent = () => { gNonexistentOnBeginEventListenerCallCount++; }; + let beginTargetWithRegularListeners = document.getElementById("beginTargetWithRegularListeners"); + beginTargetWithRegularListeners.addEventListener("beginEvent", () => { gBeginEventListenerCallCount++; }); + beginTargetWithRegularListeners.addEventListener("begin", () => { gBeginListenerCallCount++; }); + + test(t => { + beginTargetWithAttributeHandlers.dispatchEvent(new Event("begin")); + assert_equals(gOnBeginHandlerCallCount, 0); + assert_equals(gNonexistentOnBeginEventHandlerCallCount, 0); + beginTargetWithIDLListeners.dispatchEvent(new Event("begin")); + assert_equals(gOnBeginListenerCallCount, 0); + assert_equals(gNonexistentOnBeginEventListenerCallCount, 0); + beginTargetWithRegularListeners.dispatchEvent(new Event("begin")); + assert_equals(gBeginEventListenerCallCount, 0); + assert_equals(gBeginListenerCallCount, 1); + }, "custom events with the name 'begin' should only call the event listener for the event 'begin' and no attribute handlers or IDL listeners"); + + test(t => { + gOnBeginHandlerCallCount = 0; + gNonexistentOnBeginEventHandlerCallCount = 0; + gOnBeginListenerCallCount = 0; + gNonexistentOnBeginEventListenerCallCount = 0; + gBeginEventListenerCallCount = 0; + gBeginListenerCallCount = 0; + beginTargetWithAttributeHandlers.dispatchEvent(new Event("beginEvent")); + assert_equals(gOnBeginHandlerCallCount, 1); + assert_equals(gNonexistentOnBeginEventHandlerCallCount, 0); + beginTargetWithIDLListeners.dispatchEvent(new Event("beginEvent")); + assert_equals(gOnBeginListenerCallCount, 1); + assert_equals(gNonexistentOnBeginEventListenerCallCount, 0); + beginTargetWithRegularListeners.dispatchEvent(new Event("beginEvent")); + assert_equals(gBeginEventListenerCallCount, 1); + assert_equals(gBeginListenerCallCount, 0); + }, "custom events with the name 'beginEvent' should call 'onbegin' attribute handlers and IDL property listeners, and 'beginEvent' listeners"); + </script>
diff --git a/third_party/blink/web_tests/external/wpt/webusb/usb-supported-by-permissions-policy-expected.txt b/third_party/blink/web_tests/external/wpt/webusb/usb-supported-by-permissions-policy-expected.txt new file mode 100644 index 0000000..878ff89 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/webusb/usb-supported-by-permissions-policy-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] document.permissionsPolicy.features should advertise usb. + Cannot read properties of undefined (reading 'features') +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/webusb/usb-supported-by-permissions-policy.html b/third_party/blink/web_tests/external/wpt/webusb/usb-supported-by-permissions-policy.html index 8e63521..aa93f708 100644 --- a/third_party/blink/web_tests/external/wpt/webusb/usb-supported-by-permissions-policy.html +++ b/third_party/blink/web_tests/external/wpt/webusb/usb-supported-by-permissions-policy.html
@@ -6,6 +6,6 @@ <script src="/resources/testharnessreport.js"></script> <script> test(() => { - assert_in_array('usb', document.featurePolicy.features()); -}, 'document.featurePolicy.features should advertise usb.'); + assert_in_array('usb', document.permissionsPolicy.features()); +}, 'document.permissionsPolicy.features should advertise usb.'); </script>
diff --git a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt index 0797d98..9c7392d 100644 --- a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt +++ b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt
@@ -194,7 +194,10 @@ PASS oldChildWindow.onmove is newChildWindow.onmove PASS oldChildWindow.onoffline is newChildWindow.onoffline PASS oldChildWindow.ononline is newChildWindow.ononline -PASS oldChildWindow.onoverscroll is newChildWindow.onoverscroll +PASS oldChildWindow.onoverscrollcancel is newChildWindow.onoverscrollcancel +PASS oldChildWindow.onoverscrollchanging is newChildWindow.onoverscrollchanging +PASS oldChildWindow.onoverscrollend is newChildWindow.onoverscrollend +PASS oldChildWindow.onoverscrollstart is newChildWindow.onoverscrollstart PASS oldChildWindow.onpagehide is newChildWindow.onpagehide PASS oldChildWindow.onpagereveal is newChildWindow.onpagereveal PASS oldChildWindow.onpageshow is newChildWindow.onpageshow
diff --git a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt index 30c21cbf..7ba48cb 100644 --- a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt +++ b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt
@@ -133,7 +133,10 @@ PASS childWindow.onmove is null PASS childWindow.onoffline is null PASS childWindow.ononline is null -PASS childWindow.onoverscroll is null +PASS childWindow.onoverscrollcancel is null +PASS childWindow.onoverscrollchanging is null +PASS childWindow.onoverscrollend is null +PASS childWindow.onoverscrollstart is null PASS childWindow.onpagehide is null PASS childWindow.onpagereveal is null PASS childWindow.onpageshow is null
diff --git a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt index 0dbd662..4ab52ae 100644 --- a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt +++ b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt
@@ -133,7 +133,10 @@ PASS childWindow.onmove is null PASS childWindow.onoffline is null PASS childWindow.ononline is null -PASS childWindow.onoverscroll is null +PASS childWindow.onoverscrollcancel is null +PASS childWindow.onoverscrollchanging is null +PASS childWindow.onoverscrollend is null +PASS childWindow.onoverscrollstart is null PASS childWindow.onpagehide is null PASS childWindow.onpagereveal is null PASS childWindow.onpageshow is null
diff --git a/third_party/blink/web_tests/fast/dom/inert/inert-does-not-match-disabled-selector.html b/third_party/blink/web_tests/fast/dom/inert/inert-does-not-match-disabled-selector.html deleted file mode 100644 index 212df61..0000000 --- a/third_party/blink/web_tests/fast/dom/inert/inert-does-not-match-disabled-selector.html +++ /dev/null
@@ -1,27 +0,0 @@ -<!DOCTYPE html> -<html> -<head> -<script src="../../../resources/testharness.js"></script> -<script src="../../../resources/testharnessreport.js"></script> -<style> -button { - color: green; -} - -button:disabled { - color: red; -} - -</style> -</head> -<body style="color: green"> -<button inert>The test passes if this is in green.</button> -<script> -test(function() { - button = document.querySelector('button'); - color = document.defaultView.getComputedStyle(button).getPropertyValue('color'); - assert_equals(color, 'rgb(0, 128, 0)'); -}, 'Tests that inert elements do not match the :disabled selector.'); -</script> -</body> -</html>
diff --git a/third_party/blink/web_tests/fast/dom/inert/inert-in-shadow-dom.html b/third_party/blink/web_tests/fast/dom/inert/inert-in-shadow-dom.html deleted file mode 100644 index 0d27aa8..0000000 --- a/third_party/blink/web_tests/fast/dom/inert/inert-in-shadow-dom.html +++ /dev/null
@@ -1,44 +0,0 @@ -<!DOCTYPE html> -<html> -<head> -<script src="../../../resources/testharness.js"></script> -<script src="../../../resources/testharnessreport.js"></script> -</head> -<body> - - <div id="shadow-host"> - <button slot="slot-1" id="button-1">Button 1 (inert)</button> - <button slot="slot-2" id="button-2">Button 2 (not inert)</button> - </div> - <script> - setup({single_test: true}); - - const shadowHost = document.getElementById('shadow-host'); - const shadowRoot = shadowHost.attachShadow({ mode: 'open' }); - const inertDiv = document.createElement('div'); - inertDiv.inert = true; - shadowRoot.appendChild(inertDiv); - const slot1 = document.createElement('slot'); - slot1.name = 'slot-1'; - inertDiv.appendChild(slot1); - const slot2 = document.createElement('slot'); - slot2.name = 'slot-2'; - shadowRoot.appendChild(slot2); - - function testCanFocus(selector, canFocus) { - const element = document.querySelector(selector); - let focusedElement = null; - element.addEventListener('focus', function() { focusedElement = element; }, false); - element.focus(); - if (canFocus) - assert_true(focusedElement === element); - else - assert_false(focusedElement === element); - } - - testCanFocus('#button-1', false); - testCanFocus('#button-2', true); - done(); - </script> -</body> -</html>
diff --git a/third_party/blink/web_tests/fast/dom/inert/inert-node-is-uneditable.html b/third_party/blink/web_tests/fast/dom/inert/inert-node-is-uneditable.html deleted file mode 100644 index a494575..0000000 --- a/third_party/blink/web_tests/fast/dom/inert/inert-node-is-uneditable.html +++ /dev/null
@@ -1,60 +0,0 @@ -<!DOCTYPE html> -<html> -<head> -<script src="../../../resources/testharness.js"></script> -<script src="../../../resources/testharnessreport.js"></script> -</head> -<body> -<span inert id="not-editable" contenteditable>I'm not editable.</span> -<span id="editable" contenteditable>I'm editable.</span> -<script> -function clickOn(element) -{ - return new Promise(function(resolve, reject) { - if (!window.eventSender) - reject(); - - var absoluteTop = 0; - var absoluteLeft = 0; - for (var parentNode = element; parentNode; parentNode = parentNode.offsetParent) { - absoluteLeft += parentNode.offsetLeft; - absoluteTop += parentNode.offsetTop; - } - - var x = absoluteLeft + element.offsetWidth / 2; - var y = absoluteTop + element.offsetHeight / 2; - var pointerActions = [{ - source: "mouse", - actions: [ - { name: "pointerMove", x: x, y: y }, - { name: "pointerDown", x: x, y: x }, - { name: "pointerUp" }, - { name: "pointerMove", x: 0, y: 0} - ] - }]; - chrome.gpuBenchmarking.pointerActionSequence(pointerActions, resolve); - }); -} - -var notEditable = document.querySelector('#not-editable'); -var editable = document.querySelector('#editable'); - -promise_test(async () => { - await clickOn(notEditable); - var oldValue = notEditable.textContent; - assert_equals(oldValue, "I'm not editable."); - eventSender.keyDown('a'); - assert_equals(notEditable.textContent, oldValue); -}, "Can't edit inert contenteditable"); - -promise_test(async () => { - await clickOn(editable); - var oldValue = editable.textContent; - assert_equals(oldValue, "I'm editable."); - eventSender.keyDown('a'); - assert_not_equals(editable.textContent, oldValue); -}, "Can edit non-inert contenteditable"); - -</script> -</body> -</html>
diff --git a/third_party/blink/web_tests/fast/dom/inert/inert-node-is-unfocusable.html b/third_party/blink/web_tests/fast/dom/inert/inert-node-is-unfocusable.html deleted file mode 100644 index bcec732e..0000000 --- a/third_party/blink/web_tests/fast/dom/inert/inert-node-is-unfocusable.html +++ /dev/null
@@ -1,76 +0,0 @@ -<!DOCTYPE html> -<html> -<head> -<script src="../../../resources/testharness.js"></script> -<script src="../../../resources/testharnessreport.js"></script> -</head> -<body id="body" tabindex="1"> - <button id="focusable">Outside of inert container</button> - <button inert id="inert">Inert button</button> - <div inert id="container"> - <input id="text" type="text"> - <input id="datetime" type="datetime"> - <input id="color" type="color"> - <select id="select"> - <optgroup id="optgroup"> - <option id="option">Option</option> - </optgroup> - </select> - <div id="contenteditable-div" contenteditable>I'm editable</div> - <span id="tabindex-span" tabindex="0">I'm tabindexed.</div> - <embed id="embed" type="application/x-webkit-test-webplugin" width=100 height=100></embed> - <a id="anchor" href="">Link</a> - </div> -<script> -function testFocus(element, expectFocus) { - focusedElement = null; - element.addEventListener('focus', function() { focusedElement = element; }, false); - element.focus(); - theElement = element; - assert_equals(focusedElement === theElement, expectFocus); -} - -function testTree(element, expectFocus, excludeCurrent) { - if (element.nodeType == Node.ELEMENT_NODE && !excludeCurrent) - testFocus(element, expectFocus); - if (element.tagName === "SELECT") - return; - var childNodes = element.childNodes; - for (var i = 0; i < childNodes.length; i++) - testTree(childNodes[i], expectFocus); -} - - -test(function() { - testFocus(document.getElementById('focusable'), true); -}, "Button outside of inert container is focusable."); - -test(function() { - testFocus(document.getElementById('inert'), false); -}, "Button with inert atribute is unfocusable."); - -test(function() { - testTree(document.getElementById('container'), false); -}, "All focusable elements inside inert subtree are unfocusable"); - -test(function() { - assert_false(document.getElementById("focusable").inert, "Inert not set explicitly is false") - assert_true(document.getElementById("inert").inert, "Inert set explicitly is true"); - assert_true(document.getElementById("container").inert, "Inert set on container is true"); -}, "Can get inert via property"); - -test(function() { - assert_false(document.getElementById("text").inert, "Elements inside of inert subtrees return false when getting inert"); -}, "Elements inside of inert subtrees return false when getting 'inert'"); - -test(function() { - document.getElementById('focusable').inert = true; - testFocus(document.getElementById('focusable'), false); - document.getElementById('inert').inert = false; - testFocus(document.getElementById('inert'), true); - document.getElementById('container').inert = false; - testTree(document.getElementById('container'), true, true); -}, "Setting inert via property correctly modifies inert state"); -</script> -</body> -</html>
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/html/browsers/browsing-the-web/scroll-to-fragid/scroll-restore-on-reload-non-ascii-fragment-expected.txt b/third_party/blink/web_tests/platform/mac/external/wpt/html/browsers/browsing-the-web/scroll-to-fragid/scroll-restore-on-reload-non-ascii-fragment-expected.txt new file mode 100644 index 0000000..40c701f --- /dev/null +++ b/third_party/blink/web_tests/platform/mac/external/wpt/html/browsers/browsing-the-web/scroll-to-fragid/scroll-restore-on-reload-non-ascii-fragment-expected.txt
@@ -0,0 +1,7 @@ +This is a testharness.js-based test. +[FAIL] Reload preserves scroll position for ASCII fragment + assert_equals: scroll position should be preserved after reload, not scrolled to fragment expected 0 but got 608 +[FAIL] Reload preserves scroll position for non-ASCII fragment + assert_equals: scroll position should be preserved after reload, not scrolled to fragment expected 0 but got 1226 +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/html/browsers/browsing-the-web/scroll-to-fragid/scroll-restore-on-reload-non-ascii-fragment-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/html/browsers/browsing-the-web/scroll-to-fragid/scroll-restore-on-reload-non-ascii-fragment-expected.txt new file mode 100644 index 0000000..cf8ed30b --- /dev/null +++ b/third_party/blink/web_tests/platform/win/external/wpt/html/browsers/browsing-the-web/scroll-to-fragid/scroll-restore-on-reload-non-ascii-fragment-expected.txt
@@ -0,0 +1,7 @@ +This is a testharness.js-based test. +[FAIL] Reload preserves scroll position for ASCII fragment + assert_equals: scroll position should be preserved after reload, not scrolled to fragment expected 0 but got 608 +[FAIL] Reload preserves scroll position for non-ASCII fragment + assert_equals: scroll position should be preserved after reload, not scrolled to fragment expected 0 but got 1228 +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/virtual/generic-sensor-extra-classes/external/wpt/magnetometer/Magnetometer-disabled-by-feature-policy.https-expected.txt b/third_party/blink/web_tests/virtual/generic-sensor-extra-classes/external/wpt/magnetometer/Magnetometer-disabled-by-feature-policy.https-expected.txt deleted file mode 100644 index a7ebeeb6..0000000 --- a/third_party/blink/web_tests/virtual/generic-sensor-extra-classes/external/wpt/magnetometer/Magnetometer-disabled-by-feature-policy.https-expected.txt +++ /dev/null
@@ -1,13 +0,0 @@ -This is a testharness.js-based test. -[FAIL] Magnetometer: Permissions-Policy header magnetometer=() disallows same-origin iframes. - test_feature_availability is not defined -[FAIL] Magnetometer: Permissions-Policy header magnetometer=() disallows cross-origin iframes. - test_feature_availability is not defined -[FAIL] UncalibratedMagnetometer: Permissions-Policy header magnetometer=() disallows the top-level document. - assert_implements: UncalibratedMagnetometer is not supported. undefined -[FAIL] UncalibratedMagnetometer: Permissions-Policy header magnetometer=() disallows same-origin iframes. - assert_implements: UncalibratedMagnetometer is not supported. undefined -[FAIL] UncalibratedMagnetometer: Permissions-Policy header magnetometer=() disallows cross-origin iframes. - assert_implements: UncalibratedMagnetometer is not supported. undefined -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/virtual/generic-sensor-extra-classes/external/wpt/magnetometer/Magnetometer-enabled-by-feature-policy-attribute-redirect-on-load.https-expected.txt b/third_party/blink/web_tests/virtual/generic-sensor-extra-classes/external/wpt/magnetometer/Magnetometer-enabled-by-feature-policy-attribute-redirect-on-load.https-expected.txt deleted file mode 100644 index 82e9c6260..0000000 --- a/third_party/blink/web_tests/virtual/generic-sensor-extra-classes/external/wpt/magnetometer/Magnetometer-enabled-by-feature-policy-attribute-redirect-on-load.https-expected.txt +++ /dev/null
@@ -1,11 +0,0 @@ -This is a testharness.js-based test. -[FAIL] Magnetometer: Permissions-Policy allow='magnetometer' attribute allows same-origin relocation - test_feature_availability is not defined -[FAIL] Magnetometer: Permissions-Policy allow='magnetometer' attribute disallows cross-origin relocation - test_feature_availability is not defined -[FAIL] UncalibratedMagnetometer: Permissions-Policy allow='magnetometer' attribute allows same-origin relocation - assert_implements: UncalibratedMagnetometer is not supported. undefined -[FAIL] UncalibratedMagnetometer: Permissions-Policy allow='magnetometer' attribute disallows cross-origin relocation - assert_implements: UncalibratedMagnetometer is not supported. undefined -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/virtual/generic-sensor-extra-classes/external/wpt/magnetometer/Magnetometer-enabled-by-feature-policy-attribute.https-expected.txt b/third_party/blink/web_tests/virtual/generic-sensor-extra-classes/external/wpt/magnetometer/Magnetometer-enabled-by-feature-policy-attribute.https-expected.txt deleted file mode 100644 index 83f5000..0000000 --- a/third_party/blink/web_tests/virtual/generic-sensor-extra-classes/external/wpt/magnetometer/Magnetometer-enabled-by-feature-policy-attribute.https-expected.txt +++ /dev/null
@@ -1,11 +0,0 @@ -This is a testharness.js-based test. -[FAIL] Magnetometer: Permissions-Policy allow='magnetometer' attribute allows same-origin iframe - test_feature_availability is not defined -[FAIL] Magnetometer: Permissions-Policy allow='magnetometer' attribute allows cross-origin iframe - test_feature_availability is not defined -[FAIL] UncalibratedMagnetometer: Permissions-Policy allow='magnetometer' attribute allows same-origin iframe - assert_implements: UncalibratedMagnetometer is not supported. undefined -[FAIL] UncalibratedMagnetometer: Permissions-Policy allow='magnetometer' attribute allows cross-origin iframe - assert_implements: UncalibratedMagnetometer is not supported. undefined -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/virtual/generic-sensor-extra-classes/external/wpt/magnetometer/Magnetometer-enabled-by-feature-policy.https-expected.txt b/third_party/blink/web_tests/virtual/generic-sensor-extra-classes/external/wpt/magnetometer/Magnetometer-enabled-by-feature-policy.https-expected.txt deleted file mode 100644 index f6be42b..0000000 --- a/third_party/blink/web_tests/virtual/generic-sensor-extra-classes/external/wpt/magnetometer/Magnetometer-enabled-by-feature-policy.https-expected.txt +++ /dev/null
@@ -1,13 +0,0 @@ -This is a testharness.js-based test. -[FAIL] Magnetometer: Permissions-Policy header magnetometer=* allows same-origin iframes. - test_feature_availability is not defined -[FAIL] Magnetometer: Permissions-Policy header magnetometer=* allows cross-origin iframes. - test_feature_availability is not defined -[FAIL] UncalibratedMagnetometer: Permissions-Policy header magnetometer=* allows the top-level document. - assert_implements: UncalibratedMagnetometer is not supported. undefined -[FAIL] UncalibratedMagnetometer: Permissions-Policy header magnetometer=* allows same-origin iframes. - assert_implements: UncalibratedMagnetometer is not supported. undefined -[FAIL] UncalibratedMagnetometer: Permissions-Policy header magnetometer=* allows cross-origin iframes. - assert_implements: UncalibratedMagnetometer is not supported. undefined -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/virtual/generic-sensor-extra-classes/external/wpt/magnetometer/Magnetometer-enabled-on-self-origin-by-feature-policy.https-expected.txt b/third_party/blink/web_tests/virtual/generic-sensor-extra-classes/external/wpt/magnetometer/Magnetometer-enabled-on-self-origin-by-feature-policy.https-expected.txt deleted file mode 100644 index ad14fd1..0000000 --- a/third_party/blink/web_tests/virtual/generic-sensor-extra-classes/external/wpt/magnetometer/Magnetometer-enabled-on-self-origin-by-feature-policy.https-expected.txt +++ /dev/null
@@ -1,13 +0,0 @@ -This is a testharness.js-based test. -[FAIL] Magnetometer: Permissions-Policy header magnetometer=(self) allows same-origin iframes. - test_feature_availability is not defined -[FAIL] Magnetometer: Permissions-Policy header magnetometer=(self) disallows cross-origin iframes. - test_feature_availability is not defined -[FAIL] UncalibratedMagnetometer: Permissions-Policy header magnetometer=(self) allows the top-level document. - assert_implements: UncalibratedMagnetometer is not supported. undefined -[FAIL] UncalibratedMagnetometer: Permissions-Policy header magnetometer=(self) allows same-origin iframes. - assert_implements: UncalibratedMagnetometer is not supported. undefined -[FAIL] UncalibratedMagnetometer: Permissions-Policy header magnetometer=(self) disallows cross-origin iframes. - assert_implements: UncalibratedMagnetometer is not supported. undefined -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/virtual/generic-sensor-extra-classes/external/wpt/magnetometer/Magnetometer.https-expected.txt b/third_party/blink/web_tests/virtual/generic-sensor-extra-classes/external/wpt/magnetometer/Magnetometer.https-expected.txt new file mode 100644 index 0000000..0aca0d1 --- /dev/null +++ b/third_party/blink/web_tests/virtual/generic-sensor-extra-classes/external/wpt/magnetometer/Magnetometer.https-expected.txt
@@ -0,0 +1,39 @@ +This is a testharness.js-based test. +[FAIL] UncalibratedMagnetometer: Test that onerror is sent when permissions are not granted. + assert_implements: UncalibratedMagnetometer is not supported. undefined +[FAIL] UncalibratedMagnetometer: Test that onerror is send when start() call has failed. + assert_implements: UncalibratedMagnetometer is not supported. undefined +[FAIL] UncalibratedMagnetometer: Test that frequency is capped to allowed maximum. + assert_implements: UncalibratedMagnetometer is not supported. undefined +[FAIL] UncalibratedMagnetometer: Test that frequency is capped to the maximum supported frequency. + assert_implements: UncalibratedMagnetometer is not supported. undefined +[FAIL] UncalibratedMagnetometer: Test that frequency is limited to the minimum supported frequency. + assert_implements: UncalibratedMagnetometer is not supported. undefined +[FAIL] UncalibratedMagnetometer: Test that sensor cannot be constructed within iframe disallowed to use permissions policy. + assert_implements: UncalibratedMagnetometer is not supported. undefined +[FAIL] UncalibratedMagnetometer: Test that sensor can be constructed within an iframe allowed to use permissions policy. + assert_implements: UncalibratedMagnetometer is not supported. undefined +[FAIL] UncalibratedMagnetometer: Test that 'onreading' is called and sensor reading is valid. + assert_implements: UncalibratedMagnetometer is not supported. undefined +[FAIL] UncalibratedMagnetometer: sensor reading is correct. + assert_implements: UncalibratedMagnetometer is not supported. undefined +[FAIL] UncalibratedMagnetometer: Test that readings are all mapped to expectedReadings correctly. + assert_implements: UncalibratedMagnetometer is not supported. undefined +[FAIL] UncalibratedMagnetometer: sensor timestamp is updated when time passes. + assert_implements: UncalibratedMagnetometer is not supported. undefined +[FAIL] UncalibratedMagnetometer: Test that sensor can be successfully created and its states are correct. + assert_implements: UncalibratedMagnetometer is not supported. undefined +[FAIL] UncalibratedMagnetometer: no exception is thrown when calling start() on already started sensor. + assert_implements: UncalibratedMagnetometer is not supported. undefined +[FAIL] UncalibratedMagnetometer: no exception is thrown when calling stop() on already stopped sensor. + assert_implements: UncalibratedMagnetometer is not supported. undefined +[FAIL] UncalibratedMagnetometer: Test that fresh reading is fetched on start(). + assert_implements: UncalibratedMagnetometer is not supported. undefined +[FAIL] UncalibratedMagnetometer: Readings are not delivered when the page has no visibility + assert_implements: UncalibratedMagnetometer is not supported. undefined +[FAIL] UncalibratedMagnetometer: frequency hint works. + assert_implements: UncalibratedMagnetometer is not supported. undefined +[FAIL] UncalibratedMagnetometer: Readings delivered by shared platform sensor are immediately accessible to all sensors. + assert_implements: UncalibratedMagnetometer is not supported. undefined +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/virtual/selective-permissions-intervention/http/tests/inspector-protocol/issues/selective-permissions-intervention-issue-expected.txt b/third_party/blink/web_tests/virtual/selective-permissions-intervention/http/tests/inspector-protocol/issues/selective-permissions-intervention-issue-expected.txt index 95377c0..924b23a 100644 --- a/third_party/blink/web_tests/virtual/selective-permissions-intervention/http/tests/inspector-protocol/issues/selective-permissions-intervention-issue-expected.txt +++ b/third_party/blink/web_tests/virtual/selective-permissions-intervention/http/tests/inspector-protocol/issues/selective-permissions-intervention-issue-expected.txt
@@ -6,7 +6,7 @@ details : { selectivePermissionsInterventionIssueDetails : { adAncestry : { - adAncestryChain : [ + ancestryChain : [ [0] : { debuggerId : <string> name : .../issues/resources/trigger-geo.js
diff --git a/third_party/blink/web_tests/virtual/threaded/external/wpt/permissions-policy/experimental-features/unload-allowed-by-default.tentative.window-expected.txt b/third_party/blink/web_tests/virtual/threaded/external/wpt/permissions-policy/experimental-features/unload-allowed-by-default.tentative.window-expected.txt deleted file mode 100644 index d2490db..0000000 --- a/third_party/blink/web_tests/virtual/threaded/external/wpt/permissions-policy/experimental-features/unload-allowed-by-default.tentative.window-expected.txt +++ /dev/null
@@ -1,3 +0,0 @@ -This is a testharness.js-based test. -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/virtual/unload-allowed/external/wpt/permissions-policy/experimental-features/unload-allowed-by-default.tentative.window-expected.txt b/third_party/blink/web_tests/virtual/unload-allowed/external/wpt/permissions-policy/experimental-features/unload-allowed-by-default.tentative.window-expected.txt deleted file mode 100644 index d2490db..0000000 --- a/third_party/blink/web_tests/virtual/unload-allowed/external/wpt/permissions-policy/experimental-features/unload-allowed-by-default.tentative.window-expected.txt +++ /dev/null
@@ -1,3 +0,0 @@ -This is a testharness.js-based test. -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/virtual/webcrypto-pqc/external/wpt/WebCryptoAPI/encap_decap/encap_decap_bits.tentative.https.any-expected.txt b/third_party/blink/web_tests/virtual/webcrypto-pqc/external/wpt/WebCryptoAPI/encap_decap/encap_decap_bits.tentative.https.any-expected.txt index 1e3b0923..c15c057c 100644 --- a/third_party/blink/web_tests/virtual/webcrypto-pqc/external/wpt/WebCryptoAPI/encap_decap/encap_decap_bits.tentative.https.any-expected.txt +++ b/third_party/blink/web_tests/virtual/webcrypto-pqc/external/wpt/WebCryptoAPI/encap_decap/encap_decap_bits.tentative.https.any-expected.txt
@@ -1,24 +1,18 @@ This is a testharness.js-based test. [FAIL] ML-KEM-512 encapsulateBits basic functionality promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 decapsulateBits basic functionality - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" [FAIL] ML-KEM-512 encapsulateBits/decapsulateBits round-trip compatibility promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" [FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" [FAIL] ML-KEM-768 encapsulateBits basic functionality promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" -[FAIL] ML-KEM-768 decapsulateBits basic functionality - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" [FAIL] ML-KEM-768 encapsulateBits/decapsulateBits round-trip compatibility promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" [FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: importKey" [FAIL] ML-KEM-1024 encapsulateBits basic functionality promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" -[FAIL] ML-KEM-1024 decapsulateBits basic functionality - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" [FAIL] ML-KEM-1024 encapsulateBits/decapsulateBits round-trip compatibility promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" [FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation
diff --git a/third_party/blink/web_tests/virtual/webcrypto-pqc/external/wpt/WebCryptoAPI/encap_decap/encap_decap_bits.tentative.https.any.worker-expected.txt b/third_party/blink/web_tests/virtual/webcrypto-pqc/external/wpt/WebCryptoAPI/encap_decap/encap_decap_bits.tentative.https.any.worker-expected.txt index 1e3b0923..c15c057c 100644 --- a/third_party/blink/web_tests/virtual/webcrypto-pqc/external/wpt/WebCryptoAPI/encap_decap/encap_decap_bits.tentative.https.any.worker-expected.txt +++ b/third_party/blink/web_tests/virtual/webcrypto-pqc/external/wpt/WebCryptoAPI/encap_decap/encap_decap_bits.tentative.https.any.worker-expected.txt
@@ -1,24 +1,18 @@ This is a testharness.js-based test. [FAIL] ML-KEM-512 encapsulateBits basic functionality promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 decapsulateBits basic functionality - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" [FAIL] ML-KEM-512 encapsulateBits/decapsulateBits round-trip compatibility promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" [FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" [FAIL] ML-KEM-768 encapsulateBits basic functionality promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" -[FAIL] ML-KEM-768 decapsulateBits basic functionality - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" [FAIL] ML-KEM-768 encapsulateBits/decapsulateBits round-trip compatibility promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" [FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: importKey" [FAIL] ML-KEM-1024 encapsulateBits basic functionality promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" -[FAIL] ML-KEM-1024 decapsulateBits basic functionality - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" [FAIL] ML-KEM-1024 encapsulateBits/decapsulateBits round-trip compatibility promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" [FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation
diff --git a/third_party/blink/web_tests/virtual/webcrypto-pqc/external/wpt/WebCryptoAPI/encap_decap/encap_decap_keys.tentative.https.any-expected.txt b/third_party/blink/web_tests/virtual/webcrypto-pqc/external/wpt/WebCryptoAPI/encap_decap/encap_decap_keys.tentative.https.any-expected.txt index 609f0e9d..181c9e1 100644 --- a/third_party/blink/web_tests/virtual/webcrypto-pqc/external/wpt/WebCryptoAPI/encap_decap/encap_decap_keys.tentative.https.any-expected.txt +++ b/third_party/blink/web_tests/virtual/webcrypto-pqc/external/wpt/WebCryptoAPI/encap_decap/encap_decap_keys.tentative.https.any-expected.txt
@@ -1,124 +1,244 @@ This is a testharness.js-based test. -Found 60 FAIL, 0 TIMEOUT, 0 NOTRUN. -[FAIL] ML-KEM-512 encapsulateKey with AES-GCM-256 +Found 120 FAIL, 0 TIMEOUT, 0 NOTRUN. +[FAIL] ML-KEM-512 encapsulateKey with AES-GCM-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 decapsulateKey with AES-GCM-256 +[FAIL] ML-KEM-512 decapsulateKey with AES-GCM-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-GCM-256 +[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-GCM-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 encapsulateKey with AES-CBC-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 decapsulateKey with AES-CBC-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-CBC-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 encapsulateKey with AES-CTR-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 decapsulateKey with AES-CTR-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-CTR-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 encapsulateKey with AES-KW-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 decapsulateKey with AES-KW-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-KW-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 encapsulateKey with HMAC-SHA-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 decapsulateKey with HMAC-SHA-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with HMAC-SHA-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-GCM-256 +[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-GCM-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-CBC-256 +[FAIL] ML-KEM-512 encapsulateKey with AES-GCM-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 decapsulateKey with AES-GCM-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-GCM-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-GCM-256 (extractable=false) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-CTR-256 +[FAIL] ML-KEM-512 encapsulateKey with AES-CBC-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 decapsulateKey with AES-CBC-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-CBC-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-CBC-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-KW-256 +[FAIL] ML-KEM-512 encapsulateKey with AES-CBC-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 decapsulateKey with AES-CBC-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-CBC-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-CBC-256 (extractable=false) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with HMAC-SHA-256 +[FAIL] ML-KEM-512 encapsulateKey with AES-CTR-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 decapsulateKey with AES-CTR-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-CTR-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-CTR-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-768 encapsulateKey with AES-GCM-256 +[FAIL] ML-KEM-512 encapsulateKey with AES-CTR-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 decapsulateKey with AES-CTR-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-CTR-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-CTR-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 encapsulateKey with AES-KW-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 decapsulateKey with AES-KW-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-KW-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-KW-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 encapsulateKey with AES-KW-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 decapsulateKey with AES-KW-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-KW-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-KW-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 encapsulateKey with HMAC-SHA-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 decapsulateKey with HMAC-SHA-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with HMAC-SHA-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with HMAC-SHA-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 encapsulateKey with HMAC-SHA-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 decapsulateKey with HMAC-SHA-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with HMAC-SHA-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with HMAC-SHA-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 encapsulateKey with AES-GCM-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" -[FAIL] ML-KEM-768 decapsulateKey with AES-GCM-256 +[FAIL] ML-KEM-768 decapsulateKey with AES-GCM-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" -[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-GCM-256 +[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-GCM-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" -[FAIL] ML-KEM-768 encapsulateKey with AES-CBC-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" -[FAIL] ML-KEM-768 decapsulateKey with AES-CBC-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" -[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-CBC-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" -[FAIL] ML-KEM-768 encapsulateKey with AES-CTR-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" -[FAIL] ML-KEM-768 decapsulateKey with AES-CTR-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" -[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-CTR-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" -[FAIL] ML-KEM-768 encapsulateKey with AES-KW-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" -[FAIL] ML-KEM-768 decapsulateKey with AES-KW-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" -[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-KW-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" -[FAIL] ML-KEM-768 encapsulateKey with HMAC-SHA-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" -[FAIL] ML-KEM-768 decapsulateKey with HMAC-SHA-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" -[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with HMAC-SHA-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" -[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-GCM-256 +[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-GCM-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: importKey" -[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-CBC-256 +[FAIL] ML-KEM-768 encapsulateKey with AES-GCM-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 decapsulateKey with AES-GCM-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-GCM-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-GCM-256 (extractable=false) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: importKey" -[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-CTR-256 +[FAIL] ML-KEM-768 encapsulateKey with AES-CBC-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 decapsulateKey with AES-CBC-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-CBC-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-CBC-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: importKey" -[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-KW-256 +[FAIL] ML-KEM-768 encapsulateKey with AES-CBC-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 decapsulateKey with AES-CBC-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-CBC-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-CBC-256 (extractable=false) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: importKey" -[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with HMAC-SHA-256 +[FAIL] ML-KEM-768 encapsulateKey with AES-CTR-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 decapsulateKey with AES-CTR-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-CTR-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-CTR-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: importKey" -[FAIL] ML-KEM-1024 encapsulateKey with AES-GCM-256 +[FAIL] ML-KEM-768 encapsulateKey with AES-CTR-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 decapsulateKey with AES-CTR-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-CTR-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-CTR-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: importKey" +[FAIL] ML-KEM-768 encapsulateKey with AES-KW-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 decapsulateKey with AES-KW-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-KW-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-KW-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: importKey" +[FAIL] ML-KEM-768 encapsulateKey with AES-KW-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 decapsulateKey with AES-KW-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-KW-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-KW-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: importKey" +[FAIL] ML-KEM-768 encapsulateKey with HMAC-SHA-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 decapsulateKey with HMAC-SHA-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with HMAC-SHA-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with HMAC-SHA-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: importKey" +[FAIL] ML-KEM-768 encapsulateKey with HMAC-SHA-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 decapsulateKey with HMAC-SHA-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with HMAC-SHA-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with HMAC-SHA-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: importKey" +[FAIL] ML-KEM-1024 encapsulateKey with AES-GCM-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" -[FAIL] ML-KEM-1024 decapsulateKey with AES-GCM-256 +[FAIL] ML-KEM-1024 decapsulateKey with AES-GCM-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" -[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-GCM-256 +[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-GCM-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" -[FAIL] ML-KEM-1024 encapsulateKey with AES-CBC-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" -[FAIL] ML-KEM-1024 decapsulateKey with AES-CBC-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" -[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-CBC-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" -[FAIL] ML-KEM-1024 encapsulateKey with AES-CTR-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" -[FAIL] ML-KEM-1024 decapsulateKey with AES-CTR-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" -[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-CTR-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" -[FAIL] ML-KEM-1024 encapsulateKey with AES-KW-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" -[FAIL] ML-KEM-1024 decapsulateKey with AES-KW-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" -[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-KW-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" -[FAIL] ML-KEM-1024 encapsulateKey with HMAC-SHA-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" -[FAIL] ML-KEM-1024 decapsulateKey with HMAC-SHA-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" -[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with HMAC-SHA-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" -[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-GCM-256 +[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-GCM-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: importKey" -[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-CBC-256 +[FAIL] ML-KEM-1024 encapsulateKey with AES-GCM-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 decapsulateKey with AES-GCM-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-GCM-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-GCM-256 (extractable=false) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: importKey" -[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-CTR-256 +[FAIL] ML-KEM-1024 encapsulateKey with AES-CBC-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 decapsulateKey with AES-CBC-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-CBC-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-CBC-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: importKey" -[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-KW-256 +[FAIL] ML-KEM-1024 encapsulateKey with AES-CBC-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 decapsulateKey with AES-CBC-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-CBC-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-CBC-256 (extractable=false) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: importKey" -[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with HMAC-SHA-256 +[FAIL] ML-KEM-1024 encapsulateKey with AES-CTR-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 decapsulateKey with AES-CTR-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-CTR-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-CTR-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: importKey" +[FAIL] ML-KEM-1024 encapsulateKey with AES-CTR-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 decapsulateKey with AES-CTR-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-CTR-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-CTR-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: importKey" +[FAIL] ML-KEM-1024 encapsulateKey with AES-KW-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 decapsulateKey with AES-KW-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-KW-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-KW-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: importKey" +[FAIL] ML-KEM-1024 encapsulateKey with AES-KW-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 decapsulateKey with AES-KW-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-KW-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-KW-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: importKey" +[FAIL] ML-KEM-1024 encapsulateKey with HMAC-SHA-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 decapsulateKey with HMAC-SHA-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with HMAC-SHA-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with HMAC-SHA-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: importKey" +[FAIL] ML-KEM-1024 encapsulateKey with HMAC-SHA-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 decapsulateKey with HMAC-SHA-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with HMAC-SHA-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with HMAC-SHA-256 (extractable=false) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: importKey" Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/virtual/webcrypto-pqc/external/wpt/WebCryptoAPI/encap_decap/encap_decap_keys.tentative.https.any.worker-expected.txt b/third_party/blink/web_tests/virtual/webcrypto-pqc/external/wpt/WebCryptoAPI/encap_decap/encap_decap_keys.tentative.https.any.worker-expected.txt index 609f0e9d..181c9e1 100644 --- a/third_party/blink/web_tests/virtual/webcrypto-pqc/external/wpt/WebCryptoAPI/encap_decap/encap_decap_keys.tentative.https.any.worker-expected.txt +++ b/third_party/blink/web_tests/virtual/webcrypto-pqc/external/wpt/WebCryptoAPI/encap_decap/encap_decap_keys.tentative.https.any.worker-expected.txt
@@ -1,124 +1,244 @@ This is a testharness.js-based test. -Found 60 FAIL, 0 TIMEOUT, 0 NOTRUN. -[FAIL] ML-KEM-512 encapsulateKey with AES-GCM-256 +Found 120 FAIL, 0 TIMEOUT, 0 NOTRUN. +[FAIL] ML-KEM-512 encapsulateKey with AES-GCM-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 decapsulateKey with AES-GCM-256 +[FAIL] ML-KEM-512 decapsulateKey with AES-GCM-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-GCM-256 +[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-GCM-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 encapsulateKey with AES-CBC-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 decapsulateKey with AES-CBC-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-CBC-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 encapsulateKey with AES-CTR-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 decapsulateKey with AES-CTR-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-CTR-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 encapsulateKey with AES-KW-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 decapsulateKey with AES-KW-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-KW-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 encapsulateKey with HMAC-SHA-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 decapsulateKey with HMAC-SHA-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with HMAC-SHA-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-GCM-256 +[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-GCM-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-CBC-256 +[FAIL] ML-KEM-512 encapsulateKey with AES-GCM-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 decapsulateKey with AES-GCM-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-GCM-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-GCM-256 (extractable=false) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-CTR-256 +[FAIL] ML-KEM-512 encapsulateKey with AES-CBC-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 decapsulateKey with AES-CBC-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-CBC-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-CBC-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-KW-256 +[FAIL] ML-KEM-512 encapsulateKey with AES-CBC-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 decapsulateKey with AES-CBC-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-CBC-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-CBC-256 (extractable=false) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with HMAC-SHA-256 +[FAIL] ML-KEM-512 encapsulateKey with AES-CTR-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 decapsulateKey with AES-CTR-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-CTR-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-CTR-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" -[FAIL] ML-KEM-768 encapsulateKey with AES-GCM-256 +[FAIL] ML-KEM-512 encapsulateKey with AES-CTR-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 decapsulateKey with AES-CTR-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-CTR-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-CTR-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 encapsulateKey with AES-KW-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 decapsulateKey with AES-KW-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-KW-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-KW-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 encapsulateKey with AES-KW-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 decapsulateKey with AES-KW-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with AES-KW-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with AES-KW-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 encapsulateKey with HMAC-SHA-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 decapsulateKey with HMAC-SHA-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with HMAC-SHA-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with HMAC-SHA-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 encapsulateKey with HMAC-SHA-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 decapsulateKey with HMAC-SHA-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 encapsulateKey/decapsulateKey round-trip with HMAC-SHA-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-512 vector-based sampleCiphertext decapsulation with HMAC-SHA-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': Algorithm: Unrecognized name" +[FAIL] ML-KEM-768 encapsulateKey with AES-GCM-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" -[FAIL] ML-KEM-768 decapsulateKey with AES-GCM-256 +[FAIL] ML-KEM-768 decapsulateKey with AES-GCM-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" -[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-GCM-256 +[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-GCM-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" -[FAIL] ML-KEM-768 encapsulateKey with AES-CBC-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" -[FAIL] ML-KEM-768 decapsulateKey with AES-CBC-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" -[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-CBC-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" -[FAIL] ML-KEM-768 encapsulateKey with AES-CTR-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" -[FAIL] ML-KEM-768 decapsulateKey with AES-CTR-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" -[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-CTR-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" -[FAIL] ML-KEM-768 encapsulateKey with AES-KW-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" -[FAIL] ML-KEM-768 decapsulateKey with AES-KW-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" -[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-KW-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" -[FAIL] ML-KEM-768 encapsulateKey with HMAC-SHA-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" -[FAIL] ML-KEM-768 decapsulateKey with HMAC-SHA-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" -[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with HMAC-SHA-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" -[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-GCM-256 +[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-GCM-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: importKey" -[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-CBC-256 +[FAIL] ML-KEM-768 encapsulateKey with AES-GCM-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 decapsulateKey with AES-GCM-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-GCM-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-GCM-256 (extractable=false) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: importKey" -[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-CTR-256 +[FAIL] ML-KEM-768 encapsulateKey with AES-CBC-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 decapsulateKey with AES-CBC-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-CBC-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-CBC-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: importKey" -[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-KW-256 +[FAIL] ML-KEM-768 encapsulateKey with AES-CBC-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 decapsulateKey with AES-CBC-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-CBC-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-CBC-256 (extractable=false) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: importKey" -[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with HMAC-SHA-256 +[FAIL] ML-KEM-768 encapsulateKey with AES-CTR-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 decapsulateKey with AES-CTR-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-CTR-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-CTR-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: importKey" -[FAIL] ML-KEM-1024 encapsulateKey with AES-GCM-256 +[FAIL] ML-KEM-768 encapsulateKey with AES-CTR-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 decapsulateKey with AES-CTR-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-CTR-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-CTR-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: importKey" +[FAIL] ML-KEM-768 encapsulateKey with AES-KW-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 decapsulateKey with AES-KW-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-KW-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-KW-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: importKey" +[FAIL] ML-KEM-768 encapsulateKey with AES-KW-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 decapsulateKey with AES-KW-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with AES-KW-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with AES-KW-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: importKey" +[FAIL] ML-KEM-768 encapsulateKey with HMAC-SHA-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 decapsulateKey with HMAC-SHA-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with HMAC-SHA-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with HMAC-SHA-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: importKey" +[FAIL] ML-KEM-768 encapsulateKey with HMAC-SHA-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 decapsulateKey with HMAC-SHA-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 encapsulateKey/decapsulateKey round-trip with HMAC-SHA-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: generateKey" +[FAIL] ML-KEM-768 vector-based sampleCiphertext decapsulation with HMAC-SHA-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': ML-KEM-768: Unsupported operation: importKey" +[FAIL] ML-KEM-1024 encapsulateKey with AES-GCM-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" -[FAIL] ML-KEM-1024 decapsulateKey with AES-GCM-256 +[FAIL] ML-KEM-1024 decapsulateKey with AES-GCM-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" -[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-GCM-256 +[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-GCM-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" -[FAIL] ML-KEM-1024 encapsulateKey with AES-CBC-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" -[FAIL] ML-KEM-1024 decapsulateKey with AES-CBC-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" -[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-CBC-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" -[FAIL] ML-KEM-1024 encapsulateKey with AES-CTR-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" -[FAIL] ML-KEM-1024 decapsulateKey with AES-CTR-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" -[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-CTR-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" -[FAIL] ML-KEM-1024 encapsulateKey with AES-KW-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" -[FAIL] ML-KEM-1024 decapsulateKey with AES-KW-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" -[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-KW-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" -[FAIL] ML-KEM-1024 encapsulateKey with HMAC-SHA-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" -[FAIL] ML-KEM-1024 decapsulateKey with HMAC-SHA-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" -[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with HMAC-SHA-256 - promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" -[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-GCM-256 +[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-GCM-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: importKey" -[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-CBC-256 +[FAIL] ML-KEM-1024 encapsulateKey with AES-GCM-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 decapsulateKey with AES-GCM-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-GCM-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-GCM-256 (extractable=false) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: importKey" -[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-CTR-256 +[FAIL] ML-KEM-1024 encapsulateKey with AES-CBC-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 decapsulateKey with AES-CBC-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-CBC-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-CBC-256 (extractable=true) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: importKey" -[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-KW-256 +[FAIL] ML-KEM-1024 encapsulateKey with AES-CBC-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 decapsulateKey with AES-CBC-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-CBC-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-CBC-256 (extractable=false) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: importKey" -[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with HMAC-SHA-256 +[FAIL] ML-KEM-1024 encapsulateKey with AES-CTR-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 decapsulateKey with AES-CTR-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-CTR-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-CTR-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: importKey" +[FAIL] ML-KEM-1024 encapsulateKey with AES-CTR-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 decapsulateKey with AES-CTR-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-CTR-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-CTR-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: importKey" +[FAIL] ML-KEM-1024 encapsulateKey with AES-KW-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 decapsulateKey with AES-KW-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-KW-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-KW-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: importKey" +[FAIL] ML-KEM-1024 encapsulateKey with AES-KW-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 decapsulateKey with AES-KW-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with AES-KW-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with AES-KW-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: importKey" +[FAIL] ML-KEM-1024 encapsulateKey with HMAC-SHA-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 decapsulateKey with HMAC-SHA-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with HMAC-SHA-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with HMAC-SHA-256 (extractable=true) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: importKey" +[FAIL] ML-KEM-1024 encapsulateKey with HMAC-SHA-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 decapsulateKey with HMAC-SHA-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 encapsulateKey/decapsulateKey round-trip with HMAC-SHA-256 (extractable=false) + promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'generateKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: generateKey" +[FAIL] ML-KEM-1024 vector-based sampleCiphertext decapsulation with HMAC-SHA-256 (extractable=false) promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'importKey' on 'SubtleCrypto': ML-KEM-1024: Unsupported operation: importKey" Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt b/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt index 2da404cc..07b7575 100644 --- a/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt +++ b/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt
@@ -256,7 +256,10 @@ property onmouseover property onmouseup property onmousewheel - property onoverscroll + property onoverscrollcancel + property onoverscrollchanging + property onoverscrollend + property onoverscrollstart property onpaste property onpause property onplay @@ -1597,7 +1600,10 @@ property onmouseover property onmouseup property onmousewheel - property onoverscroll + property onoverscrollcancel + property onoverscrollchanging + property onoverscrollend + property onoverscrollstart property onpaste property onpause property onplay
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt index 8ef3bcd..94689161 100644 --- a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt +++ b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
@@ -2096,7 +2096,10 @@ getter onmouseover getter onmouseup getter onmousewheel - getter onoverscroll + getter onoverscrollcancel + getter onoverscrollchanging + getter onoverscrollend + getter onoverscrollstart getter onpaste getter onpause getter onplay @@ -2324,7 +2327,10 @@ setter onmouseover setter onmouseup setter onmousewheel - setter onoverscroll + setter onoverscrollcancel + setter onoverscrollchanging + setter onoverscrollend + setter onoverscrollstart setter onpaste setter onpause setter onplay @@ -4010,7 +4016,10 @@ getter onmouseover getter onmouseup getter onmousewheel - getter onoverscroll + getter onoverscrollcancel + getter onoverscrollchanging + getter onoverscrollend + getter onoverscrollstart getter onpaste getter onpause getter onplay @@ -4151,7 +4160,10 @@ setter onmouseover setter onmouseup setter onmousewheel - setter onoverscroll + setter onoverscrollcancel + setter onoverscrollchanging + setter onoverscrollend + setter onoverscrollstart setter onpaste setter onpause setter onplay @@ -6157,7 +6169,10 @@ getter onmouseover getter onmouseup getter onmousewheel - getter onoverscroll + getter onoverscrollcancel + getter onoverscrollchanging + getter onoverscrollend + getter onoverscrollstart getter onpaste getter onpause getter onplay @@ -6273,7 +6288,10 @@ setter onmouseover setter onmouseup setter onmousewheel - setter onoverscroll + setter onoverscrollcancel + setter onoverscrollchanging + setter onoverscrollend + setter onoverscrollstart setter onpaste setter onpause setter onplay @@ -7361,7 +7379,8 @@ method constructor interface OverscrollEvent : Event attribute @@toStringTag - getter overscrollElement + getter overscrollTarget + getter overscrolling method constructor interface PageRevealEvent : Event attribute @@toStringTag @@ -8747,7 +8766,10 @@ getter onmouseover getter onmouseup getter onmousewheel - getter onoverscroll + getter onoverscrollcancel + getter onoverscrollchanging + getter onoverscrollend + getter onoverscrollstart getter onpaste getter onpause getter onplay @@ -8865,7 +8887,10 @@ setter onmouseover setter onmouseup setter onmousewheel - setter onoverscroll + setter onoverscrollcancel + setter onoverscrollchanging + setter onoverscrollend + setter onoverscrollstart setter onpaste setter onpause setter onplay @@ -13633,7 +13658,10 @@ getter onmove getter onoffline getter ononline - getter onoverscroll + getter onoverscrollcancel + getter onoverscrollchanging + getter onoverscrollend + getter onoverscrollstart getter onpagehide getter onpagereveal getter onpageshow @@ -13870,7 +13898,10 @@ setter onmove setter onoffline setter ononline - setter onoverscroll + setter onoverscrollcancel + setter onoverscrollchanging + setter onoverscrollend + setter onoverscrollstart setter onpagehide setter onpagereveal setter onpageshow
diff --git a/third_party/blink/web_tests/wpt_internal/overscroll-gestures/overscroll-event-fired.html b/third_party/blink/web_tests/wpt_internal/overscroll-gestures/overscroll-event-fired.html new file mode 100644 index 0000000..df5849f --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/overscroll-gestures/overscroll-event-fired.html
@@ -0,0 +1,91 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<meta name="author" content="github.com/vmpstr"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-vendor.js"></script> + +<style> + html, body { + margin: 0; + } + #container { + width: 200px; + height: 200px; + overflow: auto; + } + #menu { + width: 100%; + height: 100%; + right: 100%; /* Overscrolls to the left of the container. */ + } + #content { + height: 600px; + } +</style> + +<div id="container" overscrollcontainer> + <div id="menu"></div> + <div id="content"></div> +</div> +<button id=button command="toggle-overscroll" commandfor="menu"></button> + +<script> +function click(target) { + let event_received = new Promise(resolve => { + target.addEventListener("click", resolve, { once: true }); + }); + return Promise.all([test_driver.click(button), event_received]); +} + +promise_test(async () => { + let event_promises = [ + new Promise(resolve => container.addEventListener("overscrollstart", resolve, { once: true })), + new Promise(resolve => container.addEventListener("overscrollchanging", resolve, { once: true })), + new Promise(resolve => container.addEventListener("overscrollend", resolve, { once: true })) + ]; + + await click(button); + + let events = await Promise.all(event_promises); + let start_event = events[0]; + let changing_event = events[1]; + let end_event = events[2]; + + assert_equals(start_event.target, container, "Event target should be the container"); + assert_equals(start_event.overscrollTarget, menu, "overscrollTarget should be the menu"); + + assert_equals(changing_event.target, container, "Event target should be the container"); + assert_equals(changing_event.overscrollTarget, menu, "overscrollTarget should be the menu"); + assert_true(changing_event.overscrolling, "overscrolling should be true"); + + assert_equals(end_event.target, container, "Event target should be the container"); + assert_equals(end_event.overscrollTarget, menu, "overscrollTarget should be the menu"); + + // Now close the menu + let event_promises2 = [ + new Promise(resolve => container.addEventListener("overscrollstart", resolve, { once: true })), + new Promise(resolve => container.addEventListener("overscrollchanging", resolve, { once: true })), + new Promise(resolve => container.addEventListener("overscrollend", resolve, { once: true })) + ]; + + await click(button); + + let events2 = await Promise.all(event_promises2); + let start_event2 = events2[0]; + let changing_event2 = events2[1]; + let end_event2 = events2[2]; + + assert_equals(start_event2.target, container, "Event target should be the container"); + assert_equals(start_event2.overscrollTarget, menu, "overscrollTarget should be the menu"); + + assert_equals(changing_event2.target, container, "Event target should be the container"); + assert_equals(changing_event2.overscrollTarget, menu, "overscrollTarget should be the menu"); + assert_false(changing_event2.overscrolling, "overscrolling should be false"); + + assert_equals(end_event2.target, container, "Event target should be the container"); + assert_equals(end_event2.overscrollTarget, menu, "overscrollTarget should be the menu"); + +}, "Toggle overscroll fires overscrollstart, overscrollchanging, overscrollend events with correct overscrollTarget"); +</script>
diff --git a/third_party/blink/web_tests/wpt_internal/overscroll-gestures/toggle-snap-targets-crash.html b/third_party/blink/web_tests/wpt_internal/overscroll-gestures/toggle-snap-targets-crash.html new file mode 100644 index 0000000..7957cc3 --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/overscroll-gestures/toggle-snap-targets-crash.html
@@ -0,0 +1,61 @@ +<!DOCTYPE html> +<html lang="en" class="reftest-wait"> + +<meta charset="UTF-8"> +<meta name="viewport" content="width=device-width, initial-scale=1.0"> +<meta name="author" content="github.com/vmpstr"> +<script src="/common/reftest-wait.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-vendor.js"></script> + +<title>Toggle snap areas crash</title> +<style> +.container { + width: 200px; + height: 200px; +} +.menu { + height: 100%; + width: 100%; + background: lightgreen; + scroll-behavior: smooth; + + &.left { + right: 100%; + } + &.top { + bottom: 100%; + } +} +</style> + +<div class="container" overscrollcontainer> + <div id="menu" class="menu left">Menu</div> +</div> +<button id=button command="toggle-overscroll" commandfor="menu">Open</button> + +<script> +function click(target) { + let event_received = new Promise(resolve => { + target.addEventListener("click", resolve, { once: true }); + }); + return Promise.all([test_driver.click(button), event_received]); +} + +async function runTest() { + for (let i = 0; i < 10; ++i) { + await click(button); + await new Promise(requestAnimationFrame); + await new Promise(requestAnimationFrame); + menu.classList.toggle("left"); + menu.classList.toggle("top"); + await new Promise(requestAnimationFrame); + await new Promise(requestAnimationFrame); + } + takeScreenshot(); +} + +onload = requestAnimationFrame(() => requestAnimationFrame(runTest)); +</script> +</html> +
diff --git a/third_party/catapult b/third_party/catapult index 9bc4a2a..f7a1fb2 160000 --- a/third_party/catapult +++ b/third_party/catapult
@@ -1 +1 @@ -Subproject commit 9bc4a2aee9361b6d2018c2f230c27c64a9e99b36 +Subproject commit f7a1fb2d8f3d155f6d52e95fa486bf91a9ebca81
diff --git a/third_party/crossbench b/third_party/crossbench index 4b00420..877a1b4 160000 --- a/third_party/crossbench +++ b/third_party/crossbench
@@ -1 +1 @@ -Subproject commit 4b00420261e9a2695d8d9b3b3672d1e0092ce241 +Subproject commit 877a1b48c4c43c063150584de7526a103ed92119
diff --git a/third_party/crossbench-web-tests b/third_party/crossbench-web-tests index 909ad17..b19e4e5 160000 --- a/third_party/crossbench-web-tests +++ b/third_party/crossbench-web-tests
@@ -1 +1 @@ -Subproject commit 909ad1733b50f28510c840ebad7b878a5ce07715 +Subproject commit b19e4e52c33fb8a105c3fc99598b0b9b4bc59752
diff --git a/third_party/dawn b/third_party/dawn index ff05aac..18eb229 160000 --- a/third_party/dawn +++ b/third_party/dawn
@@ -1 +1 @@ -Subproject commit ff05aac692cbbce4978d9233313a85d96c391023 +Subproject commit 18eb229ef5f707c1464cc581252e7603c73a3ef0
diff --git a/third_party/depot_tools b/third_party/depot_tools index 4e58caf..95d1432 160000 --- a/third_party/depot_tools +++ b/third_party/depot_tools
@@ -1 +1 @@ -Subproject commit 4e58caf8aa08befe78cf40d08ba33da072b15cf9 +Subproject commit 95d1432b5c506cc6b500b34c23f06c4708139fe9
diff --git a/third_party/devtools-frontend/src b/third_party/devtools-frontend/src index 384800e..9824f31 160000 --- a/third_party/devtools-frontend/src +++ b/third_party/devtools-frontend/src
@@ -1 +1 @@ -Subproject commit 384800eeb706ed5877c72fb9ff662357bbd6fc7d +Subproject commit 9824f31eceddd182136914feecb60f516bc68487
diff --git a/third_party/eigen3/src b/third_party/eigen3/src index ea13a98..1726a92 160000 --- a/third_party/eigen3/src +++ b/third_party/eigen3/src
@@ -1 +1 @@ -Subproject commit ea13a98decd497a8c5588fb5de71b57bcf10d864 +Subproject commit 1726a929009be60a5ed049d23052cbb7ce6f2f96
diff --git a/third_party/fuzztest/src b/third_party/fuzztest/src index 41e1606..3e42dc3 160000 --- a/third_party/fuzztest/src +++ b/third_party/fuzztest/src
@@ -1 +1 @@ -Subproject commit 41e160679e3c010a860e674e7997e2b285c6e0a2 +Subproject commit 3e42dc3c305dd22a22e7d2996c7e24177f3a43ad
diff --git a/third_party/jni_zero/codegen/called_by_native_header.py b/third_party/jni_zero/codegen/called_by_native_header.py index b2132b3..1ccc108 100644 --- a/third_party/jni_zero/codegen/called_by_native_header.py +++ b/third_party/jni_zero/codegen/called_by_native_header.py
@@ -305,6 +305,8 @@ """ if method_name_string in _CPP_RESERVED_KEYWORDS: return method_name_string + '1' + elif method_name_string == 'Constructor': + return 'New' else: return method_name_string
diff --git a/third_party/jni_zero/test/golden/testBidirectionalClass-SampleForTests_jni.h.golden b/third_party/jni_zero/test/golden/testBidirectionalClass-SampleForTests_jni.h.golden index 9e935eb4..6716ac5 100644 --- a/third_party/jni_zero/test/golden/testBidirectionalClass-SampleForTests_jni.h.golden +++ b/third_party/jni_zero/test/golden/testBidirectionalClass-SampleForTests_jni.h.golden
@@ -1175,7 +1175,7 @@ template<> class _CalledByNatives<JSampleForTests> { public: - static jni_zero::ScopedJavaLocalRef<JSampleForTests> Constructor( + static jni_zero::ScopedJavaLocalRef<JSampleForTests> New( JNIEnv* env, JniIntWrapper foo, JniIntWrapper bar) {
diff --git a/third_party/jni_zero/test/golden/testFromClassFile-JavapClass_jni.h.golden b/third_party/jni_zero/test/golden/testFromClassFile-JavapClass_jni.h.golden index 99b8ce37..fb3c12b8 100644 --- a/third_party/jni_zero/test/golden/testFromClassFile-JavapClass_jni.h.golden +++ b/third_party/jni_zero/test/golden/testFromClassFile-JavapClass_jni.h.golden
@@ -324,7 +324,7 @@ template<> class _CalledByNatives<JJavapClass> { public: - static jni_zero::ScopedJavaLocalRef<JJavapClass> Constructor(JNIEnv* env) { + static jni_zero::ScopedJavaLocalRef<JJavapClass> New(JNIEnv* env) { return Java_JavapClass_Constructor(env); }
diff --git a/third_party/jni_zero/test/golden/testPackagePrefixGenerator-SampleForTests_jni.h.golden b/third_party/jni_zero/test/golden/testPackagePrefixGenerator-SampleForTests_jni.h.golden index 1c93cee..6a9fbbd 100644 --- a/third_party/jni_zero/test/golden/testPackagePrefixGenerator-SampleForTests_jni.h.golden +++ b/third_party/jni_zero/test/golden/testPackagePrefixGenerator-SampleForTests_jni.h.golden
@@ -1175,7 +1175,7 @@ template<> class _CalledByNatives<JSampleForTests> { public: - static jni_zero::ScopedJavaLocalRef<JSampleForTests> Constructor( + static jni_zero::ScopedJavaLocalRef<JSampleForTests> New( JNIEnv* env, JniIntWrapper foo, JniIntWrapper bar) {
diff --git a/third_party/jni_zero/test/golden/testPackagePrefixWithFilter-SampleForTests_jni.h.golden b/third_party/jni_zero/test/golden/testPackagePrefixWithFilter-SampleForTests_jni.h.golden index 1c93cee..6a9fbbd 100644 --- a/third_party/jni_zero/test/golden/testPackagePrefixWithFilter-SampleForTests_jni.h.golden +++ b/third_party/jni_zero/test/golden/testPackagePrefixWithFilter-SampleForTests_jni.h.golden
@@ -1175,7 +1175,7 @@ template<> class _CalledByNatives<JSampleForTests> { public: - static jni_zero::ScopedJavaLocalRef<JSampleForTests> Constructor( + static jni_zero::ScopedJavaLocalRef<JSampleForTests> New( JNIEnv* env, JniIntWrapper foo, JniIntWrapper bar) {
diff --git a/third_party/libaom/README.chromium b/third_party/libaom/README.chromium index 9375f86..46bc689 100644 --- a/third_party/libaom/README.chromium +++ b/third_party/libaom/README.chromium
@@ -2,7 +2,7 @@ Short Name: libaom URL: https://aomedia.googlesource.com/aom/ Version: N/A -Revision: 0c15af06af108af03cbe237e4bffa4b700b76d81 +Revision: 34f25197c6e9efef129992bb763aefa6036119fd Update Mechanism: Manual CPEPrefix: cpe:/a:aomedia:aomedia:3.13.1 License: BSD-2-Clause, Patent
diff --git a/third_party/libaom/source/config/config/aom_version.h b/third_party/libaom/source/config/config/aom_version.h index 793a6e708..238cf70 100644 --- a/third_party/libaom/source/config/config/aom_version.h +++ b/third_party/libaom/source/config/config/aom_version.h
@@ -14,9 +14,9 @@ #define VERSION_MAJOR 3 #define VERSION_MINOR 13 #define VERSION_PATCH 1 -#define VERSION_EXTRA "296-g0c15af06af" +#define VERSION_EXTRA "309-g34f25197c6" #define VERSION_PACKED \ ((VERSION_MAJOR << 16) | (VERSION_MINOR << 8) | (VERSION_PATCH)) -#define VERSION_STRING_NOSP "3.13.1-296-g0c15af06af" -#define VERSION_STRING " 3.13.1-296-g0c15af06af" +#define VERSION_STRING_NOSP "3.13.1-309-g34f25197c6" +#define VERSION_STRING " 3.13.1-309-g34f25197c6" #endif // AOM_VERSION_H_
diff --git a/third_party/libaom/source/libaom b/third_party/libaom/source/libaom index 0c15af0..34f2519 160000 --- a/third_party/libaom/source/libaom +++ b/third_party/libaom/source/libaom
@@ -1 +1 @@ -Subproject commit 0c15af06af108af03cbe237e4bffa4b700b76d81 +Subproject commit 34f25197c6e9efef129992bb763aefa6036119fd
diff --git a/third_party/libunwindstack b/third_party/libunwindstack index 0928ad0..333fcaf 160000 --- a/third_party/libunwindstack +++ b/third_party/libunwindstack
@@ -1 +1 @@ -Subproject commit 0928ad0d25e4af07c8be5ab06d0ca584f9f4ceb5 +Subproject commit 333fcafb91bd3830c5ef814c071ff73df9cdc976
diff --git a/third_party/litert/README.chromium b/third_party/litert/README.chromium index 1774440..7b8cee0 100644 --- a/third_party/litert/README.chromium +++ b/third_party/litert/README.chromium
@@ -2,8 +2,8 @@ Short Name: litert URL: https://github.com/google-ai-edge/LiteRT Version: N/A -Revision: 36dcf5a2ac1d6cc02df53d5e3f5bcd6dd6876ff0 -Date: 2026-03-10 +Revision: 13469058b8ee37e2153481ba49644764666ad275 +Date: 2026-03-17 Update Mechanism: Manual License: Apache-2.0 License File: LICENSE
diff --git a/third_party/litert/src b/third_party/litert/src index 36dcf5a..1346905 160000 --- a/third_party/litert/src +++ b/third_party/litert/src
@@ -1 +1 @@ -Subproject commit 36dcf5a2ac1d6cc02df53d5e3f5bcd6dd6876ff0 +Subproject commit 13469058b8ee37e2153481ba49644764666ad275
diff --git a/third_party/perfetto b/third_party/perfetto index 4e4843a..9b59f48 160000 --- a/third_party/perfetto +++ b/third_party/perfetto
@@ -1 +1 @@ -Subproject commit 4e4843ae073504d2f58540031a8f41471fa86a76 +Subproject commit 9b59f48e11a56a8d2dddd60299e7e25b68b3072c
diff --git a/third_party/rust/chromium_crates_io/Cargo.lock b/third_party/rust/chromium_crates_io/Cargo.lock index 06a7f0c..b1ca66f 100644 --- a/third_party/rust/chromium_crates_io/Cargo.lock +++ b/third_party/rust/chromium_crates_io/Cargo.lock
@@ -139,7 +139,7 @@ [[package]] name = "cc" -version = "1.2.56" +version = "1.2.57" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "find-msvc-tools",
diff --git a/third_party/rust/chromium_crates_io/vendor/cc-v1/Cargo.toml b/third_party/rust/chromium_crates_io/vendor/cc-v1/Cargo.toml index 387de8b..fb3e578 100644 --- a/third_party/rust/chromium_crates_io/vendor/cc-v1/Cargo.toml +++ b/third_party/rust/chromium_crates_io/vendor/cc-v1/Cargo.toml
@@ -6,13 +6,13 @@ # by `tools/crates/run_gnrt.py vendor`. Do not edit! # # This is an empty placeholder that has replaced the -# `cc-1.2.56` crate. +# `cc-1.2.57` crate. # # See `//tools/crates/gnrt/removed_crate.md` to learn more. [package] name = "cc" -version = "1.2.56" +version = "1.2.57" [package.metadata.gnrt] is_placeholder = true
diff --git a/third_party/rust/chromium_crates_io/vendor/cc-v1/src/lib.rs b/third_party/rust/chromium_crates_io/vendor/cc-v1/src/lib.rs index 1f96e02..edad16b4 100644 --- a/third_party/rust/chromium_crates_io/vendor/cc-v1/src/lib.rs +++ b/third_party/rust/chromium_crates_io/vendor/cc-v1/src/lib.rs
@@ -6,6 +6,6 @@ // by `tools/crates/run_gnrt.py vendor`. Do not edit! // // This is an empty placeholder that has replaced the -// `cc-1.2.56` crate. +// `cc-1.2.57` crate. // // See `//tools/crates/gnrt/removed_crate.md` to learn more.
diff --git a/third_party/skia b/third_party/skia index 122a1f3..02ba2ea 160000 --- a/third_party/skia +++ b/third_party/skia
@@ -1 +1 @@ -Subproject commit 122a1f31d3f9bf50cedc03e46ba0fa87e46176ec +Subproject commit 02ba2eac9d65834f70e239e4db87b750dd489e73
diff --git a/third_party/tflite/README.chromium b/third_party/tflite/README.chromium index 81306e35..17416c9 100644 --- a/third_party/tflite/README.chromium +++ b/third_party/tflite/README.chromium
@@ -1,9 +1,9 @@ Name: TensorFlow Lite Short Name: tflite URL: https://github.com/tensorflow/tensorflow -Version: d20369f4f226598800e0d406db567d2d1c17fa95 -Revision: d20369f4f226598800e0d406db567d2d1c17fa95 -Date: 2026-03-10 +Version: 24d66fbe6c5e87d291207494e4e83d39de3f7d90 +Revision: 24d66fbe6c5e87d291207494e4e83d39de3f7d90 +Date: 2026-03-17 Update Mechanism: Manual License: Caffe, Apache-2.0 License File: LICENSE
diff --git a/third_party/tflite/src b/third_party/tflite/src index d20369f..24d66fb 160000 --- a/third_party/tflite/src +++ b/third_party/tflite/src
@@ -1 +1 @@ -Subproject commit d20369f4f226598800e0d406db567d2d1c17fa95 +Subproject commit 24d66fbe6c5e87d291207494e4e83d39de3f7d90
diff --git a/third_party/vulkan-deps b/third_party/vulkan-deps index 98fee62..7c625f8 160000 --- a/third_party/vulkan-deps +++ b/third_party/vulkan-deps
@@ -1 +1 @@ -Subproject commit 98fee6234d1614a87f58a40b35643d3766259a26 +Subproject commit 7c625f80e8cc10f33333a556ebb55a0443289b42
diff --git a/third_party/vulkan-validation-layers/src b/third_party/vulkan-validation-layers/src index ea525ef..d257596 160000 --- a/third_party/vulkan-validation-layers/src +++ b/third_party/vulkan-validation-layers/src
@@ -1 +1 @@ -Subproject commit ea525ef7ecc94e55e821c784ab3f4b7ef1c4feba +Subproject commit d2575968391366f3eb2fa41656076a906dcf86ed
diff --git a/third_party/wayland-protocols/README.chromium b/third_party/wayland-protocols/README.chromium index 6521d9b..b1af664 100644 --- a/third_party/wayland-protocols/README.chromium +++ b/third_party/wayland-protocols/README.chromium
@@ -38,7 +38,8 @@ Name: gtk URL: https://github.com/GNOME/gtk Version: 4.3.0 -Revision: ac07997f886a02db0cdf27a994686db13cef2e15 +Revision: 40ebed3a03aef096addc0af09fec4ec529d882a0 +Date: 2021-05-03 Update Mechanism: Manual License: LGPL-2.0 License File: gtk/COPYING @@ -60,7 +61,8 @@ Name: plasma-wayland-protocols URL: https://github.com/KDE/plasma-wayland-protocols Version: 1.3.0 -Revision: 493efe04e01780f4371f95b7b2de957cf4a31bf3 +Revision: 0b07950714b3a36c9b9f71fc025fc7783e82926e +Date: 2021-04-30 Update Mechanism: Manual License: LGPL-2.1 License File: kde/COPYING.LIB
diff --git a/third_party/webrtc b/third_party/webrtc index aa21720..6f76a57 160000 --- a/third_party/webrtc +++ b/third_party/webrtc
@@ -1 +1 @@ -Subproject commit aa217206b9ce8b929dc56d112d670a5931ef8cc1 +Subproject commit 6f76a57334e3d1f4629fdbf7f9d9bc3c38feadc9
diff --git a/third_party/wix b/third_party/wix index 1cda037..d0745e3 160000 --- a/third_party/wix +++ b/third_party/wix
@@ -1 +1 @@ -Subproject commit 1cda03778b09bee24389da73daef3de862da37fc +Subproject commit d0745e3bc7a7a83b8848d9384ac0178036c1fd04
diff --git a/third_party/xnnpack/BUILD.gn b/third_party/xnnpack/BUILD.gn index 990fe2d4..32958ce 100644 --- a/third_party/xnnpack/BUILD.gn +++ b/third_party/xnnpack/BUILD.gn
@@ -1221,6 +1221,7 @@ ":qd8-f16-qb4w-gemm_arch=armv8.2-a+dotprod+fp16", ":qd8-f16-qb4w-gemm_arch=armv8.2-a+fp16", ":qd8-f16-qb4w-gemm_arch=armv8.2-a+i8mm+fp16", + ":qd8-f16-qc2w-gemm_arch=armv8.2-a+dotprod+fp16", ":qd8-f16-qc2w-gemm_arm64", ":qd8-f16-qc4w-gemm_arch=armv8.2-a+dotprod+fp16", ":qd8-f16-qc4w-gemm_arch=armv8.2-a+fp16", @@ -1450,6 +1451,7 @@ ":qd8-f16-qb4w-gemm_arch=armv8.2-a+dotprod+fp16_standalone", ":qd8-f16-qb4w-gemm_arch=armv8.2-a+fp16_standalone", ":qd8-f16-qb4w-gemm_arch=armv8.2-a+i8mm+fp16_standalone", + ":qd8-f16-qc2w-gemm_arch=armv8.2-a+dotprod+fp16_standalone", ":qd8-f16-qc2w-gemm_arm64_standalone", ":qd8-f16-qc4w-gemm_arch=armv8.2-a+dotprod+fp16_standalone", ":qd8-f16-qc4w-gemm_arch=armv8.2-a+fp16_standalone", @@ -42345,6 +42347,65 @@ } if (build_with_chromium) { + source_set("qd8-f16-qc2w-gemm_arch=armv8.2-a+dotprod+fp16") { + cflags = [ "-march=armv8.2-a+dotprod+fp16" ] + + sources = [ + "src/include/xnnpack.h", + "src/src/qd8-f16-qc2w-gemm/gen/qd8-f16-qc2w-gemm-1x8c4-minmax-neondotfp16arith.c", + "src/src/qd8-f16-qc2w-gemm/gen/qd8-f16-qc2w-gemm-2x8c4-minmax-neondotfp16arith.c", + "src/src/qd8-f16-qc2w-gemm/gen/qd8-f16-qc2w-gemm-8x8c4-minmax-neondotfp16arith.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + configs += [ ":xnnpack_private_config" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool", + ] + + public_configs = [ ":xnnpack_public_config" ] + } + } + + # This is a target that cannot depend on //base. + if (build_with_internal_optimization_guide) { + source_set("qd8-f16-qc2w-gemm_arch=armv8.2-a+dotprod+fp16_standalone") { + cflags = [ "-march=armv8.2-a+dotprod+fp16" ] + + sources = [ + "src/include/xnnpack.h", + "src/src/qd8-f16-qc2w-gemm/gen/qd8-f16-qc2w-gemm-1x8c4-minmax-neondotfp16arith.c", + "src/src/qd8-f16-qc2w-gemm/gen/qd8-f16-qc2w-gemm-2x8c4-minmax-neondotfp16arith.c", + "src/src/qd8-f16-qc2w-gemm/gen/qd8-f16-qc2w-gemm-8x8c4-minmax-neondotfp16arith.c", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] + configs += [ ":xnnpack_private_config" ] + + deps = [ + "//third_party/cpuinfo", + "//third_party/fp16", + "//third_party/fxdiv", + "//third_party/pthreadpool:pthreadpool_standalone", + ] + + public_configs = [ ":xnnpack_public_config" ] + + if (!(is_android && use_order_profiling)) { + assert_no_deps = [ "//base" ] + } + } + } + + if (build_with_chromium) { source_set("qd8-f16-qc2w-gemm_arm64") { cflags = []
diff --git a/third_party/xnnpack/README.chromium b/third_party/xnnpack/README.chromium index 63faf9d..daaf2f1b 100644 --- a/third_party/xnnpack/README.chromium +++ b/third_party/xnnpack/README.chromium
@@ -2,7 +2,7 @@ Short Name: xnnpack URL: https://github.com/google/xnnpack Version: N/A -Revision: 15e04ff8b61e0bc2118bad268447be5b2075aa66 +Revision: ee91cc745bc715bfa38c5e8241aeb435ca59f433 Update Mechanism: Manual License: BSD-3-Clause License File: src/LICENSE
diff --git a/third_party/xnnpack/build_identifier.c b/third_party/xnnpack/build_identifier.c index c8e0cca5..a891a2d 100644 --- a/third_party/xnnpack/build_identifier.c +++ b/third_party/xnnpack/build_identifier.c
@@ -1026,10 +1026,10 @@ #include <string.h> static const uint8_t xnn_build_identifier[] = { - 86, 129, 33, 184, 94, 216, 204, 45, - 214, 201, 87, 153, 42, 213, 105, 44, - 203, 198, 29, 170, 109, 0, 14, 229, - 165, 226, 219, 0, 183, 41, 183, 247 + 241, 44, 87, 72, 212, 197, 37, 129, + 153, 184, 55, 208, 40, 53, 117, 239, + 84, 243, 43, 179, 178, 246, 230, 112, + 18, 29, 15, 185, 184, 116, 145, 134 }; size_t xnn_experimental_get_build_identifier_size() {
diff --git a/third_party/xnnpack/src b/third_party/xnnpack/src index 15e04ff..ee91cc7 160000 --- a/third_party/xnnpack/src +++ b/third_party/xnnpack/src
@@ -1 +1 @@ -Subproject commit 15e04ff8b61e0bc2118bad268447be5b2075aa66 +Subproject commit ee91cc745bc715bfa38c5e8241aeb435ca59f433
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml index e1cd8d8..991d827 100644 --- a/tools/metrics/actions/actions.xml +++ b/tools/metrics/actions/actions.xml
@@ -10956,6 +10956,24 @@ </description> </action> +<action + name="ContextualSearch.TypedSuggestNavigation.{TypedSuggestType}.{ContextualSearchSource}"> + <owner>niharm@google.com</owner> + <owner>chrome-desktop-search@google.com</owner> + <description> + Recorded when a user navigates to a {TypedSuggestType} suggestion in the + typed mode from {ContextualSearchSource}. + </description> + <token key="TypedSuggestType"> + <variant name="SearchSuggest" + summary="The user selected a suggestion from the dropdown."/> + <variant name="Verbatim" + summary="The user submitted the query verbatim (e.g. typed out the + entire query and then pressed enter)."/> + </token> + <token key="ContextualSearchSource" variants="ContextualSearchSource"/> +</action> + <action name="ContextualSearch.UncommonClose"> <owner>donnd@chromium.org</owner> <description>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 9204f481..13a28f0d 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -9818,6 +9818,7 @@ <int value="-1581724231" label="ModalPermissionPrompts:enabled"/> <int value="-1581536170" label="TabSwitcherGroupSuggestionsTestModeAndroid:disabled"/> + <int value="-1581226384" label="ThreeDotMenuBackButton:disabled"/> <int value="-1580376019" label="ShowAllDialogsWithViewsToolkit:enabled"/> <int value="-1579273370" label="FastPairPwaCompanion:enabled"/> <int value="-1578781240" label="QuickAnswersV2:enabled"/> @@ -11863,6 +11864,7 @@ <int value="-898005938" label="disable-pinch-virtual-viewport"/> <int value="-897994913" label="OmniboxUIExperimentRevealSteadyStateUrlPathQueryAndRefOnHover:enabled"/> + <int value="-897718456" label="ProcessIsolationSettings:disabled"/> <int value="-897660267" label="BluetoothDisconnectWarning:enabled"/> <int value="-897069393" label="kAutofillRationalizeRepeatedServerPredictions:disabled"/> @@ -12513,6 +12515,7 @@ label="UserCloudSigninRestrictionPolicyFetcher:enabled"/> <int value="-681434111" label="WebFeed:disabled"/> <int value="-681160117" label="ChromeOSHWVBREncoding:disabled"/> + <int value="-680978374" label="ProcessIsolationSettings:enabled"/> <int value="-680787130" label="ExperimentalVRFeatures:disabled"/> <int value="-680589442" label="MacRTL:disabled"/> <int value="-679585025" label="CaptureModeSelfieCamera:disabled"/> @@ -13028,6 +13031,7 @@ <int value="-504952236" label="AutocorrectParamsTuning:disabled"/> <int value="-504485318" label="AutofillFixServerQueriesIfPasswordManagerIsEnabled:enabled"/> + <int value="-503839607" label="NtpDoodleMurals:enabled"/> <int value="-503636510" label="UnifiedPasswordManagerSyncOnlyInGMSCore:disabled"/> <int value="-503601144" label="UserDataSnapshot:disabled"/> @@ -13484,6 +13488,7 @@ <int value="-344357771" label="WebAuthenticationCrosPlatformAuthenticator:enabled"/> <int value="-344343842" label="disable-experimental-app-list"/> + <int value="-344076279" label="NtpAnimatedDoodles:enabled"/> <int value="-343971624" label="BorealisPermitted:disabled"/> <int value="-343769596" label="ServiceWorkerScriptStreaming:disabled"/> <int value="-343314036" label="WebBluetooth:enabled"/> @@ -16921,6 +16926,7 @@ <int value="807734471" label="tab-management-experiment-type-disabled"/> <int value="808855873" label="RequestDesktopSiteGlobal:disabled"/> <int value="809404981" label="CrosBatterySaver:enabled"/> + <int value="810556985" label="NtpAnimatedDoodles:disabled"/> <int value="811057677" label="ConfirmNtpSuggestionRemovals:disabled"/> <int value="811158245" label="DevToolsPwaHandler:disabled"/> <int value="811374216" label="disable-new-bookmark-apps"/> @@ -19649,6 +19655,7 @@ <int value="1728816382" label="SeaPenEnterprise:disabled"/> <int value="1729485335" label="CastMessageLogging:disabled"/> <int value="1729672254" label="MobilePromoOnDesktopWithQRCodeWave1:enabled"/> + <int value="1729883090" label="ThreeDotMenuBackButton:enabled"/> <int value="1730094138" label="enable-md-storage-manager"/> <int value="1730236697" label="force-device-scale-factor"/> <int value="1730416578" label="NTPCondensedLayout:enabled"/> @@ -20767,6 +20774,7 @@ <int value="2100708771" label="AutofillVcnEnrollRequestTimeout:disabled"/> <int value="2101124624" label="WebUIDownloadShelf:disabled"/> <int value="2101151142" label="disable-direct-write"/> + <int value="2101244145" label="NtpDoodleMurals:disabled"/> <int value="2102772909" label="EnableGenericOidcAuthProfileManagement:disabled"/> <int value="2103800063"
diff --git a/tools/metrics/histograms/metadata/contextual_search/histograms.xml b/tools/metrics/histograms/metadata/contextual_search/histograms.xml index a2a6a8f31..aa0c1f1b 100644 --- a/tools/metrics/histograms/metadata/contextual_search/histograms.xml +++ b/tools/metrics/histograms/metadata/contextual_search/histograms.xml
@@ -751,6 +751,19 @@ </histogram> <histogram + name="ContextualSearch.TypedSuggestNavigation.IsVerbatim.{ContextualSearchSource}" + enum="Boolean" expires_after="2026-08-09"> + <owner>niharm@google.com</owner> + <owner>chrome-desktop-search@google.com</owner> + <summary> + Recorded when a user navigates to a suggestion in typed mode from + {ContextualSearchSource}. Logs true if the suggestion was verbatim, and + false otherwise (SearchSuggest). + </summary> + <token key="ContextualSearchSource" variants="ContextualSearchSource"/> +</histogram> + +<histogram name="ContextualSearch.UserAction.DeleteAutoSuggestedTab.{ContextualSearchSource}" enum="Boolean" expires_after="2026-08-09"> <owner>sophiechang@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/extensions/histograms.xml b/tools/metrics/histograms/metadata/extensions/histograms.xml index 150539d..bc1c42f 100644 --- a/tools/metrics/histograms/metadata/extensions/histograms.xml +++ b/tools/metrics/histograms/metadata/extensions/histograms.xml
@@ -852,7 +852,7 @@ </histogram> <histogram name="Extensions.CookieAPIPartitionKeyWellFormatted" - enum="BooleanEnabled" expires_after="2026-04-30"> + enum="BooleanEnabled" expires_after="2027-04-30"> <owner>arichiv@google.com</owner> <owner>src/net/cookies/OWNERS</owner> <summary> @@ -1238,7 +1238,7 @@ </histogram> <histogram name="Extensions.DeclarativeNetRequest.ManifestEnabledRulesCount2" - units="rules" expires_after="2026-04-28"> + units="rules" expires_after="2026-10-28"> <owner>kelvinjiang@chromium.org</owner> <owner>extensions-core@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/ios/enums.xml b/tools/metrics/histograms/metadata/ios/enums.xml index 010ca0c..dd7e3e22 100644 --- a/tools/metrics/histograms/metadata/ios/enums.xml +++ b/tools/metrics/histograms/metadata/ios/enums.xml
@@ -1313,6 +1313,8 @@ <int value="3" label="Scroll, action"/> </enum> +<!-- LINT.IfChange(IOSOverflowMenuDestination) --> + <enum name="IOSOverflowMenuDestination"> <int value="0" label="Bookmarks"/> <int value="1" label="History"/> @@ -1325,8 +1327,14 @@ <int value="8" label="WhatsNew"/> <int value="9" label="SpotlightDebugger"/> <int value="10" label="PriceNotifications"/> + <int value="11" label="Cobalt"/> </enum> +<!-- LINT.ThenChange( + /ios/chrome/browser/popup_menu/overflow_menu/ui/overflow_menu_metrics.h:destination, + /ios/chrome/browser/popup_menu/overflow_menu/public/overflow_menu_constants.h:destination +)--> + <enum name="IOSOverflowMenuReorderingReason"> <int value="0" label="Error Badge"/> <int value="1" label="New Badge"/>
diff --git a/tools/metrics/histograms/metadata/nearby/histograms.xml b/tools/metrics/histograms/metadata/nearby/histograms.xml index b34f7231..f97e7b64 100644 --- a/tools/metrics/histograms/metadata/nearby/histograms.xml +++ b/tools/metrics/histograms/metadata/nearby/histograms.xml
@@ -31,7 +31,7 @@ </variants> <histogram name="Nearby.BluetoothAdapter.AdvertisingSupport" - enum="NearbyBluetoothAdapterAdvertisingSupport" expires_after="2026-09-06"> + enum="NearbyBluetoothAdapterAdvertisingSupport" expires_after="2027-04-30"> <owner>julietlevesque@google.com</owner> <owner>chromeos-cross-device-eng@google.com</owner> <summary> @@ -43,7 +43,7 @@ </histogram> <histogram name="Nearby.Connections.BleV2.ConnectToGattServer.Duration" - units="ms" expires_after="2026-04-30"> + units="ms" expires_after="2027-04-30"> <owner>julietlevesque@google.com</owner> <owner>chromeos-cross-device-eng@google.com</owner> <summary> @@ -55,7 +55,7 @@ </histogram> <histogram name="Nearby.Connections.BleV2.ConnectToGattServer.FailureReason" - enum="NearbyConnectionsConnectResult" expires_after="2026-04-30"> + enum="NearbyConnectionsConnectResult" expires_after="2027-04-30"> <owner>julietlevesque@google.com</owner> <owner>chromeos-cross-device-eng@google.com</owner> <summary> @@ -68,7 +68,7 @@ </histogram> <histogram name="Nearby.Connections.BleV2.ConnectToGattServer.Result" - enum="BooleanSuccess" expires_after="2026-04-30"> + enum="BooleanSuccess" expires_after="2027-04-30"> <owner>julietlevesque@google.com</owner> <owner>chromeos-cross-device-eng@google.com</owner> <summary> @@ -81,7 +81,7 @@ <histogram name="Nearby.Connections.BleV2.GattClient.ReadCharacteristic.Duration" - units="ms" expires_after="2026-04-30"> + units="ms" expires_after="2027-04-30"> <owner>julietlevesque@google.com</owner> <owner>chromeos-cross-device-eng@google.com</owner> <summary> @@ -97,7 +97,7 @@ <histogram name="Nearby.Connections.BleV2.GattClient.ReadCharacteristic.FailureReason" - enum="NearbyConnectionsGattResult" expires_after="2026-04-30"> + enum="NearbyConnectionsGattResult" expires_after="2027-04-30"> <owner>julietlevesque@google.com</owner> <owner>chromeos-cross-device-eng@google.com</owner> <summary> @@ -114,7 +114,7 @@ </histogram> <histogram name="Nearby.Connections.BleV2.GattClient.ReadCharacteristic.Result" - enum="BooleanSuccess" expires_after="2026-04-30"> + enum="BooleanSuccess" expires_after="2027-04-30"> <owner>julietlevesque@google.com</owner> <owner>chromeos-cross-device-eng@google.com</owner> <summary> @@ -128,7 +128,7 @@ <histogram name="Nearby.Connections.BleV2.GattServer.CreateCharacteristic.Result" - enum="BooleanSuccess" expires_after="2026-04-30"> + enum="BooleanSuccess" expires_after="2027-04-30"> <owner>julietlevesque@google.com</owner> <owner>chromeos-cross-device-eng@google.com</owner> <summary> @@ -146,7 +146,7 @@ <histogram name="Nearby.Connections.BleV2.GattServer.CreateLocalGattService.Result" - enum="BooleanSuccess" expires_after="2026-04-30"> + enum="BooleanSuccess" expires_after="2027-04-30"> <owner>julietlevesque@google.com</owner> <owner>chromeos-cross-device-eng@google.com</owner> <summary> @@ -160,7 +160,7 @@ <histogram name="Nearby.Connections.BleV2.GattServer.OnLocalCharacteristicRead.Result" - enum="BooleanSuccess" expires_after="2026-04-30"> + enum="BooleanSuccess" expires_after="2027-04-30"> <owner>julietlevesque@google.com</owner> <owner>chromeos-cross-device-eng@google.com</owner> <summary> @@ -175,7 +175,7 @@ <histogram name="Nearby.Connections.BleV2.GattServer.RegisterGattService.FailureReason" - enum="BluetoothGattServiceGattErrorCode" expires_after="2026-04-30"> + enum="BluetoothGattServiceGattErrorCode" expires_after="2027-04-30"> <owner>julietlevesque@google.com</owner> <owner>chromeos-cross-device-eng@google.com</owner> <summary> @@ -188,7 +188,7 @@ <histogram name="Nearby.Connections.BleV2.GattServer.RegisterGattServices.Result" - enum="BooleanSuccess" expires_after="2026-04-30"> + enum="BooleanSuccess" expires_after="2027-04-30"> <owner>julietlevesque@google.com</owner> <owner>chromeos-cross-device-eng@google.com</owner> <summary> @@ -207,7 +207,7 @@ <histogram name="Nearby.Connections.BleV2.GattServer.UpdateCharacteristic.Result" - enum="BooleanSuccess" expires_after="2026-04-30"> + enum="BooleanSuccess" expires_after="2027-04-30"> <owner>julietlevesque@google.com</owner> <owner>chromeos-cross-device-eng@google.com</owner> <summary> @@ -222,7 +222,7 @@ </histogram> <histogram name="Nearby.Connections.BleV2.ScatternetDualRoleSupported" - enum="Boolean" expires_after="2026-09-06"> + enum="Boolean" expires_after="2027-04-30"> <owner>julietlevesque@google.com</owner> <owner>chromeos-cross-device-eng@google.com</owner> <summary> @@ -237,7 +237,7 @@ <histogram name="Nearby.Connections.BleV2.StartAdvertising.FailureReason{AdvertisementType}" enum="NearbyConnectionsStartAdvertisingFailureReason" - expires_after="2026-04-30"> + expires_after="2027-04-30"> <owner>dclasson@google.com</owner> <owner>chromeos-cross-device-eng@google.com</owner> <summary> @@ -257,7 +257,7 @@ <histogram name="Nearby.Connections.BleV2.StartAdvertising.Result{AdvertisementType}" - enum="BooleanSuccess" expires_after="2026-09-06"> + enum="BooleanSuccess" expires_after="2027-04-30"> <owner>dclasson@google.com</owner> <owner>chromeos-cross-device-eng@google.com</owner> <summary> @@ -277,7 +277,7 @@ <histogram name="Nearby.Connections.BleV2.StartScanning.FailureReason" enum="NearbyConnectionsStartScanningFailureReason" - expires_after="2026-04-30"> + expires_after="2027-04-30"> <owner>dclasson@google.com</owner> <owner>chromeos-cross-device-eng@google.com</owner> <summary> @@ -288,7 +288,7 @@ </histogram> <histogram name="Nearby.Connections.BleV2.StartScanning.Result" - enum="BooleanSuccess" expires_after="2026-04-30"> + enum="BooleanSuccess" expires_after="2027-04-30"> <owner>dclasson@google.com</owner> <owner>chromeos-cross-device-eng@google.com</owner> <summary> @@ -298,7 +298,7 @@ </histogram> <histogram name="Nearby.Connections.Bluetooth.Adapter.SetName.Result" - enum="BooleanSuccess" expires_after="2026-09-06"> + enum="BooleanSuccess" expires_after="2027-04-30"> <owner>hansenmichael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -308,7 +308,7 @@ </histogram> <histogram name="Nearby.Connections.Bluetooth.Adapter.SetScanMode.Result" - enum="BooleanSuccess" expires_after="2026-07-05"> + enum="BooleanSuccess" expires_after="2027-04-30"> <owner>hansenmichael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -319,7 +319,7 @@ <histogram name="Nearby.Connections.Bluetooth.ClassicMedium.ConnectToService.Duration" - units="ms" expires_after="2026-09-06"> + units="ms" expires_after="2027-04-30"> <owner>hansenmichael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -329,7 +329,7 @@ </histogram> <histogram name="Nearby.Connections.Bluetooth.ClassicMedium.{Operation}.Result" - enum="BooleanSuccess" expires_after="2026-09-06"> + enum="BooleanSuccess" expires_after="2027-04-30"> <owner>hansenmichael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary>Records the result of {Operation}.</summary> @@ -342,7 +342,7 @@ </histogram> <histogram name="Nearby.Connections.Bluetooth.LEMedium.StartAdvertising.Result" - enum="BooleanSuccess" expires_after="2026-04-30"> + enum="BooleanSuccess" expires_after="2027-04-30"> <owner>hansenmichael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -351,7 +351,7 @@ </histogram> <histogram name="Nearby.Connections.Bluetooth.LEMedium.StartScanning.Result" - enum="BooleanSuccess" expires_after="2026-04-30"> + enum="BooleanSuccess" expires_after="2027-04-30"> <owner>hansenmichael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -360,7 +360,7 @@ </histogram> <histogram name="Nearby.Connections.Bluetooth.LEMedium.StopAdvertising.Result" - enum="BooleanSuccess" expires_after="2026-04-30"> + enum="BooleanSuccess" expires_after="2027-04-30"> <owner>hansenmichael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -369,7 +369,7 @@ </histogram> <histogram name="Nearby.Connections.Bluetooth.LEMedium.StopScanning.Result" - enum="BooleanSuccess" expires_after="2026-04-30"> + enum="BooleanSuccess" expires_after="2027-04-30"> <owner>hansenmichael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary>Records whether BLE scanning has been stopped successfully.</summary> @@ -377,7 +377,7 @@ <histogram name="Nearby.Connections.InstantMessaging.ReceiveExpress.NumParsingAttempts" - units="attempts" expires_after="2026-04-30"> + units="attempts" expires_after="2027-04-30"> <owner>julietlevesque@chromium.org</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -390,7 +390,7 @@ <histogram name="Nearby.Connections.InstantMessaging.TachyonIceConfigFetcher.CacheHit" - enum="BooleanCacheHit" expires_after="2026-04-30"> + enum="BooleanCacheHit" expires_after="2027-04-30"> <owner>crisrael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -401,7 +401,7 @@ <histogram name="Nearby.Connections.InstantMessaging.TachyonIceConfigFetcher.FailureReason" - enum="CombinedHttpResponseAndNetErrorCode" expires_after="2026-04-30"> + enum="CombinedHttpResponseAndNetErrorCode" expires_after="2027-04-30"> <owner>crisrael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -412,7 +412,7 @@ <histogram name="Nearby.Connections.InstantMessaging.TachyonIceConfigFetcher.OAuthTokenFetchResult" - enum="BooleanSuccess" expires_after="2026-04-30"> + enum="BooleanSuccess" expires_after="2027-04-30"> <owner>crisrael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -423,7 +423,7 @@ <histogram name="Nearby.Connections.InstantMessaging.TachyonIceConfigFetcher.Result" - enum="BooleanSuccess" expires_after="2026-04-30"> + enum="BooleanSuccess" expires_after="2027-04-30"> <owner>crisrael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -434,7 +434,7 @@ <histogram name="Nearby.Connections.InstantMessaging.{Direction}Express.OAuthTokenFetchResult" - enum="BooleanSuccess" expires_after="2026-04-30"> + enum="BooleanSuccess" expires_after="2027-04-30"> <owner>hansenmichael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -450,7 +450,7 @@ </histogram> <histogram name="Nearby.Connections.InstantMessaging.{Direction}Express.Result" - enum="BooleanSuccess" expires_after="2026-09-06"> + enum="BooleanSuccess" expires_after="2027-04-30"> <owner>hansenmichael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -465,7 +465,7 @@ <histogram name="Nearby.Connections.InstantMessaging.{Direction}Express.Result.FailureReason" - enum="CombinedHttpResponseAndNetErrorCode" expires_after="2026-07-05"> + enum="CombinedHttpResponseAndNetErrorCode" expires_after="2027-04-30"> <owner>hansenmichael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -481,7 +481,7 @@ <histogram name="Nearby.Connections.UtilityProcessShutdownReason" enum="NearbyConnectionsUtilityProcessShutdownReason" - expires_after="2026-09-06"> + expires_after="2027-04-30"> <owner>hansenmichael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -494,7 +494,7 @@ <histogram name="Nearby.Connections.UtilityProcessShutdownReason.DisconnectedMojoDependency" enum="NearbyConnectionsUtilityProcessMojoDependencyName" - expires_after="2026-04-30"> + expires_after="2027-04-30"> <owner>hansenmichael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -507,7 +507,7 @@ </histogram> <histogram name="Nearby.Connections.V3.Connection.Result" - enum="NearbyConnectionsStatus" expires_after="2026-04-30"> + enum="NearbyConnectionsStatus" expires_after="2027-04-30"> <owner>crisrael@google.com</owner> <owner>chromeos-cross-device-eng@google.com</owner> <summary> @@ -518,7 +518,7 @@ </histogram> <histogram name="Nearby.Connections.V3.ConnectionResult.Success.Latency" - units="ms" expires_after="2026-04-30"> + units="ms" expires_after="2027-04-30"> <owner>crisrael@google.com</owner> <owner>chromeos-cross-device-eng@google.com</owner> <summary> @@ -529,7 +529,7 @@ </histogram> <histogram name="Nearby.Connections.V3.Medium.ChangedToMedium" - enum="NearbyConnectionsMedium" expires_after="2026-04-30"> + enum="NearbyConnectionsMedium" expires_after="2027-04-30"> <owner>crisrael@google.com</owner> <owner>chromeos-cross-device-eng@google.com</owner> <summary> @@ -540,7 +540,7 @@ </histogram> <histogram name="Nearby.Connections.WifiDirect.AssociateSocket.Result" - enum="BooleanSuccess" expires_after="2026-04-30"> + enum="BooleanSuccess" expires_after="2027-04-30"> <owner>jackshira@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -551,7 +551,7 @@ </histogram> <histogram name="Nearby.Connections.WifiDirect.ConnectToService.Error" - enum="NearbyConnectionsWifiDirectServiceError" expires_after="2026-04-30"> + enum="NearbyConnectionsWifiDirectServiceError" expires_after="2027-04-30"> <owner>jackshira@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -562,7 +562,7 @@ </histogram> <histogram name="Nearby.Connections.WifiDirect.ConnectToService.Result" - enum="BooleanSuccess" expires_after="2026-04-30"> + enum="BooleanSuccess" expires_after="2027-04-30"> <owner>jackshira@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -573,7 +573,7 @@ </histogram> <histogram name="Nearby.Connections.WifiDirect.ConnectToWifiDirectGroup.Error" - enum="NearbyConnectionsWifiDirectResult" expires_after="2026-04-30"> + enum="NearbyConnectionsWifiDirectResult" expires_after="2027-04-30"> <owner>jackshira@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -584,7 +584,7 @@ </histogram> <histogram name="Nearby.Connections.WifiDirect.ConnectToWifiDirectGroup.Result" - enum="BooleanSuccess" expires_after="2026-04-30"> + enum="BooleanSuccess" expires_after="2027-04-30"> <owner>jackshira@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -594,7 +594,7 @@ </histogram> <histogram name="Nearby.Connections.WifiDirect.CreateWifiDirectGroup.Error" - enum="NearbyConnectionsWifiDirectResult" expires_after="2026-04-30"> + enum="NearbyConnectionsWifiDirectResult" expires_after="2027-04-30"> <owner>jackshira@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -605,7 +605,7 @@ </histogram> <histogram name="Nearby.Connections.WifiDirect.CreateWifiDirectGroup.Result" - enum="BooleanSuccess" expires_after="2026-04-30"> + enum="BooleanSuccess" expires_after="2027-04-30"> <owner>jackshira@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -615,7 +615,7 @@ </histogram> <histogram name="Nearby.Connections.WifiDirect.IsP2pSupported" enum="Boolean" - expires_after="2026-04-30"> + expires_after="2027-04-30"> <owner>jackshira@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -627,7 +627,7 @@ </histogram> <histogram name="Nearby.Connections.WifiDirect.ListenForService.Error" - enum="NearbyConnectionsWifiDirectServiceError" expires_after="2026-04-30"> + enum="NearbyConnectionsWifiDirectServiceError" expires_after="2027-04-30"> <owner>jackshira@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -638,7 +638,7 @@ </histogram> <histogram name="Nearby.Connections.WifiDirect.ListenForService.Result" - enum="BooleanSuccess" expires_after="2026-04-30"> + enum="BooleanSuccess" expires_after="2027-04-30"> <owner>jackshira@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -649,7 +649,7 @@ </histogram> <histogram name="Nearby.Connections.WifiDirect.ServerSocket.Accept.Error" - enum="NearbyConnectionsWifiDirectSocketError" expires_after="2026-04-30"> + enum="NearbyConnectionsWifiDirectSocketError" expires_after="2027-04-30"> <owner>jackshira@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -662,7 +662,7 @@ </histogram> <histogram name="Nearby.Connections.WifiDirect.ServerSocket.Accept.Result" - enum="BooleanSuccess" expires_after="2026-04-30"> + enum="BooleanSuccess" expires_after="2027-04-30"> <owner>jackshira@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -677,7 +677,7 @@ </histogram> <histogram name="Nearby.Connections.WifiDirect.Socket.Read.Result" - enum="BooleanSuccess" expires_after="2026-04-30"> + enum="BooleanSuccess" expires_after="2027-04-30"> <owner>jackshira@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -688,7 +688,7 @@ </histogram> <histogram name="Nearby.Connections.WifiDirect.Socket.Write.Result" - enum="BooleanSuccess" expires_after="2026-04-30"> + enum="BooleanSuccess" expires_after="2027-04-30"> <owner>jackshira@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -699,7 +699,7 @@ </histogram> <histogram name="Nearby.Connections.WifiLan.ConnectResult" - enum="NearbyConnectionsWifiLanConnectResult" expires_after="2026-04-30"> + enum="NearbyConnectionsWifiLanConnectResult" expires_after="2027-04-30"> <owner>hansenmichael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -712,7 +712,7 @@ </histogram> <histogram name="Nearby.Connections.WifiLan.ListenResult" - enum="NearbyConnectionsWifiLanListenResult" expires_after="2026-04-30"> + enum="NearbyConnectionsWifiLanListenResult" expires_after="2027-04-30"> <owner>hansenmichael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -725,7 +725,7 @@ </histogram> <histogram name="Nearby.Connections.WifiLan.Socket.AcceptResult" - enum="NetErrorCodes" expires_after="2026-04-30"> + enum="NetErrorCodes" expires_after="2027-04-30"> <owner>hansenmichael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -739,7 +739,7 @@ </histogram> <histogram name="Nearby.Connections.WifiLan.TimeToConnect" units="ms" - expires_after="2026-04-30"> + expires_after="2027-04-30"> <owner>hansenmichael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -750,7 +750,7 @@ </histogram> <histogram name="Nearby.Connections.{Medium}.Socket.{Operation}.Result" - enum="BooleanSuccess" expires_after="2026-09-06"> + enum="BooleanSuccess" expires_after="2027-04-30"> <owner>hansenmichael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1282,7 +1282,7 @@ <histogram name="Nearby.Share.BackgroundScanning.DeviceNearbySharing.Notification.Flow" enum="NearbyShareBackgroundScanningDeviceNearbySharingNotificationFlowEvent" - expires_after="2026-04-30"> + expires_after="2027-04-30"> <owner>hansenmichael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1296,7 +1296,7 @@ <histogram name="Nearby.Share.BackgroundScanning.DeviceNearbySharing.Notification.TimeToAction" - units="ms" expires_after="2026-04-30"> + units="ms" expires_after="2027-04-30"> <owner>hansenmichael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1308,7 +1308,7 @@ <histogram name="Nearby.Share.BackgroundScanning.DevicesDetected" enum="NearbyShareBackgroundScanningDevicesDetectedEvent" - expires_after="2026-04-30"> + expires_after="2027-04-30"> <owner>hansenmichael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1322,7 +1322,7 @@ </histogram> <histogram name="Nearby.Share.BackgroundScanning.DevicesDetected.Duration" - units="ms" expires_after="2026-04-30"> + units="ms" expires_after="2027-04-30"> <owner>hansenmichael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1333,7 +1333,7 @@ </histogram> <histogram name="Nearby.Share.BackgroundScanning.SessionStarted" - enum="BooleanSuccess" expires_after="2026-04-30"> + enum="BooleanSuccess" expires_after="2027-04-30"> <owner>hansenmichael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1346,7 +1346,7 @@ <histogram name="Nearby.Share.BackgroundScanning.Setup.Notification.Flow" enum="NearbyShareBackgroundScanningSetupNotificationFlowEvent" - expires_after="2026-04-30"> + expires_after="2027-04-30"> <owner>hansenmichael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1360,7 +1360,7 @@ <histogram name="Nearby.Share.BackgroundScanning.Setup.Notification.TimeToAction" - units="ms" expires_after="2026-04-30"> + units="ms" expires_after="2027-04-30"> <owner>hansenmichael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1372,7 +1372,7 @@ <histogram name="Nearby.Share.Certificates.Manager.BluetoothMacAddressPresentForPrivateCertificateCreation" - enum="BooleanPresent" expires_after="2026-09-06"> + enum="BooleanPresent" expires_after="2027-04-30"> <owner>pushi@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1387,7 +1387,7 @@ <histogram name="Nearby.Share.Certificates.Manager.DownloadPublicCertificatesCount" - units="certificates" expires_after="2026-09-06"> + units="certificates" expires_after="2027-04-30"> <owner>crisrael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1399,7 +1399,7 @@ <histogram name="Nearby.Share.Certificates.Manager.DownloadPublicCertificatesFailuePageCount" - units="pages" expires_after="2026-04-30"> + units="pages" expires_after="2027-04-30"> <owner>crisrael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1411,7 +1411,7 @@ <histogram name="Nearby.Share.Certificates.Manager.DownloadPublicCertificatesHttpResult" - enum="NearbyHttpResult" expires_after="2026-04-30"> + enum="NearbyHttpResult" expires_after="2027-04-30"> <owner>crisrael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1424,7 +1424,7 @@ <histogram name="Nearby.Share.Certificates.Manager.DownloadPublicCertificatesSuccessPageCount" - units="pages" expires_after="2026-04-30"> + units="pages" expires_after="2027-04-30"> <owner>crisrael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1435,7 +1435,7 @@ <histogram name="Nearby.Share.Certificates.Manager.DownloadPublicCertificatesSuccessRate" - enum="BooleanSuccess" expires_after="2026-09-06"> + enum="BooleanSuccess" expires_after="2027-04-30"> <owner>crisrael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1447,7 +1447,7 @@ <histogram name="Nearby.Share.Certificates.Manager.GetDecryptedPublicCertificateResult" enum="NearbyShareCertificateManagerGetDecryptedPublicCertificateResult" - expires_after="2026-09-06"> + expires_after="2027-04-30"> <owner>crisrael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1457,7 +1457,7 @@ </histogram> <histogram name="Nearby.Share.Certificates.Storage.InitializeAttemptCount" - units="attempts" expires_after="2026-04-30"> + units="attempts" expires_after="2027-04-30"> <owner>crisrael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1468,7 +1468,7 @@ <histogram name="Nearby.Share.Certificates.Storage.InitializeAttemptResult" enum="NearbyShareCertificateStorageInitializationResult" - expires_after="2026-04-30"> + expires_after="2027-04-30"> <owner>crisrael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1479,7 +1479,7 @@ </histogram> <histogram name="Nearby.Share.Certificates.Storage.InitializeSuccessDuration" - units="ms" expires_after="2026-04-30"> + units="ms" expires_after="2027-04-30"> <owner>crisrael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1490,7 +1490,7 @@ </histogram> <histogram name="Nearby.Share.Certificates.Storage.{Operation}SuccessRate" - enum="BooleanSuccess" expires_after="2026-09-06"> + enum="BooleanSuccess" expires_after="2027-04-30"> <owner>crisrael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1505,7 +1505,7 @@ </histogram> <histogram name="Nearby.Share.Connection.EstablishOutgoingConnection.Success" - enum="BooleanSuccess" expires_after="2026-04-30"> + enum="BooleanSuccess" expires_after="2027-04-30"> <owner>pushi@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1519,7 +1519,7 @@ </histogram> <histogram name="Nearby.Share.Connection.EstablishOutgoingConnectionStatus" - enum="NearbyShareFinalStatus" expires_after="2026-04-30"> + enum="NearbyShareFinalStatus" expires_after="2027-04-30"> <owner>crisrael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1532,7 +1532,7 @@ </histogram> <histogram name="Nearby.Share.Connection.InitialMedium" - enum="NearbyShareUpgradedMedium" expires_after="2026-04-30"> + enum="NearbyShareUpgradedMedium" expires_after="2027-04-30"> <owner>dclasson@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1546,7 +1546,7 @@ </histogram> <histogram name="Nearby.Share.Connection.TimeToEstablishOutgoingConnection" - units="ms" expires_after="2026-04-30"> + units="ms" expires_after="2027-04-30"> <owner>pushi@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1560,7 +1560,7 @@ </histogram> <histogram name="Nearby.Share.Contacts.CanGetProfileUserName" - enum="BooleanSuccess" expires_after="2026-04-30"> + enum="BooleanSuccess" expires_after="2027-04-30"> <owner>crisrael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1575,7 +1575,7 @@ </histogram> <histogram name="Nearby.Share.Contacts.DownloadPageCount.{Result}" - units="pages" expires_after="2026-04-30"> + units="pages" expires_after="2027-04-30"> <owner>pushi@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1595,7 +1595,7 @@ </histogram> <histogram name="Nearby.Share.Contacts.DownloadResult" enum="BooleanSuccess" - expires_after="2026-09-06"> + expires_after="2027-04-30"> <owner>crisrael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1609,7 +1609,7 @@ </histogram> <histogram name="Nearby.Share.Contacts.HttpResult" enum="NearbyHttpResult" - expires_after="2026-09-06"> + expires_after="2027-04-30"> <owner>pushi@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1623,7 +1623,7 @@ </histogram> <histogram name="Nearby.Share.Contacts.NumContacts.{Type}" units="contacts" - expires_after="2026-09-06"> + expires_after="2027-04-30"> <owner>crisrael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1646,7 +1646,7 @@ </histogram> <histogram name="Nearby.Share.Contacts.Percent{Type}" units="%" - expires_after="2026-04-30"> + expires_after="2027-04-30"> <owner>pushi@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1669,7 +1669,7 @@ </histogram> <histogram name="Nearby.Share.Contacts.TimeToDownload.{Result}" units="ms" - expires_after="2026-04-30"> + expires_after="2027-04-30"> <owner>crisrael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1687,7 +1687,7 @@ </histogram> <histogram name="Nearby.Share.DeviceType{Direction}" - enum="NearbyShareDeviceType" expires_after="2026-04-30"> + enum="NearbyShareDeviceType" expires_after="2027-04-30"> <owner>pushi@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1703,7 +1703,7 @@ </histogram> <histogram name="Nearby.Share.Discovery.Delay.FromStartDiscoveryTo{EndState}" - units="ms" expires_after="2026-04-30"> + units="ms" expires_after="2027-04-30"> <owner>crisrael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1718,7 +1718,7 @@ </histogram> <histogram name="Nearby.Share.Discovery.FurthestDiscoveryProgress" - enum="NearbyShareDiscoveryProgress" expires_after="2026-04-30"> + enum="NearbyShareDiscoveryProgress" expires_after="2027-04-30"> <owner>pushi@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1728,7 +1728,7 @@ </histogram> <histogram name="Nearby.Share.Discovery.LookUpSelectedShareTarget" - enum="BooleanFound" expires_after="2026-04-30"> + enum="BooleanFound" expires_after="2027-04-30"> <owner>crisrael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1740,7 +1740,7 @@ </histogram> <histogram name="Nearby.Share.Discovery.NumShareTargets.{Variation}" - units="share targets" expires_after="2026-09-06"> + units="share targets" expires_after="2027-04-30"> <owner>pushi@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1755,7 +1755,7 @@ </histogram> <histogram name="Nearby.Share.Discovery.{Operation}" - enum="NearbyShareServiceStatusCode" expires_after="2026-04-30"> + enum="NearbyShareServiceStatusCode" expires_after="2027-04-30"> <owner>crisrael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1774,7 +1774,7 @@ </histogram> <histogram name="Nearby.Share.Enabled" enum="NearbyShareEnabledState" - expires_after="2026-09-06"> + expires_after="2027-04-30"> <owner>pushi@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1787,7 +1787,7 @@ </histogram> <histogram name="Nearby.Share.EnabledStateChanged" enum="BooleanEnabled" - expires_after="2026-07-05"> + expires_after="2027-04-30"> <owner>crisrael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1799,7 +1799,7 @@ </histogram> <histogram name="Nearby.Share.Error" enum="NearbyShareError" - expires_after="2026-09-06"> + expires_after="2027-04-30"> <owner>crisrael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1809,7 +1809,7 @@ </histogram> <histogram name="Nearby.Share.IsKnownContact" enum="BooleanKnown" - expires_after="2026-04-30"> + expires_after="2027-04-30"> <owner>pushi@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1820,7 +1820,7 @@ </histogram> <histogram name="Nearby.Share.IsSelfShare" enum="BooleanSuccess" - expires_after="2026-09-06"> + expires_after="2027-04-30"> <owner>brandosocarras@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1831,7 +1831,7 @@ </histogram> <histogram name="Nearby.Share.LocalDeviceData.DeviceDataUpdater.HttpResult" - enum="NearbyHttpResult" expires_after="2026-09-06"> + enum="NearbyHttpResult" expires_after="2027-04-30"> <owner>crisrael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1842,7 +1842,7 @@ </histogram> <histogram name="Nearby.Share.Medium.ChangedToMedium" - enum="NearbyConnectionsMedium" expires_after="2026-04-30"> + enum="NearbyConnectionsMedium" expires_after="2027-04-30"> <owner>crisrael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1853,7 +1853,7 @@ </histogram> <histogram name="Nearby.Share.Medium.InitiateBandwidthUpgradeResult" - enum="BooleanSuccess" expires_after="2026-04-30"> + enum="BooleanSuccess" expires_after="2027-04-30"> <owner>pushi@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1867,7 +1867,7 @@ </histogram> <histogram name="Nearby.Share.Medium.RequestedBandwidthUpgradeResult" - enum="BooleanUpgraded" expires_after="2026-04-30"> + enum="BooleanUpgraded" expires_after="2027-04-30"> <owner>crisrael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1878,7 +1878,7 @@ </histogram> <histogram name="Nearby.Share.Onboarding.Duration" units="ms" - expires_after="2026-04-30"> + expires_after="2027-04-30"> <owner>pushi@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1888,7 +1888,7 @@ </histogram> <histogram name="Nearby.Share.Onboarding.EntryPoint" - enum="NearbyShareOnboardingEntryPoint" expires_after="2026-09-06"> + enum="NearbyShareOnboardingEntryPoint" expires_after="2027-04-30"> <owner>pushi@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1900,7 +1900,7 @@ </histogram> <histogram name="Nearby.Share.Onboarding.FlowEvent" - enum="NearbyShareOnboardingFlowEvent" expires_after="2026-04-30"> + enum="NearbyShareOnboardingFlowEvent" expires_after="2027-04-30"> <owner>pushi@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1910,7 +1910,7 @@ </histogram> <histogram name="Nearby.Share.Onboarding.Result" - enum="NearbyShareOnboardingFinalState" expires_after="2026-09-06"> + enum="NearbyShareOnboardingFinalState" expires_after="2027-04-30"> <owner>pushi@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1923,7 +1923,7 @@ </histogram> <histogram name="Nearby.Share.Onboarding.{EntryPoint}.Result" - enum="NearbyShareOnboardingFinalState" expires_after="2026-04-30"> + enum="NearbyShareOnboardingFinalState" expires_after="2027-04-30"> <owner>brandosocarras@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1941,7 +1941,7 @@ </histogram> <histogram name="Nearby.Share.PairedKeyVerificationError" - enum="NearbySharePairedKeyVerificationError" expires_after="2026-04-30"> + enum="NearbySharePairedKeyVerificationError" expires_after="2027-04-30"> <owner>crisrael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1951,7 +1951,7 @@ </histogram> <histogram name="Nearby.Share.Payload.AttachmentType{Variation}" - enum="NearbyShareAttachmentType" expires_after="2026-04-30"> + enum="NearbyShareAttachmentType" expires_after="2027-04-30"> <owner>pushi@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1971,7 +1971,7 @@ </histogram> <histogram name="Nearby.Share.Payload.FinalStatus{UpgradedMedium}" - enum="NearbyShareFinalStatus" expires_after="2026-04-30"> + enum="NearbyShareFinalStatus" expires_after="2027-04-30"> <owner>crisrael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -1990,7 +1990,7 @@ </histogram> <histogram name="Nearby.Share.Payload.Medium" enum="NearbyShareUpgradedMedium" - expires_after="2026-04-30"> + expires_after="2027-04-30"> <owner>pushi@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -2002,7 +2002,7 @@ <histogram name="Nearby.Share.Payload.Medium.Over5MbTransferred{ShareTargetType}" - enum="NearbyShareUpgradedMedium" expires_after="2026-09-06"> + enum="NearbyShareUpgradedMedium" expires_after="2027-04-30"> <owner>crisrael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -2021,7 +2021,7 @@ </histogram> <histogram name="Nearby.Share.Payload.NumAttachments{Type}" units="attachments" - expires_after="2026-04-30"> + expires_after="2027-04-30"> <owner>pushi@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -2037,7 +2037,7 @@ </histogram> <histogram name="Nearby.Share.Payload.TotalSize{Variation}" units="KB" - expires_after="2026-09-06"> + expires_after="2027-04-30"> <owner>crisrael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -2070,7 +2070,7 @@ </histogram> <histogram name="Nearby.Share.Payload.TransferRate{Variation}" units="KB/s" - expires_after="2026-09-06"> + expires_after="2027-04-30"> <owner>pushi@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -2104,7 +2104,7 @@ <histogram name="Nearby.Share.Payload.{ContactStatus}.AttachmentType{Variation}" - enum="NearbyShareAttachmentType" expires_after="2026-04-30"> + enum="NearbyShareAttachmentType" expires_after="2027-04-30"> <owner>brandosocarras@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -2130,7 +2130,7 @@ </histogram> <histogram name="Nearby.Share.Payload{Operation}.Success{FilePath}" - enum="BooleanSuccess" expires_after="2026-04-30"> + enum="BooleanSuccess" expires_after="2027-04-30"> <owner>alanding@google.com</owner> <owner>cros-sharesheet@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> @@ -2153,7 +2153,7 @@ </histogram> <histogram name="Nearby.Share.StartAdvertising.Result.FailureReason{Mode}" - enum="NearbyShareStartAdvertisingFailureReason" expires_after="2026-09-06"> + enum="NearbyShareStartAdvertisingFailureReason" expires_after="2027-04-30"> <owner>crisrael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -2167,7 +2167,7 @@ </histogram> <histogram name="Nearby.Share.StartAdvertising.Result{Mode}" - enum="BooleanSuccess" expires_after="2026-09-06"> + enum="BooleanSuccess" expires_after="2027-04-30"> <owner>pushi@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -2181,7 +2181,7 @@ </histogram> <histogram name="Nearby.Share.TimeFromInitiateSendToRemoteDeviceNotification" - units="ms" expires_after="2026-04-30"> + units="ms" expires_after="2027-04-30"> <owner>crisrael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -2196,7 +2196,7 @@ </histogram> <histogram name="Nearby.Share.TimeFromLocalAcceptToTransferStart" units="ms" - expires_after="2026-04-30"> + expires_after="2027-04-30"> <owner>pushi@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -2208,7 +2208,7 @@ </histogram> <histogram name="Nearby.Share.Transfer.FinalStatus{Variation}" - enum="NearbyShareTransferFinalStatus" expires_after="2026-09-06"> + enum="NearbyShareTransferFinalStatus" expires_after="2027-04-30"> <owner>crisrael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -2235,7 +2235,7 @@ </histogram> <histogram name="Nearby.Share.Transfer.Success" enum="BooleanSuccess" - expires_after="2026-04-30"> + expires_after="2027-04-30"> <owner>pushi@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -2247,7 +2247,7 @@ <histogram name="Nearby.Share.Transfer.Success.Receive.{ShareTargetType}.SelfShare.{DeviceState}" - enum="BooleanSuccess" expires_after="2026-04-30"> + enum="BooleanSuccess" expires_after="2027-04-30"> <owner>brandosocarras@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -2271,7 +2271,7 @@ <histogram name="Nearby.Share.Transfer.Success.{Direction}.{ShareTargetType}.{ContactStatus}" - enum="BooleanSuccess" expires_after="2026-07-05"> + enum="BooleanSuccess" expires_after="2027-04-30"> <owner>crisrael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -2299,7 +2299,7 @@ <histogram name="Nearby.Share.TransferDuration.Receiver.AcceptedTransferToAllFilesReceived" - units="ms" expires_after="2026-04-30"> + units="ms" expires_after="2027-04-30"> <owner>jackshira@google.com</owner> <owner>dclasson@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> @@ -2311,7 +2311,7 @@ <histogram name="Nearby.Share.TransferDuration.Receiver.BandwidthUpgradeToAllFilesReceived2{TransferMedium}" - units="ms" expires_after="2026-04-30"> + units="ms" expires_after="2027-04-30"> <owner>jackshira@google.com</owner> <owner>dclasson@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> @@ -2324,7 +2324,7 @@ <histogram name="Nearby.Share.TransferDuration.Receiver.EndpointDecodedToReceivedIntroductionFrame" - units="ms" expires_after="2026-04-30"> + units="ms" expires_after="2027-04-30"> <owner>jackshira@google.com</owner> <owner>dclasson@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> @@ -2336,7 +2336,7 @@ <histogram name="Nearby.Share.TransferDuration.Receiver.HighVisibilityEndpointDecodedToBandwidthUpgrade2{TransferMedium}" - units="ms" expires_after="2026-04-30"> + units="ms" expires_after="2027-04-30"> <owner>jackshira@google.com</owner> <owner>dclasson@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> @@ -2351,7 +2351,7 @@ <histogram name="Nearby.Share.TransferDuration.Receiver.NonHighVisibilityPairedKeyCompleteToBandwidthUpgrade2{TransferMedium}" - units="ms" expires_after="2026-04-30"> + units="ms" expires_after="2027-04-30"> <owner>jackshira@google.com</owner> <owner>dclasson@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> @@ -2367,7 +2367,7 @@ <histogram name="Nearby.Share.TransferDuration.Receiver.ReceivedIntroductionFrameToAllFilesReceived" - units="ms" expires_after="2026-04-30"> + units="ms" expires_after="2027-04-30"> <owner>jackshira@google.com</owner> <owner>dclasson@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> @@ -2380,7 +2380,7 @@ <histogram name="Nearby.Share.TransferDuration.Sender.BandwidthUpgradeToAllFilesSent2{TransferMedium}" - units="ms" expires_after="2026-04-30"> + units="ms" expires_after="2027-04-30"> <owner>jackshira@google.com</owner> <owner>dclasson@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> @@ -2393,7 +2393,7 @@ <histogram name="Nearby.Share.TransferDuration.Sender.ConnectionEstablishedToBandwidthUpgrade2{TransferMedium}" - units="ms" expires_after="2026-04-30"> + units="ms" expires_after="2027-04-30"> <owner>jackshira@google.com</owner> <owner>dclasson@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> @@ -2406,7 +2406,7 @@ <histogram name="Nearby.Share.TransferDuration.Sender.DiscoveredToConnectionEstablished" - units="ms" expires_after="2026-04-30"> + units="ms" expires_after="2027-04-30"> <owner>jackshira@google.com</owner> <owner>dclasson@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> @@ -2418,7 +2418,7 @@ </histogram> <histogram name="Nearby.Share.TransferDuration.Sender.InitiatedToAllFilesSent" - units="ms" expires_after="2026-04-30"> + units="ms" expires_after="2027-04-30"> <owner>jackshira@google.com</owner> <owner>dclasson@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> @@ -2431,7 +2431,7 @@ <histogram name="Nearby.Share.TransferDuration.Sender.InitiatedToSentIntroductionFrame" - units="ms" expires_after="2026-04-30"> + units="ms" expires_after="2027-04-30"> <owner>jackshira@google.com</owner> <owner>dclasson@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> @@ -2443,7 +2443,7 @@ <histogram name="Nearby.Share.TransferDuration.Sender.StartSendFilesToAllFilesSent" - units="ms" expires_after="2026-04-30"> + units="ms" expires_after="2027-04-30"> <owner>jackshira@google.com</owner> <owner>dclasson@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> @@ -2454,7 +2454,7 @@ </histogram> <histogram name="Nearby.Share.VisibilityChoice" enum="NearbyShareVisibility" - expires_after="2026-09-06"> + expires_after="2027-04-30"> <owner>pushi@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> @@ -2465,7 +2465,7 @@ </histogram> <histogram name="Nearby.Share.WifiNetworkConfiguration.Result" - enum="BooleanSuccess" expires_after="2026-04-30"> + enum="BooleanSuccess" expires_after="2027-04-30"> <owner>crisrael@google.com</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/net/histograms.xml b/tools/metrics/histograms/metadata/net/histograms.xml index f3a8a83..8164235 100644 --- a/tools/metrics/histograms/metadata/net/histograms.xml +++ b/tools/metrics/histograms/metadata/net/histograms.xml
@@ -4344,6 +4344,17 @@ </summary> </histogram> +<histogram name="Net.NetworkTransaction.TooManyRetriesOnConnectionErrors" + enum="Boolean" expires_after="2026-09-01"> + <owner>hayato@chromium.org</owner> + <owner>src/net/OWNERS</owner> + <summary> + Recorded when an HTTP network transaction has reached the maximum number of + retries for connection errors. Recorded every time when the retry reached + kMaxRetryAttemptsOnConnectionErrors (50). + </summary> +</histogram> + <histogram name="Net.NetworkTransaction.{Protocol}StreamCreationTime2.{NewOrExisting}" units="ms" expires_after="2026-06-28">
diff --git a/tools/metrics/histograms/metadata/security/histograms.xml b/tools/metrics/histograms/metadata/security/histograms.xml index 6d7221f..9be0ba30 100644 --- a/tools/metrics/histograms/metadata/security/histograms.xml +++ b/tools/metrics/histograms/metadata/security/histograms.xml
@@ -815,18 +815,6 @@ </token> </histogram> -<histogram name="Security.SafetyTips.SafetyTipIgnoredPageLoad" - enum="SafetyTipStatus" expires_after="2024-03-17"> - <owner>jdeblasio@chromium.org</owner> - <owner>src/chrome/browser/lookalikes/OWNERS</owner> - <summary> - Records the Safety Tip status of a page after navigation commit for a page - where the Safety Tip has previously been ignored. - - Note: This histogram was expired from 2021-12-26 until 2023-01-19. - </summary> -</histogram> - <histogram name="Security.SafetyTips.SafetyTipShown" enum="SafetyTipStatus" expires_after="2024-05-26"> <owner>jdeblasio@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/sql/histograms.xml b/tools/metrics/histograms/metadata/sql/histograms.xml index 5842fcc..3beb64b 100644 --- a/tools/metrics/histograms/metadata/sql/histograms.xml +++ b/tools/metrics/histograms/metadata/sql/histograms.xml
@@ -100,6 +100,20 @@ <variant name="Web" summary="Web"/> </variants> +<histogram name="Sql.Database.DatabaseOpenTime.{DatabaseTag}" + units="microseconds" expires_after="2026-07-26"> + <owner>olivierli@chromium.org</owner> + <owner>etienneb@chromium.org</owner> + <summary> + Reports the time spent in Database::Open, in microseconds, when opening the + {DatabaseTag} database. Reported for failure and success without + distinction. + + Only reported for clients with high-resolution clocks. + </summary> + <token key="DatabaseTag" variants="DatabaseTag"/> +</histogram> + <histogram name="Sql.Database.Open.FailureReason.{DatabaseTag}" enum="OpenDatabaseFailedReason" expires_after="2026-08-09"> <owner>anthonyvd@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/ui/histograms.xml b/tools/metrics/histograms/metadata/ui/histograms.xml index ddfd815..2968396 100644 --- a/tools/metrics/histograms/metadata/ui/histograms.xml +++ b/tools/metrics/histograms/metadata/ui/histograms.xml
@@ -419,6 +419,33 @@ </histogram> <histogram + name="InitialWebUI.NewWindow{CreationSource}.BrowserWindow.ShowRequestedToFirstPaint" + units="ms" expires_after="2026-09-17"> + <owner>mych@chromium.org</owner> + <owner>chrome-webium-product-eng@google.com</owner> + <summary> + Records the duration from the initial show/activation request of a new + browser window to its first paint. {CreationSource} + + This metric is used to measure the impact of window show deferral. It is + recorded only once per window lifecycle. If multiple windows are shown + during startup, e.g. due to session restore, the first window is measured in + "InitialWebUI.Startup" and not in this histogram. + + This is only recorded for desktop platforms when the InitialWebUIMetrics is + enabled. + </summary> + <token key="CreationSource"> + <variant name=".AllSources" summary="Aggregated across all sources"/> + <variant name=".BrowserInitiated" + summary="Triggered by browser action, e.g. shortcut or menu"/> + <variant name=".DragToNewWindow" + summary="Triggered by dragging a tab to a new window"/> + <variant name=".SessionRestore" summary="Triggered by session restore"/> + </token> +</histogram> + +<histogram name="InitialWebUI.NewWindow{CreationSource}.BrowserWindowToReloadButton.FirstPaintGap" units="ms" expires_after="2026-09-13"> <owner>mych@chromium.org</owner> @@ -621,6 +648,44 @@ </histogram> <histogram + name="InitialWebUI.Startup{Scenario}.BrowserWindow.ShowRequestedToFirstPaint{StartupTemperature}" + units="ms" expires_after="2026-09-06"> + <owner>mych@chromium.org</owner> + <owner>chrome-webium-product-eng@google.com</owner> + <summary> + Records the duration from the initial show/activation request of the first + browser window during {Scenario} startup to its first + paint{StartupTemperature}. + + This metric is used to measure the impact of window show deferral. It is + recorded only once per browser process. If multiple windows are shown during + startup, e.g. due to session restore, only the first window is measured, and + all the others are measured in the "InitialWebUI.NewWindow" + histogram. + + This is only recorded for desktop platforms when the InitialWebUIMetrics + feature is enabled. + </summary> + <token key="Scenario"> + <variant name="" summary="standard"/> + <variant name=".FirstRun" summary="first run"/> + <variant name=".SessionRestore" + summary="session restored (without showing the Profile Picker)"/> + </token> + <token key="StartupTemperature"> + <variant name="" summary=""/> + <variant name=".Temperature.ColdStartup" + summary=", where startup was cold (mostly hard faults). Only + available on Windows."/> + <variant name=".Temperature.Other" + summary=", where startup temperature was undetermined"/> + <variant name=".Temperature.WarmStartup" + summary=", where startup was warm (almost no hard faults). Only + available on Windows."/> + </token> +</histogram> + +<histogram name="InitialWebUI.Startup{Scenario}.BrowserWindowToReloadButton.FirstPaintGap{StartupTemperature}" units="ms" expires_after="2026-09-13"> <owner>mych@chromium.org</owner>
diff --git a/ui/accessibility/ax_node.h b/ui/accessibility/ax_node.h index 9acc67d..21651f8 100644 --- a/ui/accessibility/ax_node.h +++ b/ui/accessibility/ax_node.h
@@ -92,9 +92,9 @@ protected: raw_ptr<const NodeType> parent_; - raw_ptr<NodeType, DanglingUntriaged> child_; - raw_ptr<NodeType, DanglingUntriaged> first_child_{nullptr}; - raw_ptr<NodeType, DanglingUntriaged> last_child_{nullptr}; + raw_ptr<NodeType> child_; + raw_ptr<NodeType> first_child_{nullptr}; + raw_ptr<NodeType> last_child_{nullptr}; }; // The constructor requires a parent, id, and index in parent, but
diff --git a/ui/android/java/src/org/chromium/ui/xr/OWNERS b/ui/android/java/src/org/chromium/ui/xr/OWNERS index cf9959a3..e006c64 100644 --- a/ui/android/java/src/org/chromium/ui/xr/OWNERS +++ b/ui/android/java/src/org/chromium/ui/xr/OWNERS
@@ -1,2 +1 @@ -gurmeetk@google.com -desiatyrikov@google.com +file://chrome/android/modules/xr/OWNERS \ No newline at end of file
diff --git a/ui/aura/window.cc b/ui/aura/window.cc index 6b23994..c1db2c9 100644 --- a/ui/aura/window.cc +++ b/ui/aura/window.cc
@@ -1567,14 +1567,22 @@ observer.OnWindowBoundsChanged(this, old_bounds, bounds_, reason); // Trigger the changed notification for each of the bounds "properties". - if (old_bounds.x() != bounds_.x()) - TriggerChangedCallback(UNSAFE_TODO(&bounds_ + kBoundsX)); - if (old_bounds.y() != bounds_.y()) - TriggerChangedCallback(UNSAFE_TODO(&bounds_ + kBoundsY)); - if (old_bounds.width() != bounds_.width()) - TriggerChangedCallback(UNSAFE_TODO(&bounds_ + kBoundsWidth)); - if (old_bounds.height() != bounds_.height()) - TriggerChangedCallback(UNSAFE_TODO(&bounds_ + kBoundsHeight)); + if (old_bounds.x() != bounds_.x()) { + TriggerChangedCallback( + ui::metadata::MakeUniquePropertyKey(&bounds_, kBoundsX)); + } + if (old_bounds.y() != bounds_.y()) { + TriggerChangedCallback( + ui::metadata::MakeUniquePropertyKey(&bounds_, kBoundsY)); + } + if (old_bounds.width() != bounds_.width()) { + TriggerChangedCallback( + ui::metadata::MakeUniquePropertyKey(&bounds_, kBoundsWidth)); + } + if (old_bounds.height() != bounds_.height()) { + TriggerChangedCallback( + ui::metadata::MakeUniquePropertyKey(&bounds_, kBoundsHeight)); + } } void Window::OnLayerOpacityChanged(ui::PropertyChangeReason reason) {
diff --git a/ui/file_manager/file_manager/widgets/xf_breadcrumb.ts b/ui/file_manager/file_manager/widgets/xf_breadcrumb.ts index 98dbf1f..f9f3581 100644 --- a/ui/file_manager/file_manager/widgets/xf_breadcrumb.ts +++ b/ui/file_manager/file_manager/widgets/xf_breadcrumb.ts
@@ -42,6 +42,8 @@ @query('button[elider]') private $eliderButton_?: HTMLButtonElement; @query('cr-action-menu') private $actionMenu_?: CrActionMenuElement; + // TODO(crbug.com/493624186): Fix members asserted as non-null . + /* eslint-disable-next-line no-restricted-syntax */ @query('#first') private $firstButton_!: HTMLButtonElement; /** Indicates if the elider menu is open or not. */
diff --git a/ui/file_manager/file_manager/widgets/xf_bulk_pinning_dialog.ts b/ui/file_manager/file_manager/widgets/xf_bulk_pinning_dialog.ts index 412e7a8..6519b7a 100644 --- a/ui/file_manager/file_manager/widgets/xf_bulk_pinning_dialog.ts +++ b/ui/file_manager/file_manager/widgets/xf_bulk_pinning_dialog.ts
@@ -46,6 +46,8 @@ */ @customElement('xf-bulk-pinning-dialog') export class XfBulkPinningDialog extends XfBase { + // TODO(crbug.com/493624186): Fix members asserted as non-null . + /* eslint-disable no-restricted-syntax */ @query('cr-dialog') private $dialog_!: CrDialogElement; @query('#continue-button') private $button_!: CrButtonElement; @query('#offline-footer') private $offlineFooter_!: HTMLElement; @@ -56,6 +58,7 @@ private $notEnoughSpaceFooter_!: HTMLElement; @query('#ready-footer') private $readyFooter_!: HTMLElement; @query('#listing-files-text') private $listingFilesText_!: HTMLElement; + /* eslint-enable no-restricted-syntax */ private store_ = getStore(); private stage_ = '';
diff --git a/ui/file_manager/file_manager/widgets/xf_tree.ts b/ui/file_manager/file_manager/widgets/xf_tree.ts index 488a4760..f639202 100644 --- a/ui/file_manager/file_manager/widgets/xf_tree.ts +++ b/ui/file_manager/file_manager/widgets/xf_tree.ts
@@ -61,6 +61,8 @@ } /** The default unnamed slot to let consumer pass children tree items. */ + // TODO(crbug.com/493624186): Fix members asserted as non-null . + /* eslint-disable-next-line no-restricted-syntax */ @query('slot') private $childrenSlot_!: HTMLSlotElement; /** The child tree items. */
diff --git a/ui/file_manager/file_manager/widgets/xf_tree_item.ts b/ui/file_manager/file_manager/widgets/xf_tree_item.ts index 1331aab..0d8c4601 100644 --- a/ui/file_manager/file_manager/widgets/xf_tree_item.ts +++ b/ui/file_manager/file_manager/widgets/xf_tree_item.ts
@@ -183,9 +183,12 @@ */ @state() private level_ = 1; + // TODO(crbug.com/493624186): Fix members asserted as non-null . + /* eslint-disable no-restricted-syntax */ @query('li') private $treeItem_!: HTMLLIElement; @query('.tree-row') private $treeRow_!: HTMLElement; @query('slot:not([name])') private $childrenSlot_!: HTMLSlotElement; + /* eslint-enable no-restricted-syntax */ /** The child tree items. */ private items_: XfTreeItem[] = [];
diff --git a/ui/gfx/blit.cc b/ui/gfx/blit.cc index 0237531..feb18ff 100644 --- a/ui/gfx/blit.cc +++ b/ui/gfx/blit.cc
@@ -7,8 +7,9 @@ #include <stddef.h> #include "base/check.h" -#include "base/compiler_specific.h" -#include "build/build_config.h" +#include "base/check_op.h" +#include "base/containers/auto_spanification_helper.h" +#include "base/containers/span.h" #include "skia/ext/platform_canvas.h" #include "third_party/skia/include/core/SkPixmap.h" #include "ui/gfx/geometry/point.h" @@ -70,29 +71,32 @@ // Compute the source pixels that will map to the dest_rect gfx::Rect src_rect = dest_rect - offset; - size_t row_bytes = dest_rect.width() * 4; + const size_t pixels_per_row = static_cast<size_t>(dest_rect.width()); + auto copy_row = [pixels_per_row](SkPixmap& pixmap, const gfx::Rect& src_rect, + const gfx::Rect& dest_rect, int y) { + base::span<uint32_t> dest = UNSAFE_SKPIXMAP_GET_WRITABLE_ADDR32( + pixmap, dest_rect.x(), dest_rect.y() + y) + .first(pixels_per_row); + base::span<const uint32_t> src = + UNSAFE_SKPIXMAP_GET_ADDR32(pixmap, src_rect.x(), src_rect.y() + y) + .first(pixels_per_row); + dest.copy_from(src); + }; if (offset.y() > 0) { // Data is moving down, copy from the bottom up. for (int y = dest_rect.height() - 1; y >= 0; y--) { - UNSAFE_TODO( - memcpy(pixmap.writable_addr32(dest_rect.x(), dest_rect.y() + y), - pixmap.addr32(src_rect.x(), src_rect.y() + y), row_bytes)); + copy_row(pixmap, src_rect, dest_rect, y); } } else if (offset.y() < 0) { // Data is moving up, copy from the top down. for (int y = 0; y < dest_rect.height(); y++) { - UNSAFE_TODO( - memcpy(pixmap.writable_addr32(dest_rect.x(), dest_rect.y() + y), - pixmap.addr32(src_rect.x(), src_rect.y() + y), row_bytes)); + copy_row(pixmap, src_rect, dest_rect, y); } } else if (offset.x() != 0) { // Horizontal-only scroll. We can do it in either top-to-bottom or bottom- - // to-top, but have to be careful about the order for copying each row. - // Fortunately, memmove already handles this for us. + // to-top, but `copy_from()` already handles overlapping spans. for (int y = 0; y < dest_rect.height(); y++) { - UNSAFE_TODO( - memmove(pixmap.writable_addr32(dest_rect.x(), dest_rect.y() + y), - pixmap.addr32(src_rect.x(), src_rect.y() + y), row_bytes)); + copy_row(pixmap, src_rect, dest_rect, y); } } }
diff --git a/ui/gfx/color_space.cc b/ui/gfx/color_space.cc index 3d87098..979f27d 100644 --- a/ui/gfx/color_space.cc +++ b/ui/gfx/color_space.cc
@@ -10,7 +10,11 @@ #include <sstream> #include "base/atomic_sequence_num.h" +#include "base/bit_cast.h" #include "base/compiler_specific.h" +#include "base/containers/span.h" +#include "base/containers/span_reader.h" +#include "base/containers/span_writer.h" #include "base/debug/crash_logging.h" #include "base/lazy_instance.h" #include "base/logging.h" @@ -32,18 +36,60 @@ namespace { -static bool FloatsEqualWithinTolerance(const float* a, - const float* b, - int n, - float tol) { - for (int i = 0; i < n; ++i) { - if (std::abs(UNSAFE_TODO(a[i]) - UNSAFE_TODO(b[i])) > tol) { - return false; +constexpr size_t kPrimaryMatrixElementCount = + sizeof(skcms_Matrix3x3) / sizeof(float); + +// These span conversions assume skcms_TransferFunction and skcms_Matrix3x3 are +// stored as tightly packed floats. +static_assert(sizeof(skcms_Matrix3x3) == + kPrimaryMatrixElementCount * sizeof(float)); + +bool MatricesEqualWithinTolerance(const skcms_Matrix3x3& lhs, + const skcms_Matrix3x3& rhs, + float tol) { + constexpr size_t kPrimaryMatrixRowCount = std::size(skcms_Matrix3x3{}.vals); + constexpr size_t kPrimaryMatrixColumnCount = + std::size(skcms_Matrix3x3{}.vals[0]); + // SAFETY: `skcms_Matrix3x3::vals` is a fixed-size `float[3][3]` array. + // `row` and `column` are both bounded by these compile-time dimensions, so + // each indexed access stays within the matrix storage. + for (size_t row = 0; row < kPrimaryMatrixRowCount; ++row) { + for (size_t column = 0; column < kPrimaryMatrixColumnCount; ++column) { + if (std::abs(UNSAFE_TODO(lhs.vals[row][column]) - + UNSAFE_TODO(rhs.vals[row][column])) > tol) { + return false; + } } } return true; } +void CopyMatrixToArray(const skcms_Matrix3x3& matrix, + base::span<float, kPrimaryMatrixElementCount> out) { + base::SpanWriter writer(out); + for (const base::span<const float, 3> row : matrix.vals) { + CHECK(writer.Write(row)); + } +} + +void CopyArrayToMatrix( + base::span<const float, kPrimaryMatrixElementCount> values, + skcms_Matrix3x3& matrix) { + base::SpanReader reader(values); + for (base::span<float, 3> row : matrix.vals) { + CHECK(reader.ReadCopy(row)); + } +} + +bool TransferFunctionsEqualWithinTolerance(const skcms_TransferFunction& lhs, + const skcms_TransferFunction& rhs, + float tol) { + return std::abs(lhs.a - rhs.a) <= tol && std::abs(lhs.b - rhs.b) <= tol && + std::abs(lhs.c - rhs.c) <= tol && std::abs(lhs.d - rhs.d) <= tol && + std::abs(lhs.e - rhs.e) <= tol && std::abs(lhs.f - rhs.f) <= tol && + std::abs(lhs.g - rhs.g) <= tol; +} + bool PrimaryIdContainsSRGB(ColorSpace::PrimaryID id) { DCHECK(id != ColorSpace::PrimaryID::INVALID && id != ColorSpace::PrimaryID::CUSTOM); @@ -192,14 +238,13 @@ for (PrimaryID id : kIDsToCheck) { skcms_Matrix3x3 matrix; GetPrimaryMatrix(id, &matrix); - if (FloatsEqualWithinTolerance(&to_XYZD50.vals[0][0], &matrix.vals[0][0], 9, - 0.001f)) { + if (MatricesEqualWithinTolerance(to_XYZD50, matrix, 0.001f)) { primaries_ = id; return; } } - UNSAFE_TODO(memcpy(custom_primary_matrix_, &to_XYZD50, 9 * sizeof(float))); + CopyMatrixToArray(to_XYZD50, custom_primary_matrix_); primaries_ = PrimaryID::CUSTOM; } @@ -208,7 +253,7 @@ auto check_transfer_fn = [this, &fn](TransferID id) { skcms_TransferFunction id_fn; GetTransferFunction(id, &id_fn); - if (!FloatsEqualWithinTolerance(&fn.g, &id_fn.g, 7, 0.001f)) { + if (!TransferFunctionsEqualWithinTolerance(fn, id_fn, 0.001f)) { return false; } transfer_ = id; @@ -278,14 +323,28 @@ return false; } if (primaries_ == PrimaryID::CUSTOM) { - if (UNSAFE_TODO(memcmp(custom_primary_matrix_, other.custom_primary_matrix_, - sizeof(custom_primary_matrix_)))) { + // Preserve the memcmp()-style bitwise comparison semantics for + // floats, including NaNs and signed zero. + // base::allow_nonunique_obj is safe here since floats are trivially + // copyable and we want a memcmp()-style bitwise comparison between floats, + // including NaNs and signed zero. + // See + // https://chromium.googlesource.com/chromium/src/+/HEAD/base/containers/span.h#164 + auto lhs = + base::as_byte_span(base::allow_nonunique_obj, custom_primary_matrix_); + auto rhs = base::as_byte_span(base::allow_nonunique_obj, + other.custom_primary_matrix_); + if (lhs != rhs) { return false; } } if (size_t param_count = TransferParamCount(transfer_)) { - if (UNSAFE_TODO(memcmp(transfer_params_, other.transfer_params_, - param_count * sizeof(float)))) { + auto lhs = base::as_byte_span(base::allow_nonunique_obj, transfer_params_) + .first(param_count * sizeof(float)); + auto rhs = + base::as_byte_span(base::allow_nonunique_obj, other.transfer_params_) + .first(param_count * sizeof(float)); + if (lhs != rhs) { return false; } } @@ -367,21 +426,24 @@ if (range_ > other.range_) return false; if (primaries_ == PrimaryID::CUSTOM) { - int primary_result = - UNSAFE_TODO(memcmp(custom_primary_matrix_, other.custom_primary_matrix_, - sizeof(custom_primary_matrix_))); - if (primary_result < 0) + auto lhs = + base::as_byte_span(base::allow_nonunique_obj, custom_primary_matrix_); + auto rhs = base::as_byte_span(base::allow_nonunique_obj, + other.custom_primary_matrix_); + if (lhs < rhs) { return true; - if (primary_result > 0) + } + if (lhs > rhs) { return false; + } } if (size_t param_count = TransferParamCount(transfer_)) { - int transfer_result = UNSAFE_TODO(memcmp( - transfer_params_, other.transfer_params_, param_count * sizeof(float))); - if (transfer_result < 0) - return true; - if (transfer_result > 0) - return false; + auto lhs = base::as_byte_span(base::allow_nonunique_obj, transfer_params_) + .first(param_count * sizeof(float)); + auto rhs = + base::as_byte_span(base::allow_nonunique_obj, other.transfer_params_) + .first(param_count * sizeof(float)); + return lhs < rhs; } return false; } @@ -392,18 +454,14 @@ (static_cast<size_t>(matrix_) << 16) | (static_cast<size_t>(range_) << 24); if (primaries_ == PrimaryID::CUSTOM) { - const uint32_t* params = - reinterpret_cast<const uint32_t*>(custom_primary_matrix_); - result ^= params[0]; - result ^= UNSAFE_TODO(params[4]); - result ^= UNSAFE_TODO(params[8]); + result ^= base::bit_cast<uint32_t>(custom_primary_matrix_[0]); + result ^= base::bit_cast<uint32_t>(custom_primary_matrix_[4]); + result ^= base::bit_cast<uint32_t>(custom_primary_matrix_[8]); } { // Note that |transfer_params_| must be zero when they are unused. - const uint32_t* params = - reinterpret_cast<const uint32_t*>(transfer_params_); - result ^= UNSAFE_TODO(params[3]); - result ^= UNSAFE_TODO(params[6]); + result ^= base::bit_cast<uint32_t>(transfer_params_[3]); + result ^= base::bit_cast<uint32_t>(transfer_params_[6]); } return result; } @@ -555,9 +613,9 @@ ColorSpace result(*this); skcms_Matrix3x3 to_XYZD50; GetPrimaryMatrix(&to_XYZD50); - for (int row = 0; row < 3; ++row) { - for (int col = 0; col < 3; ++col) { - UNSAFE_TODO(to_XYZD50.vals[row][col]) *= factor; + for (base::span<float, 3> row : to_XYZD50.vals) { + for (float& val : row) { + val *= factor; } } result.SetCustomPrimaries(to_XYZD50); @@ -778,10 +836,9 @@ // |matrix|. So the multiplication can be skipped, and we can just check if // each value in the matrix is in the range [0, 1]. constexpr float epsilon = 0.001f; - for (int r = 0; r < 3; r++) { - for (int c = 0; c < 3; c++) { - if (UNSAFE_TODO(matrix.vals[r][c]) < -epsilon || - UNSAFE_TODO(matrix.vals[r][c]) > 1 + epsilon) { + for (base::span<float, 3> row : matrix.vals) { + for (float& value : row) { + if (value < -epsilon || value > 1 + epsilon) { return false; } } @@ -857,7 +914,7 @@ SkColorSpacePrimaries ColorSpace::GetPrimaries() const { skcms_Matrix3x3 matrix; - UNSAFE_TODO(memcpy(&matrix, custom_primary_matrix_, 9 * sizeof(float))); + CopyArrayToMatrix(custom_primary_matrix_, matrix); return GetColorSpacePrimaries(primaries_, &matrix); } @@ -874,8 +931,9 @@ } void ColorSpace::GetPrimaryMatrix(skcms_Matrix3x3* to_XYZD50) const { + CHECK(to_XYZD50); if (primaries_ == PrimaryID::CUSTOM) { - UNSAFE_TODO(memcpy(to_XYZD50, custom_primary_matrix_, 9 * sizeof(float))); + CopyArrayToMatrix(custom_primary_matrix_, *to_XYZD50); } else { GetPrimaryMatrix(primaries_, to_XYZD50); }
diff --git a/ui/gfx/color_space.h b/ui/gfx/color_space.h index 27fa055..bf31d0c 100644 --- a/ui/gfx/color_space.h +++ b/ui/gfx/color_space.h
@@ -7,6 +7,7 @@ #include <stdint.h> +#include <array> #include <iosfwd> #include <optional> #include <string> @@ -413,7 +414,7 @@ RangeID range_ = RangeID::INVALID; // Only used if primaries_ is PrimaryID::CUSTOM. - float custom_primary_matrix_[9] = {}; + std::array<float, 9> custom_primary_matrix_ = {}; // Parameters for the transfer function. The interpretation depends on // |transfer_|. Only TransferParamCount() of these parameters are used, all @@ -423,7 +424,7 @@ // - PQ: SDR white point (entry A of the skcms_TransferFunction structure). // - HLG: SDR white point, peak luminance, and system gamma (entries A, B, and // C of the skcms_TransferFunction). - float transfer_params_[7] = {}; + std::array<float, 7> transfer_params_ = {}; friend struct IPC::ParamTraits<gfx::ColorSpace>; friend struct mojo::StructTraits<gfx::mojom::ColorSpaceDataView,
diff --git a/ui/gfx/geometry/matrix44.cc b/ui/gfx/geometry/matrix44.cc index 3e3f3d4..4b8336c2 100644 --- a/ui/gfx/geometry/matrix44.cc +++ b/ui/gfx/geometry/matrix44.cc
@@ -11,6 +11,7 @@ #include "base/compiler_specific.h" #include "base/containers/span.h" +#include "base/containers/span_writer.h" #include "ui/gfx/geometry/decomposed_transform.h" namespace gfx { @@ -104,17 +105,20 @@ } // anonymous namespace void Matrix44::GetColMajor(base::span<double, 16> dst) const { - base::span UNSAFE_TODO(src{&matrix_[0][0], base::fixed_extent<16>()}); - dst.copy_from(src); + base::SpanWriter writer(dst); + for (const base::span<const double, 4> col : matrix_) { + CHECK(writer.Write(col)); + } } void Matrix44::GetColMajorF(base::span<float, 16> dst) const { - base::span UNSAFE_TODO(src{&matrix_[0][0], base::fixed_extent<16>()}); - - // TODO: It's surprising that this isn't flagged as unsafe. - // It'd be nice if copy_from() supported differing element types, - // then this would be statically safe. - std::ranges::copy(src, dst.begin()); + size_t offset = 0; + for (const base::span<const double, 4> col : matrix_) { + std::ranges::transform( + col, dst.subspan(offset, std::size(col)).begin(), + [](double value) { return static_cast<float>(value); }); + offset += std::size(col); + } } void Matrix44::PreTranslate(double dx, double dy) { @@ -156,8 +160,9 @@ if (!HasPerspective()) [[likely]] { SetCol(3, Col(3) + t); } else { - for (int i = 0; i < 4; ++i) - SetCol(i, Col(i) + t * UNSAFE_TODO(matrix_[i])[3]); + for (size_t i = 0; i < matrix_.size(); ++i) { + SetCol(i, Col(i) + t * matrix_[i][3]); + } } }
diff --git a/ui/gfx/win/physical_size.cc b/ui/gfx/win/physical_size.cc index 1b74a7b..f268dc20 100644 --- a/ui/gfx/win/physical_size.cc +++ b/ui/gfx/win/physical_size.cc
@@ -8,6 +8,8 @@ #include <setupapi.h> +#include <array> + // LogSeverity is both a macro in setupapi.h and an enum in absl, which is used // indirectly via //base. #undef LogSeverity @@ -47,11 +49,10 @@ if (!reg_key.Valid()) return false; - BYTE data[128]; // EDID block is exactly 128 bytes long. - UNSAFE_TODO(ZeroMemory(&data[0], sizeof(data))); - DWORD data_length = sizeof(data); + std::array<BYTE, 128> data = {}; // EDID block is exactly 128 bytes long. + DWORD data_length = data.size(); LONG return_value = - reg_key.ReadValue(L"EDID", &data[0], &data_length, nullptr); + reg_key.ReadValue(L"EDID", data.data(), &data_length, nullptr); if (return_value != ERROR_SUCCESS) return false; @@ -146,9 +147,14 @@ while (EnumDisplayDevices(display_device.DeviceName, attached_index++, &attached_device, EDD_GET_DEVICE_INTERFACE_NAME)) { - wchar_t* attached_device_id = attached_device.DeviceID; - wchar_t* setup_device_path = interface_detail->DevicePath; - if (UNSAFE_TODO(wcsicmp(attached_device_id, setup_device_path)) == 0) { + // -1 means the string is NUL-terminated for CompareStringOrdinal. + // See + // https://learn.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-comparestringordinal + constexpr int kNullTerminatedString = -1; + if (CompareStringOrdinal(attached_device.DeviceID, + kNullTerminatedString, + interface_detail->DevicePath, + kNullTerminatedString, TRUE) == CSTR_EQUAL) { int width_mm; int height_mm; bool found = GetSizeFromRegistry(device_info_list.get(), &device_info,
diff --git a/ui/gl/gl_context.h b/ui/gl/gl_context.h index cccb613..321ff5d21 100644 --- a/ui/gl/gl_context.h +++ b/ui/gl/gl_context.h
@@ -77,6 +77,7 @@ kGLImageProcessor = 2, kWebViewRenderThread = 3, kAndroidVideoEncoder = 4, + kGraphiteDawnSharedContext = 5, }; struct GL_EXPORT GLContextAttribs {
diff --git a/ui/views/cocoa/native_widget_mac_ns_window_host.h b/ui/views/cocoa/native_widget_mac_ns_window_host.h index aa73ba0..7de4377 100644 --- a/ui/views/cocoa/native_widget_mac_ns_window_host.h +++ b/ui/views/cocoa/native_widget_mac_ns_window_host.h
@@ -78,9 +78,9 @@ // widget; use a __bridge cast to convert to and from NSView*. static const char kMovedContentNSView[]; - // Sets state as to whether windows, upon being restored, should be moved to - // the space that originally contained them. - static void SetMoveWindowsToOriginalSpacesUponRestoration(bool move); + // Sets state to indicate that windows, upon being restored, should be moved + // to the space that originally contained them. + static void MoveWindowsToOriginalSpacesUponRestoration(); // Unique integer id handles are used to bridge between the // NativeWidgetMacNSWindowHost in one process and the NativeWidgetNSWindowHost
diff --git a/ui/views/cocoa/native_widget_mac_ns_window_host.mm b/ui/views/cocoa/native_widget_mac_ns_window_host.mm index 56caa43b..e86b88c 100644 --- a/ui/views/cocoa/native_widget_mac_ns_window_host.mm +++ b/ui/views/cocoa/native_widget_mac_ns_window_host.mm
@@ -302,9 +302,8 @@ "kMovedContentNSView"; // static -void NativeWidgetMacNSWindowHost::SetMoveWindowsToOriginalSpacesUponRestoration( - bool move) { - g_move_windows_to_original_spaces_upon_restoration = move; +void NativeWidgetMacNSWindowHost::MoveWindowsToOriginalSpacesUponRestoration() { + g_move_windows_to_original_spaces_upon_restoration = true; } // static
diff --git a/ui/webui/resources/cr_components/composebox/BUILD.gn b/ui/webui/resources/cr_components/composebox/BUILD.gn index 7c0f668..8b013ba 100644 --- a/ui/webui/resources/cr_components/composebox/BUILD.gn +++ b/ui/webui/resources/cr_components/composebox/BUILD.gn
@@ -25,6 +25,7 @@ "composebox.html.ts", "composebox.ts", "composebox_context_menu.html.ts", + "composebox_mixin.ts", "composebox_dropdown.html.ts", "composebox_dropdown.ts", "composebox_file_inputs.html.ts",
diff --git a/ui/webui/resources/cr_components/composebox/composebox.css b/ui/webui/resources/cr_components/composebox/composebox.css index de09ed3..2ba864f 100644 --- a/ui/webui/resources/cr_components/composebox/composebox.css +++ b/ui/webui/resources/cr_components/composebox/composebox.css
@@ -276,7 +276,6 @@ #input, #smartCompose { - min-height: 48px; max-height: var(--text-input-max-height); scrollbar-width: none; } @@ -504,11 +503,11 @@ #submitContainer { border-radius: 50%; + bottom: var(--input-bottom-spacing); cursor: default; /* For Lens side panel. */ height: var(--cr-composebox-submit-container-size, var(--cr-icon-button-size)); - bottom: var(--input-bottom-spacing); - position: absolute; inset-inline-end: 10px; + position: absolute; width: var(--cr-composebox-submit-container-size, var(--cr-icon-button-size)); } @@ -607,7 +606,7 @@ #carousel { box-sizing: border-box; - margin-bottom: var(--context-non-top-carousel-bottom-margin, 12px); + margin-bottom: var(--context-non-top-carousel-bottom-margin, 8px); margin-top: var(--context-non-top-carousel-top-margin, 4px); /* Prefer using margin, but from legacy var name, we should be using inset. */ inset-inline-start: var(--context-carousel-inline-start-spacing, 50px); @@ -635,8 +634,9 @@ } #toolChipsContainer { - padding-top: 14px; + padding-bottom: 4px; padding-inline-start: 16px; + padding-top: 8px; } :host(:not([file-uploads-complete])) .upload-button { @@ -668,7 +668,7 @@ :host([searchbox-next-enabled][searchbox-layout-mode='Compact']) #textContainer { --text-input-inline-start-spacing: 40px; - padding-block: 6px 0; + padding-block: 6px 2px; } :host([searchbox-next-enabled]) #input, @@ -684,19 +684,20 @@ --cr-icon-button-icon-size: 12px; } -:host([searchbox-next-enabled][searchbox-layout-mode='Compact']) #context { - margin-top: var(--cr-composebox-context-margin-top, -48px); -} - :host([expanding_][show-dropdown_][searchbox-next-enabled][searchbox-layout-mode='Compact']) cr-composebox-dropdown { padding-bottom: 0; - padding-top: 8px; + padding-top: 4px; } :host-context([searchbox-layout-mode='TallTopContext']) .carousel-divider { margin-top: 10px; } +:host([searchbox-layout-mode='Compact'][show-dropdown_]) .carousel-divider { + --contextual-entrypoint-and-carousel-carousel-divider-margin-bottom: 8px; + --contextual-entrypoint-and-carousel-carousel-divider-margin-top: 12px; +} + #voiceSearchButton { --cr-icon-button-fill-color: var(--color-composebox-font-light); --cr-icon-button-hover-background-color: var(--color-composebox-context-entrypoint-hover-background); @@ -756,28 +757,19 @@ :host([searchbox-next-enabled][searchbox-layout-mode='Compact']) #carouselContainer, :host([searchbox-next-enabled][searchbox-layout-mode='TallBottomContext']) #carouselContainer { - align-items: flex-start; + align-items: flex-end; display: flex; flex-direction: row; } :host([submit-enabled_][searchbox-layout-mode='Compact']) #submitContainer { - margin-inline-end: 0; - margin-inline-start: auto; + inset-inline-end: 0; + margin-block: 12px 2px; + margin-inline: auto 10px; position: relative; } -:host([submit-enabled_][searchbox-layout-mode='Compact']:not([show-file-carousel_])) #submitContainer { - bottom: 0; - margin-top: 14px; -} - -:host([submit-enabled_][searchbox-layout-mode='Compact'][show-file-carousel_]) #submitContainer { - top: 14px; -} - :host([submit-enabled_][searchbox-layout-mode='TallBottomContext']) #submitContainer { - inset-inline-end: 10px; position: absolute; } @@ -793,12 +785,7 @@ --contextual-entrypoint-and-carousel-carousel-divider-margin-top: 50px; } -:host([submit-enabled_][searchbox-layout-mode='Compact'][show-dropdown_]:not([show-file-carousel_])) .carousel-divider { - --contextual-entrypoint-and-carousel-carousel-divider-margin-top: 12px; -} - -:host([submit-enabled_][searchbox-layout-mode='TallBottomContext'][show-dropdown_][show-file-carousel_]) .carousel-divider, -:host([submit-enabled_][searchbox-layout-mode='Compact'][show-dropdown_][show-file-carousel_]) .carousel-divider { +:host([submit-enabled_][searchbox-layout-mode='TallBottomContext'][show-dropdown_][show-file-carousel_]) .carousel-divider { --contextual-entrypoint-and-carousel-carousel-divider-margin-top: 8px; } @@ -822,7 +809,12 @@ } :host([searchbox-next-enabled]) #carousel { - margin-top: 16px; + --context-non-top-carousel-bottom-margin: 10px; + --context-non-top-carousel-top-margin: 6px; +} + +:host([searchbox-next-enabled]:not([in-tool-mode_])) #carousel { + --context-non-top-carousel-bottom-margin: 4px; } :host([is-omnibox-in-compact-mode_]) #carousel {
diff --git a/ui/webui/resources/cr_components/composebox/composebox.html.ts b/ui/webui/resources/cr_components/composebox/composebox.html.ts index f4c37b4..d1b1d39 100644 --- a/ui/webui/resources/cr_components/composebox/composebox.html.ts +++ b/ui/webui/resources/cr_components/composebox/composebox.html.ts
@@ -25,11 +25,11 @@ ` : ''} <ntp-error-scrim id="errorScrim" part="error-scrim" ?compact-mode="${this.searchboxLayoutMode === 'Compact' && - this.files_.size === 0}" - .errorMessage="${this.errorMessage_}" + this.files.size === 0}" + .errorMessage="${this.errorMessage}" @dismiss-error-scrim="${this.onDismissErrorScrim_}"> </ntp-error-scrim> - <div id="composebox" part="composebox" ?inert="${!!this.errorMessage_}" + <div id="composebox" part="composebox" ?inert="${!!this.errorMessage}" @keydown="${this.onKeydown_}" @focusin="${this.onComposeboxFocusin_}" @focusout="${this.onComposeboxFocusout_}" @@ -52,9 +52,9 @@ aria-expanded="${this.showDropdown_}" aria-controls="matches" role="combobox" autocomplete="off" id="input" type="search" spellcheck="false" - placeholder="${this.inputPlaceholder_}" + placeholder="${this.inputPlaceholder}" part="input" - .value="${this.input_}" + .value="${this.input}" @click="${this.onInputClick_}" @keyup="${this.onInputKeyup_}" @input="${this.onInputInput_}" @@ -65,7 +65,7 @@ <div id="smartCompose" part="smart-compose"> <!-- Comments in between spans to eliminate spacing between spans --> - <span id="invisibleText">${this.input_}</span><!-- + <span id="invisibleText">${this.input}</span><!-- --><span id="ghostText">${this.smartComposeInlineHint_}</span><!-- --><span id="tabChip">${this.i18n('composeboxSmartComposeTabTitle')}</span> </div> @@ -101,20 +101,18 @@ exportparts="thumbnail, thumbnail-title" id="carousel" class="${this.carouselOnTop_ ? 'top' : ''}" - .files="${Array.from(this.files_.values())}" + .files="${Array.from(this.files.values())}" ?enable-scrolling="${this.enableCarouselScrolling}" @delete-file="${this.onDeleteFile_}"> </cr-composebox-file-carousel> ` : ''} - ${this.searchboxLayoutMode === 'Compact' && this.inToolMode_ && !this.showDropdown_ ? html` + ${this.searchboxLayoutMode === 'Compact' && this.inToolMode_ ? html` <div class="context-menu-container" id="toolChipsContainer" part="tool-chips-container"> - ${this.inToolMode_ ? html` <cr-composebox-tool-chip exportparts="tool-chip-label" - .inputState="${this.inputState_}" + .inputState="${this.inputState}" @tool-click="${this.onToolClick_}"> </cr-composebox-tool-chip> - `: ''} </div> ` : ''} </div> @@ -136,25 +134,13 @@ .result="${this.result_}" .selectedMatchIndex="${this.selectedMatchIndex_}" .maxSuggestions="${this.maxSuggestions}" - .toolMode="${this.activeToolMode_}" + .toolMode="${this.activeToolMode}" @selected-match-index-changed="${this.onSelectedMatchIndexChanged_}" @match-focusin="${this.onMatchFocusin_}" @match-click="${this.onMatchClick_}" ?hidden="${!this.showDropdown_}" .lastQueriedInput="${this.lastQueriedInput_}"> </cr-composebox-dropdown> - ${this.searchboxLayoutMode === 'Compact' && this.inToolMode_ && this.showDropdown_ ? html` - <div class="context-menu-container" id="toolChipsContainer" - part="tool-chips-container"> - ${this.inToolMode_ ? html` - <cr-composebox-tool-chip - exportparts="tool-chip-label" - .inputState="${this.inputState_}" - @tool-click="${this.onToolClick_}"> - </cr-composebox-tool-chip> - `: ''} - </div> - ` : ''} ${this.searchboxLayoutMode === 'TallBottomContext' || this.searchboxLayoutMode === '' || this.isOmniboxInCompactMode_ ? html` ${this.contextMenuEnabled_ ? getContextMenuHtml.bind(this)() : ''} `: ''}
diff --git a/ui/webui/resources/cr_components/composebox/composebox.ts b/ui/webui/resources/cr_components/composebox/composebox.ts index 14afbb8..3511195 100644 --- a/ui/webui/resources/cr_components/composebox/composebox.ts +++ b/ui/webui/resources/cr_components/composebox/composebox.ts
@@ -22,7 +22,7 @@ import {getInstance as getAnnouncerInstance} from '//resources/cr_elements/cr_a11y_announcer/cr_a11y_announcer.js'; import type {CrIconButtonElement} from '//resources/cr_elements/cr_icon_button/cr_icon_button.js'; import {I18nMixinLit} from '//resources/cr_elements/i18n_mixin_lit.js'; -import {assert} from '//resources/js/assert.js'; +import {assert, assertNotReachedCase} from '//resources/js/assert.js'; import {EventTracker} from '//resources/js/event_tracker.js'; import {loadTimeData} from '//resources/js/load_time_data.js'; import {hasKeyModifiers} from '//resources/js/util.js'; @@ -42,6 +42,7 @@ import type {PageHandlerRemote} from './composebox.mojom-webui.js'; import type {ComposeboxDropdownElement} from './composebox_dropdown.js'; import type {ComposeboxFileInputsElement} from './composebox_file_inputs.js'; +import {ComposeboxEmbedderMixin} from './composebox_mixin.js'; import {ComposeboxProxyImpl} from './composebox_proxy.js'; import {ContextUploadStatus, InputType, ToolMode as ComposeboxToolMode} from './composebox_query.mojom-webui.js'; import type {ContextUploadErrorType, InputState} from './composebox_query.mojom-webui.js'; @@ -65,6 +66,24 @@ QUERY_SUBMITTED = 1, } +export function isTerminalState(status: ContextUploadStatus): boolean { + switch (status) { + case ContextUploadStatus.kUploadSuccessful: + case ContextUploadStatus.kUploadFailed: + case ContextUploadStatus.kValidationFailed: + case ContextUploadStatus.kUploadExpired: + case ContextUploadStatus.kUploadReplaced: + return true; + case ContextUploadStatus.kNotUploaded: + case ContextUploadStatus.kProcessing: + case ContextUploadStatus.kUploadStarted: + case ContextUploadStatus.kProcessingSuggestSignalsReady: + return false; + default: + assertNotReachedCase(status, 'Unknown enum value'); + } +} + const DEBOUNCE_TIMEOUT_MS: number = 20; const ZERO_SPACE_STRING: string = '\u200b'; @@ -118,8 +137,8 @@ } -export class ComposeboxElement extends I18nMixinLit -(CrLitElement) implements DragAndDropHost { +export class ComposeboxElement extends ComposeboxEmbedderMixin +(I18nMixinLit(CrLitElement)) implements DragAndDropHost { static get is() { return 'cr-composebox'; } @@ -138,7 +157,6 @@ showLensButton: {type: Boolean}, suggestionActivityEnabled: {type: Boolean}, lensButtonTriggersOverlay: {type: Boolean}, - input_: {type: String}, isCollapsible: { reflect: true, type: Boolean, @@ -170,10 +188,6 @@ reflect: true, type: Boolean, }, - inputPlaceholder_: { - reflect: true, - type: String, - }, smartComposeEnabled_: { reflect: true, type: Boolean, @@ -187,8 +201,8 @@ reflect: true, type: Boolean, }, - activeToolMode_: { - type: Number, + inToolMode_: { + type: Boolean, reflect: true, }, /** @@ -214,7 +228,6 @@ reflect: true, type: Boolean, }, - errorMessage_: {type: String}, searchboxLayoutMode: { type: String, reflect: true, @@ -246,7 +259,6 @@ reflect: true, }, showModelPicker: {type: Boolean}, - inputState_: {type: Object}, showModelPicker_: { type: Boolean, reflect: true, @@ -257,9 +269,7 @@ }, enableCarouselScrolling: {type: Boolean}, inputPlaceholderOverride: {type: String}, - files_: {type: Object}, contextMenuEnabled_: {type: Boolean}, - addedTabsIds_: {type: Object}, showContextMenuDescription_: {type: Boolean}, uploadButtonDisabled_: { type: Boolean, @@ -314,7 +324,6 @@ // Whether the composebox is currently expanded. Always true if isCollapsible // is false. protected accessor expanding_: boolean = false; - protected accessor input_: string = ''; protected accessor showDropdown_: boolean = loadTimeData.getBoolean('composeboxShowZps'); protected accessor enableImageContextualSuggestions_: boolean = @@ -326,16 +335,10 @@ protected accessor smartComposeInlineHint_: string = ''; protected accessor smartComposeEnabled_: boolean = loadTimeData.getBoolean('composeboxSmartComposeEnabled'); - protected accessor inputPlaceholder_: string = - loadTimeData.getString('searchboxComposePlaceholder'); protected accessor showFileCarousel_: boolean = false; - protected accessor activeToolMode_: ComposeboxToolMode = - ComposeboxToolMode.kUnspecified; - protected accessor errorMessage_: string = ''; protected accessor transcript_: string = ''; protected accessor receivedSpeech_: boolean = false; protected accessor canSubmitFilesAndInput_: boolean = true; - protected accessor inputState_: InputState|null = null; protected lastQueriedInput_: string = ''; protected showVoiceSearchInSteadyComposebox_: boolean = loadTimeData.getBoolean('steadyComposeboxShowVoiceSearch'); @@ -346,16 +349,16 @@ loadTimeData.getBoolean('contextualMenuUsePecApi') : false; protected accessor hasAllowedInputs_: boolean = false; - protected accessor files_: Map<UnguessableToken, ComposeboxFile> = new Map(); protected accessor contextMenuEnabled_: boolean = loadTimeData.getBoolean('composeboxShowContextMenu'); - protected accessor addedTabsIds_: Map<number, UnguessableToken> = new Map(); protected accessor uploadButtonDisabled_: boolean = false; protected contextMenuDescriptionEnabled_: boolean = loadTimeData.getBoolean('composeboxShowContextMenuDescription'); protected accessor showContextMenuDescription_: boolean = this.contextMenuDescriptionEnabled_; protected accessor isOmniboxInCompactMode_: boolean = false; + protected accessor inVoiceSearchMode_: boolean = false; + protected accessor inToolMode_: boolean = false; // Synchronous immediate guard used to deduplicate processing // autochips being added, not fully processed chips. protected pendingAutomaticActiveTabUrl_: string = ''; @@ -391,7 +394,6 @@ loadTimeData.valueExists('autoSubmitVoiceSearchQuery') ? loadTimeData.getBoolean('autoSubmitVoiceSearchQuery') : true; - protected accessor inVoiceSearchMode_: boolean = false; private selectedMatch_: AutocompleteMatch|null = null; // Whether the composebox is actively waiting for an autocomplete response. If // this is false, that means at least one response has been received (even if @@ -412,10 +414,6 @@ private imageFileTypes_: string[] = loadTimeData.getString('composeboxImageFileTypes').split(','); - protected get inToolMode_(): boolean { - return this.activeToolMode_ !== ComposeboxToolMode.kUnspecified; - } - protected get shouldShowDivider_(): boolean { // TODO(crbug.com/476175193): Remove `entrypointName` condition. if (this.entrypointName === 'Omnibox' && @@ -427,7 +425,7 @@ return this.showDropdown_ && (this.showFileCarousel_ || this.searchboxLayoutMode === 'TallTopContext' || - this.shouldShowSubmitButton_); + this.shouldShowSubmitButton_ || this.inToolMode_); } protected get shouldShowSubmitButton_(): boolean { @@ -494,7 +492,7 @@ const inputState = await this.searchboxHandler_.getInputState(); if (inputState) { - this.inputState_ = inputState.state; + this.inputState = inputState.state; } this.setupResizeObservers_(); @@ -550,12 +548,16 @@ const changedPrivateProperties = changedProperties as Map<PropertyKey, unknown>; + if (changedPrivateProperties.has('activeToolMode')) { + this.inToolMode_ = + this.activeToolMode !== ComposeboxToolMode.kUnspecified; + } // When the result initially gets set check if dropdown should show. - if (changedPrivateProperties.has('input_') || + if (changedPrivateProperties.has('input') || changedPrivateProperties.has('result_') || - changedPrivateProperties.has('files_') || - changedPrivateProperties.has('errorMessage_')) { - this.showFileCarousel_ = this.files_.size > 0; + changedPrivateProperties.has('files') || + changedPrivateProperties.has('errorMessage')) { + this.showFileCarousel_ = this.files.size > 0; this.showDropdown_ = this.computeShowDropdown_(); } if (changedPrivateProperties.has('submitEnabled_') || @@ -565,18 +567,18 @@ this.submitEnabled_ && this.fileUploadsComplete; } - if (changedPrivateProperties.has('inputState_')) { - this.hasAllowedInputs_ = !!this.inputState_ && - (this.inputState_.allowedModels.length > 0 || - this.inputState_.allowedTools.length > 0 || - this.inputState_.allowedInputTypes.length > 0); + if (changedPrivateProperties.has('inputState')) { + this.hasAllowedInputs_ = !!this.inputState && + (this.inputState.allowedModels.length > 0 || + this.inputState.allowedTools.length > 0 || + this.inputState.allowedInputTypes.length > 0); } if (changedPrivateProperties.has('inputPlaceholderOverride') || - changedPrivateProperties.has('files_') || + changedPrivateProperties.has('files') || changedPrivateProperties.has('enableFileHint') || - changedPrivateProperties.has('inputState_') || - changedPrivateProperties.has('activeToolMode_')) { + changedPrivateProperties.has('inputState') || + changedPrivateProperties.has('activeToolMode')) { this.updateInputPlaceholder_(); } } @@ -593,7 +595,7 @@ if (this.selectedMatch_) { // Update the input. const text = this.selectedMatch_.fillIntoEdit; - this.input_ = text; + this.input = text; } else if (!this.lastQueriedInput_) { // This is for cases when focus leaves the matches/input. // If there was already text in the input do not clear it. @@ -601,14 +603,14 @@ } else { // For typed queries reset the input back to typed value when // focus leaves the match. - this.input_ = this.lastQueriedInput_; + this.input = this.lastQueriedInput_; } } if (changedPrivateProperties.has('selectedMatchIndex_') || - changedPrivateProperties.has('inputState_') || + changedPrivateProperties.has('inputState') || changedPrivateProperties.has('isFollowupQuery') || - changedPrivateProperties.has('files_')) { + changedPrivateProperties.has('files')) { this.submitEnabled_ = this.computeSubmitEnabled_(); this.canSubmitFilesAndInput_ = this.submitEnabled_ && this.fileUploadsComplete; @@ -646,7 +648,7 @@ } getText() { - return this.input_; + return this.input; } queryAutocomplete(clearMatches: boolean) { @@ -676,35 +678,34 @@ } setText(text: string) { - this.input_ = text; + this.input = text; } resetModes() { - const previousTool = this.activeToolMode_; - this.activeToolMode_ = ComposeboxToolMode.kUnspecified; + const previousTool = this.activeToolMode; + this.activeToolMode = ComposeboxToolMode.kUnspecified; this.uploadButtonDisabled_ = false; if (previousTool !== ComposeboxToolMode.kUnspecified) { this.showContextMenuDescription_ = this.contextMenuDescriptionEnabled_; - this.handleToolModeUpdate_(); + this.handleToolModeUpdate_(ComposeboxToolMode.kUnspecified); } } setDefaultModel() { - if (this.inputState_?.activeModel && - (this.inputState_.activeModel as ModelMode) !== - ModelMode.kUnspecified) { - this.searchboxHandler_.setActiveModelMode(this.inputState_.activeModel); + if (this.inputState?.activeModel && + (this.inputState.activeModel as ModelMode) !== ModelMode.kUnspecified) { + this.searchboxHandler_.setActiveModelMode(this.inputState.activeModel); } else if ( - this.inputState_?.allowedModels && - this.inputState_.allowedModels.length > 0) { + this.inputState?.allowedModels && + this.inputState.allowedModels.length > 0) { this.searchboxHandler_.setActiveModelMode( - this.inputState_.allowedModels[0]!); + this.inputState.allowedModels[0]!); } } resetToolsAndModels() { - if (this.inputState_) { + if (this.inputState) { this.searchboxHandler_.setActiveToolMode(ComposeboxToolMode.kUnspecified); this.searchboxHandler_.setActiveModelMode(ModelMode.kUnspecified); } @@ -741,7 +742,7 @@ } hasFiles(): boolean { - return this.files_.size > 0; + return this.files.size > 0; } isExpanded(): boolean { @@ -759,7 +760,7 @@ let model = state.model ?? ModelMode.kUnspecified; if (text) { - this.input_ = text; + this.input = text; this.lastQueriedInput_ = text; } if (this.showZps && files.length === 0) { @@ -797,9 +798,9 @@ this.handleToolClick_(mode); } - if (!!this.inputState_ && model === ModelMode.kUnspecified && - this.inputState_.allowedModels.length > 0) { - model = this.inputState_.allowedModels[0]!; + if (!!this.inputState && model === ModelMode.kUnspecified && + this.inputState.allowedModels.length > 0) { + model = this.inputState.allowedModels[0]!; } this.searchboxHandler_.setActiveModelMode(model); this.updateInputPlaceholder_(); @@ -817,7 +818,7 @@ } protected computeCancelButtonTitle_() { - return this.input_.trim().length > 0 || this.files_.size > 0 ? + return this.input.trim().length > 0 || this.files.size > 0 ? this.i18n('composeboxCancelButtonTitleInput') : this.i18n('composeboxCancelButtonTitle'); } @@ -849,7 +850,7 @@ private computeShowDropdown_() { // Don't show dropdown if there's multiple files. - if (this.files_.size > 1) { + if (this.files.size > 1) { return false; } @@ -859,7 +860,7 @@ } // Do not show dropdown if there's an error scrim. - if (this.errorMessage_ !== '') { + if (this.errorMessage !== '') { return false; } @@ -872,7 +873,7 @@ if (this.showTypedSuggest_ && this.lastQueriedInput_.trim()) { // If context is present, but not enabled, continue to avoid showing the // dropdown. - if (!this.showTypedSuggestWithContext_ && this.files_.size > 0) { + if (!this.showTypedSuggestWithContext_ && this.files.size > 0) { return false; } // Do not show the dropdown for multiline input or if only the verbatim @@ -883,8 +884,8 @@ } } - // lastQueriedInput_ is used here since the input_ changes based on - // the selected match. If typed suggest is not enabled and input_ is used, + // lastQueriedInput_ is used here since the input changes based on + // the selected match. If typed suggest is not enabled and input is used, // the dropdown will hide if the user keys down over zps matches. return this.showZps && !this.lastQueriedInput_; } @@ -892,7 +893,7 @@ private hasValidQuery_() { // If there is at least one file that supports unimodal search, query is // valid. - if (this.files_.values().find( + if (this.files.values().find( (file: ComposeboxFile) => file.supportsUnimodal)) { return true; } @@ -902,14 +903,14 @@ return true; } - if (this.input_.trim().length > 0) { + if (this.input.trim().length > 0) { return true; } // TODO(crbug.com/485648942): Update to drive Deep Search behavior from the // PEC API's ToolSubstateConfig. // Allow empty query for Deep Search follow-ups. - if (this.inputState_?.activeTool === ComposeboxToolMode.kDeepSearch && + if (this.inputState?.activeTool === ComposeboxToolMode.kDeepSearch && this.isFollowupQuery) { return true; } @@ -933,7 +934,7 @@ } protected shouldShowVoiceSearch_(): boolean { - const isExpanded = this.showDropdown_ || this.files_.size > 0; + const isExpanded = this.showDropdown_ || this.files.size > 0; const isFeatureEnabled = isExpanded ? this.showVoiceSearchInExpandedComposebox_ : this.showVoiceSearchInSteadyComposebox_; @@ -956,13 +957,13 @@ } deleteFile(uuidToDelete: UnguessableToken, fromUserAction?: boolean) { - if (!uuidToDelete || !this.files_.has(uuidToDelete)) { + if (!uuidToDelete || !this.files.has(uuidToDelete)) { return; } - const file = this.files_.get(uuidToDelete); + const file = this.files.get(uuidToDelete); if (file?.tabId) { - this.addedTabsIds_ = new Map([...this.addedTabsIds_.entries()].filter( + this.addedTabsIds = new Map([...this.addedTabsIds.entries()].filter( ([id, _]) => id !== file.tabId)); } @@ -988,8 +989,8 @@ recordBoolean(metricName, true); } - this.files_ = new Map([...this.files_.entries()].filter( - ([uuid, _]) => uuid !== uuidToDelete)); + this.files = new Map( + [...this.files.entries()].filter(([uuid, _]) => uuid !== uuidToDelete)); this.pendingUploads_.delete(uuidToDelete); this.fileUploadsComplete = this.pendingUploads_.size === 0; this.searchboxHandler_.deleteContext(uuidToDelete, fromAutoSuggestedChip); @@ -1037,7 +1038,7 @@ } catch (e) { const err = e as ContextUploadErrorType; if (FILE_VALIDATION_ERRORS_MAP.has(err)) { - this.errorMessage_ = this.i18n(FILE_VALIDATION_ERRORS_MAP.get(err)!); + this.errorMessage = this.i18n(FILE_VALIDATION_ERRORS_MAP.get(err)!); } continue; } @@ -1054,8 +1055,8 @@ const announcer = getAnnouncerInstance(); announcer.announce(this.i18n('composeboxFileUploadStartedText')); } - this.files_ = - new Map([...this.files_.entries(), ...composeboxFiles.entries()]); + this.files = + new Map([...this.files.entries(), ...composeboxFiles.entries()]); this.recordFileValidationMetric_(ComposeboxFileValidationError.NONE); this.focusInput(); } @@ -1152,10 +1153,10 @@ } private onInputStateChanged_(inputState: InputState) { - this.inputState_ = inputState; + this.inputState = inputState; - const allowedTypes = this.inputState_.allowedInputTypes; - this.files_.forEach((file, uuid) => { + const allowedTypes = this.inputState.allowedInputTypes; + this.files.forEach((file, uuid) => { if (!allowedTypes.includes(file.inputType)) { this.deleteFile(uuid); } @@ -1207,10 +1208,10 @@ tabUpload.title, tabUpload.url, {supportsUnimodal: true}); - this.files_ = new Map( - [...this.files_.entries(), [attachment.uuid, attachment]]); - this.addedTabsIds_ = new Map( - [...this.addedTabsIds_.entries(), [tabUpload.tabId, attachment.uuid]]); + this.files = + new Map([...this.files.entries(), [attachment.uuid, attachment]]); + this.addedTabsIds = new Map( + [...this.addedTabsIds.entries(), [tabUpload.tabId, attachment.uuid]]); // Do not reset pending active tab to avoid overwriting // synchronous "pending statuses" that are queued (since this function @@ -1225,7 +1226,7 @@ } catch (e) { const err = e as ContextUploadErrorType; if (FILE_VALIDATION_ERRORS_MAP.has(err)) { - this.errorMessage_ = this.i18n(FILE_VALIDATION_ERRORS_MAP.get(err)!); + this.errorMessage = this.i18n(FILE_VALIDATION_ERRORS_MAP.get(err)!); } return; } @@ -1307,7 +1308,7 @@ // TODO(crbug.com/466412331): Remove, only recorded for the NTP. this.fire( 'voice-search-action', {value: VoiceSearchAction.QUERY_SUBMITTED}); - this.input_ = e.detail; + this.input = e.detail; const metricName = `ContextualSearch.UserAction.SubmitVoiceQuery.${ this.composeboxSource_}`; recordUserAction(metricName); @@ -1320,7 +1321,7 @@ // If auto-submit is not enabled, update the input to the voice search // query, clear autocomplete matches, and recompute whether submission // should be enabled. - this.input_ = e.detail; + this.input = e.detail; this.queryAutocomplete_(/* clearMatches= */ true); this.submitEnabled_ = this.computeSubmitEnabled_(); await this.updateComplete; @@ -1389,8 +1390,8 @@ } private hasContent_(): boolean { - return this.activeToolMode_ !== ComposeboxToolMode.kUnspecified || - this.input_.trim().length > 0 || this.files_.size > 0; + return this.activeToolMode !== ComposeboxToolMode.kUnspecified || + this.input.trim().length > 0 || this.files.size > 0; } protected onLensClick_() { @@ -1411,124 +1412,120 @@ private updateInputPlaceholder_() { if (this.inputPlaceholderOverride) { - this.inputPlaceholder_ = this.inputPlaceholderOverride; + this.inputPlaceholder = this.inputPlaceholderOverride; return; } // The file hint should only be shown when there is context that was // deliberately added by the user (i.e. not the automatic active tab). - const isOnlyAutoTab = this.files_.size === 1 && !!this.automaticActiveTab_; + const isOnlyAutoTab = this.files.size === 1 && !!this.automaticActiveTab_; const shouldUseFileHint = this.enableFileHint && this.hasFiles() && !isOnlyAutoTab && - this.activeToolMode_ === ComposeboxToolMode.kUnspecified; + this.activeToolMode === ComposeboxToolMode.kUnspecified; if (shouldUseFileHint) { - if (this.files_.size > 1) { - this.inputPlaceholder_ = this.i18n('composeboxHintTextAskAboutThese'); + if (this.files.size > 1) { + this.inputPlaceholder = this.i18n('composeboxHintTextAskAboutThese'); return; } - const file = this.files_.values().next().value!; + const file = this.files.values().next().value!; if (file.type === 'tab') { - this.inputPlaceholder_ = this.i18n('composeboxHintTextAskAboutThisTab'); + this.inputPlaceholder = this.i18n('composeboxHintTextAskAboutThisTab'); return; } else if (file.type.includes('image')) { - this.inputPlaceholder_ = + this.inputPlaceholder = this.i18n('composeboxHintTextAskAboutThisImage'); return; } else if (file.type === 'pdf' || file.type === 'application/pdf') { - this.inputPlaceholder_ = this.i18n('composeboxHintTextAskAboutThisDoc'); + this.inputPlaceholder = this.i18n('composeboxHintTextAskAboutThisDoc'); return; } } - if (this.inputState_) { - if (this.activeToolMode_ !== ComposeboxToolMode.kUnspecified) { - const config = this.inputState_.toolConfigs.find( - c => c.tool === this.activeToolMode_); + if (this.inputState) { + if (this.activeToolMode !== ComposeboxToolMode.kUnspecified) { + const config = this.inputState.toolConfigs.find( + c => c.tool === this.activeToolMode); if (config?.hintText) { - this.inputPlaceholder_ = config.hintText; + this.inputPlaceholder = config.hintText; return; } } - if (this.inputState_.activeModel !== ModelMode.kUnspecified) { - const config = this.inputState_.modelConfigs.find( - c => c.model === this.inputState_!.activeModel); + if (this.inputState.activeModel !== ModelMode.kUnspecified) { + const config = this.inputState.modelConfigs.find( + c => c.model === this.inputState!.activeModel); if (config?.hintText) { - this.inputPlaceholder_ = config.hintText; + this.inputPlaceholder = config.hintText; return; } } - if (this.inputState_.hintText) { - this.inputPlaceholder_ = this.inputState_.hintText; + if (this.inputState.hintText) { + this.inputPlaceholder = this.inputState.hintText; return; } } - if (this.activeToolMode_ === ComposeboxToolMode.kDeepSearch) { - this.inputPlaceholder_ = + if (this.activeToolMode === ComposeboxToolMode.kDeepSearch) { + this.inputPlaceholder = loadTimeData.getString('composeDeepSearchPlaceholder'); - } else if (this.activeToolMode_ === ComposeboxToolMode.kImageGen) { - this.inputPlaceholder_ = + } else if (this.activeToolMode === ComposeboxToolMode.kImageGen) { + this.inputPlaceholder = loadTimeData.getString('composeCreateImagePlaceholder'); } else { - this.inputPlaceholder_ = + this.inputPlaceholder = loadTimeData.getString('searchboxComposePlaceholder'); } } - get activeToolMode(): ComposeboxToolMode { - return this.activeToolMode_; - } - protected onToolClick_(e: CustomEvent<{toolMode: ComposeboxToolMode}>) { this.handleToolClick_(e.detail.toolMode); } protected handleToolClick_(tool: ComposeboxToolMode) { + const isTogglingOff = this.activeToolMode === tool; + if (this.contextMenuDescriptionEnabled_) { - if (this.activeToolMode_ === tool) { - this.showContextMenuDescription_ = true; - } else { - this.showContextMenuDescription_ = - tool === ComposeboxToolMode.kUnspecified; - } + this.showContextMenuDescription_ = + isTogglingOff || tool === ComposeboxToolMode.kUnspecified; } - if (this.activeToolMode_ === tool) { - this.activeToolMode_ = ComposeboxToolMode.kUnspecified; + const newToolMode = isTogglingOff ? ComposeboxToolMode.kUnspecified : tool; + + if (isTogglingOff) { const metricName = `ContextualSearch.UserAction.InputStateDeletion.Tool.${ this.composeboxSource_}`; recordUserAction(metricName); recordBoolean(metricName, true); } else { - this.activeToolMode_ = tool; + this.searchboxHandler_.recordToolSelectionAction(newToolMode); } - - this.handleToolModeUpdate_(); + this.handleToolModeUpdate_(newToolMode); } - private handleToolModeUpdate_() { - this.searchboxHandler_.setActiveToolMode(this.activeToolMode_); + private handleToolModeUpdate_(toolMode: ComposeboxToolMode) { + this.activeToolMode = toolMode; + this.searchboxHandler_.setActiveToolMode(this.activeToolMode); this.queryAutocomplete_(/* clearMatches= */ true); this.updateInputPlaceholder_(); - this.fire('active-tool-mode-changed', {value: this.activeToolMode_}); + this.fire('active-tool-mode-changed', {value: this.activeToolMode}); } protected onModelClick_(e: CustomEvent<{model: ModelMode}>) { + this.searchboxHandler_.recordModelSelectionAction(e.detail.model); this.searchboxHandler_.setActiveModelMode(e.detail.model); this.updateInputPlaceholder_(); } protected onDismissErrorScrim_() { - this.errorMessage_ = ''; + this.errorMessage = ''; } // Sets the input property to compute the cancel button title without using // "$." syntax as this is not allowed in WillUpdate(). protected onInputInput_(e: Event) { const inputElement = e.target as HTMLInputElement; - this.input_ = inputElement.value; + this.input = inputElement.value; if (!this.disableCaretColorAnimation) { this.updateMirror_(); @@ -1543,12 +1540,12 @@ // If the composebox no flickering fix is enabled, stop the ACController // from querying for suggestions when the input is empty, but don't clear // the matches so the dropdown doesn't close. - if (this.input_ === '') { + if (this.input === '') { this.searchboxHandler_.stopAutocomplete(/*clearResult=*/ true); } this.queryAutocomplete_(/* clearMatches= */ false); } else { - this.queryAutocomplete_(/* clearMatches= */ this.input_ === ''); + this.queryAutocomplete_(/* clearMatches= */ this.input === ''); } } @@ -1560,7 +1557,7 @@ mirror.textContent = ''; - const chars = this.input_.split(''); + const chars = this.input.split(''); if (chars.length === 0) { const emptySpan = document.createElement('span'); @@ -1722,7 +1719,7 @@ if (e.shiftKey) { this.$.matches.unselect(); } else if (this.smartComposeEnabled_ && this.smartComposeInlineHint_) { - this.input_ = this.input_ + this.smartComposeInlineHint_; + this.input = this.input + this.smartComposeInlineHint_; this.smartComposeInlineHint_ = ''; e.preventDefault(); this.queryAutocomplete_(/* clearMatches= */ true); @@ -1851,7 +1848,7 @@ protected onSubmitContainerFocusin_() { // Matches should always be greater than 0 due to verbatim match. - if (this.input_ && !this.selectedMatch_) { + if (this.input && !this.selectedMatch_) { this.selectFirstMatch(); } } @@ -1859,7 +1856,7 @@ addSearchContext(context: SearchContext|null) { if (context) { if (context.input.length > 0) { - this.input_ = context.input; + this.input = context.input; } for (const attachment of context.attachments) { if (attachment.fileAttachment) { @@ -1871,13 +1868,13 @@ switch (context.toolMode) { case ToolMode.kDeepSearch: - this.handleToolClick_(ComposeboxToolMode.kDeepSearch); + this.handleToolModeUpdate_(ComposeboxToolMode.kDeepSearch); break; case ToolMode.kCreateImage: - this.handleToolClick_(ComposeboxToolMode.kImageGen); + this.handleToolModeUpdate_(ComposeboxToolMode.kImageGen); break; case ToolMode.kCanvas: - this.handleToolClick_(ComposeboxToolMode.kCanvas); + this.handleToolModeUpdate_(ComposeboxToolMode.kCanvas); break; default: } @@ -1892,7 +1889,7 @@ this.resetModes(); this.searchboxHandler_.clearFiles(/*shouldBlockAutoSuggestedTabs=*/ false); this.resetToolsAndModels(); - this.fire('close-composebox', {composeboxText: this.input_}); + this.fire('close-composebox', {composeboxText: this.input}); if (this.isCollapsible) { this.expanding_ = false; @@ -1939,8 +1936,8 @@ e.altKey, e.ctrlKey, e.metaKey, e.shiftKey); } else { this.searchboxHandler_.submitQuery( - this.input_.trim(), (e as MouseEvent).button || 0, e.altKey, - e.ctrlKey, e.metaKey, e.shiftKey); + this.input.trim(), (e as MouseEvent).button || 0, e.altKey, e.ctrlKey, + e.metaKey, e.shiftKey); } this.submitCleanup_(); @@ -1982,7 +1979,7 @@ } getFilesForTesting(): ComposeboxFile[] { - return [...this.files_.values()]; + return [...this.files.values()]; } getResultForTesting(): AutocompleteResult|null { @@ -2050,7 +2047,7 @@ if (firstMatch && firstMatch.allowedToBeDefaultMatch) { this.selectFirstMatch(); } else if ( - this.input_.trim() && hasMatches && this.selectedMatchIndex_ >= 0 && + this.input.trim() && hasMatches && this.selectedMatchIndex_ >= 0 && this.selectedMatchIndex_ < this.result_.matches.length) { // Restore the selection and update the input. Don't restore when the // user deletes all their input and autocomplete is queried or else the @@ -2061,7 +2058,7 @@ // (and therefore `selectedMatch_` does not get updated since // `onSelectedMatchIndexChanged_` is not called). this.selectedMatch_ = this.result_.matches[this.selectedMatchIndex_]!; - this.input_ = this.selectedMatch_.fillIntoEdit; + this.input = this.selectedMatch_.fillIntoEdit; } else { this.$.matches.unselect(); } @@ -2083,13 +2080,13 @@ const {file, errorMessage} = this.updateFileStatus_(token, status, errorType); if (errorMessage) { // `file` value is definitely stale. - this.errorMessage_ = errorMessage; + this.errorMessage = errorMessage; this.pendingUploads_.delete(token); this.fileUploadsComplete = this.pendingUploads_.size === 0; } else if (file) { // Treat `kUploadReplaced` like an error upload state // (like `kUploadFailed`. `kValidationFailed`, - // `kUploadExpired`), just without setting `errorMessage_`. + // `kUploadExpired`), just without setting `errorMessage`. // This means for `kUploadReplaced`, we do not fetch suggestions, // etc. if (file.status === ContextUploadStatus.kUploadReplaced) { @@ -2176,9 +2173,9 @@ if (clearMatches) { this.clearAutocompleteMatches(); } - this.lastQueriedInput_ = this.input_; + this.lastQueriedInput_ = this.input; this.haveReceivedAutcompleteResponse_ = false; - this.searchboxHandler_.queryAutocomplete(this.input_, false); + this.searchboxHandler_.queryAutocomplete(this.input, false); } clearAllInputs( @@ -2194,14 +2191,14 @@ this.resetModes(); } const undeletableFiles = - Array.from(this.files_.values()).filter(file => !file.isDeletable); - if (undeletableFiles.length !== this.files_.size) { - this.files_ = new Map(undeletableFiles.map(file => [file.uuid, file])); - this.addedTabsIds_ = new Map(undeletableFiles.filter(file => file.tabId) - .map(file => [file.tabId!, file.uuid])); + Array.from(this.files.values()).filter(file => !file.isDeletable); + if (undeletableFiles.length !== this.files.size) { + this.files = new Map(undeletableFiles.map(file => [file.uuid, file])); + this.addedTabsIds = new Map(undeletableFiles.filter(file => file.tabId) + .map(file => [file.tabId!, file.uuid])); } // Reset files in set to match remaining files in carousel. - this.setPendingUploads([...this.files_.keys()]); + this.setPendingUploads([...this.files.keys()]); this.smartComposeInlineHint_ = ''; if (!querySubmitted) { // If the query was submitted, the searchbox handler will clear its own @@ -2215,7 +2212,7 @@ } clearInput() { - this.input_ = ''; + this.input = ''; this.lastQueriedInput_ = ''; this.$.matches.unselect(); if (!this.disableCaretColorAnimation) { @@ -2225,11 +2222,11 @@ } getInputText(): string { - return this.input_; + return this.input; } getNumOfFilesForTesting(): number { - return this.files_.size; + return this.files.size; } private selectFirstMatch() { @@ -2250,8 +2247,8 @@ } protected hasImageFiles_() { - return Array.from(this.files_.values()).some( - file => file.type.includes('image')); + return Array.from(this.files.values()) + .some(file => file.type.includes('image')); } // This function is called when backend starts a file upload flow, whether @@ -2259,9 +2256,9 @@ // contrasts with the workflows where the frontend starts a file upload flow // (`addFileContext_`). private onFileContextAdded_(file: ComposeboxFile) { - const newFiles = new Map(this.files_); + const newFiles = new Map(this.files); newFiles.set(file.uuid, file); - this.files_ = newFiles; + this.files = newFiles; this.addToPendingUploads_(file.uuid); } @@ -2275,29 +2272,29 @@ switch (error) { case ProcessFilesError.MAX_FILES_EXCEEDED: metric = ComposeboxFileValidationError.TOO_MANY_FILES; - this.errorMessage_ = this.i18n('maxFilesReachedError'); + this.errorMessage = this.i18n('maxFilesReachedError'); break; case ProcessFilesError.MAX_IMAGES_EXCEEDED: metric = ComposeboxFileValidationError.TOO_MANY_FILES; - this.errorMessage_ = this.i18n('maxImagesReachedError'); + this.errorMessage = this.i18n('maxImagesReachedError'); break; case ProcessFilesError.MAX_PDFS_EXCEEDED: metric = ComposeboxFileValidationError.TOO_MANY_FILES; - this.errorMessage_ = this.i18n('maxPdfsReachedError'); + this.errorMessage = this.i18n('maxPdfsReachedError'); break; case ProcessFilesError.FILE_EMPTY: metric = ComposeboxFileValidationError.FILE_EMPTY; - this.errorMessage_ = this.i18n('composeboxFileUploadInvalidEmptySize'); + this.errorMessage = this.i18n('composeboxFileUploadInvalidEmptySize'); break; case ProcessFilesError.FILE_TOO_LARGE: metric = ComposeboxFileValidationError.FILE_SIZE_TOO_LARGE; - this.errorMessage_ = this.i18n('composeboxFileUploadInvalidTooLarge'); + this.errorMessage = this.i18n('composeboxFileUploadInvalidTooLarge'); break; case ProcessFilesError.INVALID_TYPE: - this.errorMessage_ = this.i18n('composeFileTypesAllowedError'); + this.errorMessage = this.i18n('composeFileTypesAllowedError'); break; case ProcessFilesError.FILE_UPLOAD_NOT_ALLOWED: - this.errorMessage_ = this.i18n('composeboxFileUploadNotAllowed'); + this.errorMessage = this.i18n('composeboxFileUploadNotAllowed'); break; default: break; @@ -2311,18 +2308,14 @@ token: UnguessableToken, status: ContextUploadStatus, errorType: ContextUploadErrorType|null) { let errorMessage = null; - let file = this.files_.get(token); + let file = this.files.get(token); if (file) { - if ([ - ContextUploadStatus.kValidationFailed, - ContextUploadStatus.kUploadFailed, - ContextUploadStatus.kUploadExpired, - ContextUploadStatus.kUploadReplaced, - ].includes(status)) { - this.files_.delete(token); + if (isTerminalState(status) && + status !== ContextUploadStatus.kUploadSuccessful) { + this.files.delete(token); if (file.tabId) { - this.addedTabsIds_ = new Map([...this.addedTabsIds_.entries()].filter( + this.addedTabsIds = new Map([...this.addedTabsIds.entries()].filter( ([id, _]) => id !== file!.tabId)); } switch (status) { @@ -2355,9 +2348,9 @@ this.closeMenu_(); } else { file = {...file, status: status}; - this.files_.set(token, file); + this.files.set(token, file); } - this.files_ = new Map([...this.files_]); + this.files = new Map([...this.files]); } else { // File is unknown but its status is known. Show this if // ghost/unknown files in frontend are allowed to be in @@ -2392,7 +2385,7 @@ return; } - if (this.activeToolMode_ === ComposeboxToolMode.kDeepSearch) { + if (this.activeToolMode === ComposeboxToolMode.kDeepSearch) { this.handleProcessFilesError_(ProcessFilesError.FILE_UPLOAD_NOT_ALLOWED); return; } @@ -2405,16 +2398,16 @@ counts.set(InputType.kLensFile, 0); counts.set(InputType.kBrowserTab, 0); - for (const file of this.files_.values()) { + for (const file of this.files.values()) { const type = this.getInputType_(file.type); counts.set(type, (counts.get(type) || 0) + 1); } - let totalCount = this.files_.size; + let totalCount = this.files.size; let maxTotal = this.maxFileCount_; - if (this.inputState_ && this.inputState_.maxTotalInputs > 0) { - maxTotal = this.inputState_.maxTotalInputs; + if (this.inputState && this.inputState.maxTotalInputs > 0) { + maxTotal = this.inputState.maxTotalInputs; } if (totalCount + files.length > maxTotal) { @@ -2423,9 +2416,9 @@ for (const file of files) { const inputType = this.getInputType_(file.type); - if (this.inputState_ && - this.activeToolMode_ !== ComposeboxToolMode.kUnspecified) { - const disabledTypes = this.inputState_.disabledInputTypes || []; + if (this.inputState && + this.activeToolMode !== ComposeboxToolMode.kUnspecified) { + const disabledTypes = this.inputState.disabledInputTypes || []; if (disabledTypes.includes(inputType)) { errorToDisplay = Math.max(errorToDisplay, ProcessFilesError.INVALID_TYPE); @@ -2447,9 +2440,9 @@ } let maxType = maxTotal; - if (this.inputState_ && - this.inputState_.maxInstances[inputType] !== undefined) { - maxType = this.inputState_.maxInstances[inputType]; + if (this.inputState && + this.inputState.maxInstances[inputType] !== undefined) { + maxType = this.inputState.maxInstances[inputType]; } const currentTypeCount = counts.get(inputType) || 0; @@ -2505,7 +2498,7 @@ this.handleProcessFilesError_(ProcessFilesError.INVALID_TYPE); return; } - const pendingStatus = this.files_.get(fileAttachment.uuid)?.status; + const pendingStatus = this.files.get(fileAttachment.uuid)?.status; const composeboxFile = ComposeboxFile.createFromFile( fileAttachment.uuid as unknown as UnguessableToken, {name: fileAttachment.name, type: fileAttachment.mimeType},
diff --git a/ui/webui/resources/cr_components/composebox/composebox_context_menu.html.ts b/ui/webui/resources/cr_components/composebox/composebox_context_menu.html.ts index c1b6864e..a0b74869 100644 --- a/ui/webui/resources/cr_components/composebox/composebox_context_menu.html.ts +++ b/ui/webui/resources/cr_components/composebox/composebox_context_menu.html.ts
@@ -29,14 +29,14 @@ @context-menu-closed="${this.onContextMenuClosed_ }" @context-menu-opened="${this.onContextMenuOpened_}" .showModelPicker="${this.showModelPicker_}" - .inputState="${this.inputState_}" + .inputState="${this.inputState}" .searchboxLayoutMode="${this.searchboxLayoutMode}" .tabSuggestions="${this.tabSuggestions_}" .inCreateImageMode="${ - this.activeToolMode_ === ComposeboxToolMode.kImageGen}" + this.activeToolMode === ComposeboxToolMode.kImageGen}" .hasImageFiles="${this.hasImageFiles_()}" - .disabledTabIds="${this.addedTabsIds_}" - .fileNum="${this.files_.size}" + .disabledTabIds="${this.addedTabsIds}" + .fileNum="${this.files.size}" ?upload-button-disabled="${this.uploadButtonDisabled_}" ?show-context-menu-description="${this.showContextMenuDescription_}"> </cr-composebox-contextual-entrypoint-and-menu> @@ -46,7 +46,7 @@ part="composebox-entrypoint" exportparts="context-menu-entrypoint-icon" class="upload-button no-overlap" - .inputState="${this.inputState_}" + .inputState="${this.inputState}" ?upload-button-disabled="${this.uploadButtonDisabled_}" ?show-context-menu-description="${this.showContextMenuDescription_}"> </cr-composebox-contextual-entrypoint-button> @@ -62,7 +62,7 @@ ${this.inToolMode_ ? html` <cr-composebox-tool-chip exportparts="tool-chip-label" - .inputState="${this.inputState_}" + .inputState="${this.inputState}" @tool-click="${this.onToolClick_}"> </cr-composebox-tool-chip> ` : ''}
diff --git a/ui/webui/resources/cr_components/composebox/composebox_mixin.ts b/ui/webui/resources/cr_components/composebox/composebox_mixin.ts new file mode 100644 index 0000000..a4babc4 --- /dev/null +++ b/ui/webui/resources/cr_components/composebox/composebox_mixin.ts
@@ -0,0 +1,54 @@ +// Copyright 2026 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import {loadTimeData} from '//resources/js/load_time_data.js'; +import type {CrLitElement} from '//resources/lit/v3_0/lit.rollup.js'; +import type {UnguessableToken} from '//resources/mojo/mojo/public/mojom/base/unguessable_token.mojom-webui.js'; + +import type {ComposeboxFile} from './common.js'; +import {ToolMode as ComposeboxToolMode} from './composebox_query.mojom-webui.js'; +import type {InputState} from './composebox_query.mojom-webui.js'; + +type Constructor<T> = new (...args: any[]) => T; + +export const ComposeboxEmbedderMixin = + <T extends Constructor<CrLitElement>>(superClass: T): T& + Constructor<ComposeboxEmbedderMixinInterface> => { + class ComposeboxEmbedderMixin extends superClass implements + ComposeboxEmbedderMixinInterface { + static get properties() { + return { + activeToolMode: {type: Number, reflect: true}, + addedTabsIds: {type: Object}, + errorMessage: {type: String}, + files: {type: Object}, + input: {type: String}, + inputPlaceholder: {type: String, reflect: true}, + inputState: {type: Object}, + }; + } + + accessor activeToolMode: ComposeboxToolMode = + ComposeboxToolMode.kUnspecified; + accessor addedTabsIds: Map<number, UnguessableToken> = new Map(); + accessor errorMessage: string = ''; + accessor files: Map<UnguessableToken, ComposeboxFile> = new Map(); + accessor input: string = ''; + accessor inputPlaceholder: string = + loadTimeData.getString('searchboxComposePlaceholder'); + accessor inputState: InputState|null = null; + } + + return ComposeboxEmbedderMixin; + }; + +export interface ComposeboxEmbedderMixinInterface { + activeToolMode: ComposeboxToolMode; + addedTabsIds: Map<number, UnguessableToken>; + errorMessage: string; + files: Map<UnguessableToken, ComposeboxFile>; + input: string; + inputPlaceholder: string; + inputState: InputState|null; +}
diff --git a/ui/webui/resources/cr_components/composebox/composebox_shared_style.css b/ui/webui/resources/cr_components/composebox/composebox_shared_style.css index b31d6605f..d16a1821 100644 --- a/ui/webui/resources/cr_components/composebox/composebox_shared_style.css +++ b/ui/webui/resources/cr_components/composebox/composebox_shared_style.css
@@ -13,7 +13,6 @@ display: flex; gap: 4px; margin-bottom: var(--contextual-entrypoint-and-carousel-context-menu-container-margin-bottom); - min-height: var(--cr-icon-button-size); padding-inline-start: var(--contextual-entrypoint-and-carousel-context-menu-container-padding-inline-start, 4px); flex-wrap: nowrap; }
diff --git a/ui/webui/resources/cr_components/composebox/file_carousel.ts b/ui/webui/resources/cr_components/composebox/file_carousel.ts index 95f08ed..97e9888 100644 --- a/ui/webui/resources/cr_components/composebox/file_carousel.ts +++ b/ui/webui/resources/cr_components/composebox/file_carousel.ts
@@ -3,7 +3,8 @@ // found in the LICENSE file. import './file_thumbnail.js'; -import {CrLitElement, type PropertyValues} from '//resources/lit/v3_0/lit.rollup.js'; +import {CrLitElement} from '//resources/lit/v3_0/lit.rollup.js'; +import type {PropertyValues} from '//resources/lit/v3_0/lit.rollup.js'; import type {UnguessableToken} from '//resources/mojo/mojo/public/mojom/base/unguessable_token.mojom-webui.js'; import type {ComposeboxFile} from './common.js';
diff --git a/ui/webui/resources/cr_components/searchbox/searchbox.ts b/ui/webui/resources/cr_components/searchbox/searchbox.ts index 6b7c7f5..423058b 100644 --- a/ui/webui/resources/cr_components/searchbox/searchbox.ts +++ b/ui/webui/resources/cr_components/searchbox/searchbox.ts
@@ -416,8 +416,11 @@ waitForLazyRender().then(async () => { const {config} = await this.pageHandler_.getPlaceholderConfig(); const texts = config.texts; - assert(texts[0]); - this.placeholderText = texts[0]; + if (texts.length === 0) { + // PEC API returned no placeholders; feature is disabled. + return; + } + this.placeholderText = texts[0]!; this.placeholderCycler_ = new PlaceholderTextCycler( this.$.input.inputElement, texts, Number(config.changeTextAnimationInterval.microseconds / 1000n), @@ -438,11 +441,6 @@ return matches; } - // Deprecated. Use `getDropDownElement`. - getSuggestionsElement(): SearchboxDropdownElement { - return this.getDropdownElement(); - } - override getWrapperElement(): HTMLElement { return this.$.inputWrapper; }
diff --git a/ui/webui/resources/tools/eslint/lit_element_bindings.js b/ui/webui/resources/tools/eslint/lit_element_bindings.js index 12641e9..021d48de 100644 --- a/ui/webui/resources/tools/eslint/lit_element_bindings.js +++ b/ui/webui/resources/tools/eslint/lit_element_bindings.js
@@ -24,6 +24,10 @@ 'Incorrect assignment to property \'{{propertyName}}\' using attribute expression \'{{attributeExpression}}\'. Object/Array Lit properties can only be initialized with property expressions. Change to \'{{propertyExpression}}\' instead, or update the property\'s type if Object/Array is not accurate.', incorrectBooleanBinding: 'Incorrect assignment to property \'{{propertyName}}\' using boolean attribute expression \'{{attributeExpression}}\'. Boolean attribute expressions should only be assigned to boolean properties. To bind to the truthiness of \'{{propertyName}}\', convert it to a boolean using \'!!\'.', + noTrueBinding: + 'Boolean attribute \'{{attributeName}}\' does not need to be bound to \'${true}\'. Use either \'{{attributeName}}\' or \'.{{propertyName}}="${true}"\' instead.', + noFalseBinding: + 'Incorrect assignment to boolean attribute expression \'?{{attributeName}}=\' using \'${false}\'. Use property binding \'.{{propertyName}}="${false}"\' instead.', }, }, defaultOptions: [], @@ -97,11 +101,30 @@ continue; } - if (node.expressions[i].type !== 'MemberExpression') { + const expression = node.expressions[i]; + if (!expression) { continue; } - const propName = node.expressions[i].property.name; + if (expression.type === 'Literal' && !!match.groups['boolName'] && + (expression.value === true || expression.value === false)) { + const boolName = match.groups['boolName']; + context.report({ + node: expression, + messageId: expression.value ? 'noTrueBinding' : 'noFalseBinding', + data: { + attributeName: boolName, + propertyName: dashCaseToCamelCase(boolName), + }, + }); + continue; + } + + if (expression.type !== 'MemberExpression') { + continue; + } + + const propName = expression.property.name; const declaredProp = declaredProps.find(prop => prop.key.name === propName); if (!declaredProp) { @@ -115,7 +138,7 @@ if (!!match.groups['boolName'] && declaredType.value.name !== 'Boolean') { context.report({ - node: node.expressions[i], + node: expression, messageId: 'incorrectBooleanBinding', data: { attributeExpression: `?${match.groups['boolName']}=`, @@ -129,7 +152,7 @@ declaredType.value.name === 'Object') { const attrName = match.groups['attrName']; context.report({ - node: node.expressions[i], + node: expression, messageId: 'incorrectAttributeBinding', data: { attributeExpression: `${attrName}=`,
diff --git a/ui/webui/resources/tools/eslint_ts_test.py b/ui/webui/resources/tools/eslint_ts_test.py index 046b257..5fe8f5e1 100755 --- a/ui/webui/resources/tools/eslint_ts_test.py +++ b/ui/webui/resources/tools/eslint_ts_test.py
@@ -644,6 +644,10 @@ _INCORRECT_BOOLEAN_ERROR = "Incorrect assignment to property '%(propertyName)s' using boolean attribute expression '?%(attributeName)s='. Boolean attribute expressions should only be assigned to boolean properties. To bind to the truthiness of '%(propertyName)s', convert it to a boolean using '!!'" + _NO_TRUE_BINDING_ERROR = "Boolean attribute '%(attributeName)s' does not need to be bound to '${true}'. Use either '%(attributeName)s' or '.%(propertyName)s=\"${true}\"' instead" + + _NO_FALSE_BINDING_ERROR = "Incorrect assignment to boolean attribute expression '?%(attributeName)s=' using '${false}'. Use property binding '.%(propertyName)s=\"${false}\"' instead" + # The following strings *should* appear in the error output. errors = [ _INCORRECT_ATTRIBUTE_ERROR % { @@ -660,6 +664,18 @@ 'attributeName': 'invalid', 'propertyName': 'errorMessage', }, + _NO_TRUE_BINDING_ERROR % { + 'attributeName': 'readonly', + 'propertyName': 'readonly', + }, + _NO_FALSE_BINDING_ERROR % { + 'attributeName': 'disabled', + 'propertyName': 'disabled', + }, + _NO_FALSE_BINDING_ERROR % { + 'attributeName': 'some-multi-word-attr', + 'propertyName': 'someMultiWordAttr', + }, ] for e in errors: self.assertTrue(
diff --git a/ui/webui/resources/tools/tests/eslint_ts/with_webui_plugin_lit_element_bindings_violations.html.ts b/ui/webui/resources/tools/tests/eslint_ts/with_webui_plugin_lit_element_bindings_violations.html.ts index 49ad4331..163c69d 100644 --- a/ui/webui/resources/tools/tests/eslint_ts/with_webui_plugin_lit_element_bindings_violations.html.ts +++ b/ui/webui/resources/tools/tests/eslint_ts/with_webui_plugin_lit_element_bindings_violations.html.ts
@@ -13,7 +13,8 @@ aria-description="${this.description}" ?disabled="${this.disabled}" error-message="${this.errorMessage}" min="${this.limits.min}" max="${this.limits.max}" - ?invalid="${this.errorMessage}"> + ?invalid="${this.errorMessage}" ?readonly="${true}" + ?disabled="${false}" ?some-multi-word-attr="${false}"> </cr-input> `; }
diff --git a/v8 b/v8 index 13f57cb..bd829db 160000 --- a/v8 +++ b/v8
@@ -1 +1 @@ -Subproject commit 13f57cb4f1c0a5d04345d42ce3bfadb5c71d3b4e +Subproject commit bd829db3f269af2aeb5f080d1ed0a96c6d2eb235