diff --git a/DEPS b/DEPS index 30d68a2..276f01b 100644 --- a/DEPS +++ b/DEPS
@@ -328,7 +328,7 @@ # 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': '80b4ac89a93da6906d7d7ab93d08bb36b84b8bf6', + 'angle_revision': '3cd478b595cb98a6f1283876aadea5fc0a9543f8', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. @@ -340,7 +340,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling BoringSSL # and whatever else without interference from each other. - 'boringssl_revision': '6474716769bcf85be5509b728af82a988f26fb2e', + 'boringssl_revision': '950495856681c75e929963673dff12351378af60', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Fuchsia sdk # and whatever else without interference from each other. @@ -380,7 +380,7 @@ # 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': '50443e9356593c8a1ac9f18bc6a66378cdc8810d', + 'crossbench_revision': '7e536e3a169d2862d9cde1633829d9aba5e137f5', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling CrossBench # 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': 'd71632604eea6ff3492da15af59ffe3ea201399b', + 'devtools_frontend_revision': '8c8963f2e817337256efa9d06b79abbc257887fc', # 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,7 +424,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'dawn_revision': '1fa8f21027a55087ded8e9c0d5fef8ab74b39924', + 'dawn_revision': '5326a2acd1a0bc04637e3618b2095894ba97f3bd', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -532,11 +532,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling clusterfuzz-data # and whatever else without interference from each other. - 'clusterfuzz_data_revision':'16291853b71303fe621459f0c280e2ba1257d529', + 'clusterfuzz_data_revision':'96aa078abb0c3d3ba923776bd47f489e4e675a35', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling agents-internal # and whatever else without interference from each other. - 'agents_internal_revision': 'f86c3fa19ff5bea2f05c5478207636fbc700a43c', + 'agents_internal_revision': 'eda60a5a7e6373fb28f76d984b070f92bc1d8e80', # If you change this, also update the libc++ revision in # //buildtools/deps_revisions.gni. @@ -1446,7 +1446,7 @@ 'packages': [ { 'package': 'chromium/third_party/updater/chromium_win_arm64', - 'version': 'version:2@1620014', + 'version': 'version:2@1621011', }, ], }, @@ -1468,7 +1468,7 @@ 'packages': [ { 'package': 'chromium/third_party/updater/chromium_win_x86_64', - 'version': 'version:2@1620002', + 'version': 'version:2@1621004', }, ], }, @@ -1660,12 +1660,12 @@ 'src/clank': { 'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' + - '4a1e60d516065bfec4001af37a85676174ece923', + '5683fd1a4e5efcee66a6c524d3a100ff831280f3', 'condition': 'checkout_android and checkout_src_internal', }, 'src/docs/website': { - 'url': Var('chromium_git') + '/website.git' + '@' + 'adf532f7c299a1f849f0310446669bcaf3816230', + 'url': Var('chromium_git') + '/website.git' + '@' + '81a7ea93897de0f405c0105c06e94b2c7d8f9b34', }, 'src/ios/third_party/earl_grey2/src': { @@ -2390,7 +2390,7 @@ Var('chromium_git') + '/external/libaddressinput.git' + '@' + 'e20690c8d5178bb282641d5eb06ef0298ff4cbc5', 'src/third_party/libaom/source/libaom': - Var('aomedia_git') + '/aom.git' + '@' + 'e86de95f799ebfe82db8b279bfb1386d4f74ab1d', + Var('aomedia_git') + '/aom.git' + '@' + 'e67178f5ef15f7568be9f1e162a32b643c6bbd72', 'src/third_party/crabbyavif/src': Var('chromium_git') + '/external/github.com/webmproject/CrabbyAvif.git' + '@' + Var('crabbyavif_revision'), @@ -2504,7 +2504,7 @@ Var('chromium_git') + '/chromiumos/platform/libva-fake-driver.git' + '@' + 'a9bcab9cd6b15d4e3634ca44d5e5f7652c612194', 'src/third_party/libvpx/source/libvpx': - Var('chromium_git') + '/webm/libvpx.git' + '@' + '640d4ce27ba918783e28a0da46a8a37abe4a65b6', + Var('chromium_git') + '/webm/libvpx.git' + '@' + '76b08021715417b48f01713c6100f86d9b7ab450', 'src/third_party/libwebm/source': Var('chromium_git') + '/webm/libwebm.git' + '@' + '6184f4484a826724b5293837134ab9492261b941', @@ -2647,7 +2647,7 @@ Var('pdfium_git') + '/pdfium.git' + '@' + Var('pdfium_revision'), 'src/third_party/perfetto': - Var('chromium_git') + '/external/github.com/google/perfetto.git' + '@' + 'c9f7b8a8e0f461dd8335af67ae9e097622d47152', + Var('chromium_git') + '/external/github.com/google/perfetto.git' + '@' + '08617935301242fb7a9cb649ed65f035dcaf04f9', 'src/base/tracing/test/data': { 'bucket': 'perfetto', @@ -3040,7 +3040,7 @@ Var('chromium_git') + '/webpagereplay.git' + '@' + Var('webpagereplay_revision'), 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '125a9d22b0edd885012a492fcb2fb2d795e5a106', + Var('webrtc_git') + '/src.git' + '@' + 'f9c143a1b1a960b179f63eea1e511d1871a91b00', # 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. @@ -3761,7 +3761,7 @@ 'src/components/optimization_guide/internal': { 'url': Var('chrome_git') + '/chrome/components/optimization_guide.git' + '@' + - '5f94267a383c538ef982fce8044811c5a6cc33aa', + '41b8d85727afeb00dbf4bad0f040b0e4e1374ec3', 'condition': 'checkout_src_internal', },
diff --git a/WATCHLISTS b/WATCHLISTS index 63a56fcb..4141d96 100644 --- a/WATCHLISTS +++ b/WATCHLISTS
@@ -1930,13 +1930,6 @@ 'plugin_metadata': { 'filepath': 'chrome/browser/resources/plugin_metadata/' }, - 'plus_addresses': { - 'filepath': 'components/plus_addresses/'\ - '|chrome/browser/plus_addresses/'\ - '|chrome/browser/ui/plus_addresses/'\ - '|components/plus_addresses_strings_grdp/'\ - '|ios/chrome/browser/plus_addresses/' - }, 'popup_blocker': { 'filepath': 'chrome/browser/ui/blocked_content' }, @@ -3248,8 +3241,6 @@ 'pushi+watch-phonehub@google.com'], 'picture_in_picture': ['beaufort.francois+pip@gmail.com'], 'plugin_metadata': ['wfh+watch@chromium.org'], - 'plus_addresses': ['mreichhoff+watch-plus_addresses@chromium.org', - 'jkeitel+watch-plus_addresses@google.com'], 'popup_blocker': ['csharrison+watch-popups@chromium.org'], 'precache': ['wifiprefetch-reviews@google.com'], 'prefetch_proxy': ['marcinjb+p4watch@google.com',
diff --git a/agents/internal b/agents/internal index f86c3fa..eda60a5 160000 --- a/agents/internal +++ b/agents/internal
@@ -1 +1 @@ -Subproject commit f86c3fa19ff5bea2f05c5478207636fbc700a43c +Subproject commit eda60a5a7e6373fb28f76d984b070f92bc1d8e80
diff --git a/android_webview/glue/java/src/com/android/webview/chromium/SharedWebViewChromium.java b/android_webview/glue/java/src/com/android/webview/chromium/SharedWebViewChromium.java index 54d4289..bf2db8a 100644 --- a/android_webview/glue/java/src/com/android/webview/chromium/SharedWebViewChromium.java +++ b/android_webview/glue/java/src/com/android/webview/chromium/SharedWebViewChromium.java
@@ -286,6 +286,7 @@ } public AwContents getAwContents() { + mAwInit.triggerAndWaitForChromiumStarted(CallSite.WEBVIEW_INSTANCE_GET_AW_CONTENTS); return mAwContents; }
diff --git a/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumAwInit.java b/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumAwInit.java index 865b761..2bb9446 100644 --- a/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumAwInit.java +++ b/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumAwInit.java
@@ -372,6 +372,7 @@ CallSite.GET_DEFAULT_COOKIE_MANAGER, CallSite.GET_PROFILE_STORE, CallSite.WEBVIEW_INSTANCE_GET_SETTINGS, + CallSite.WEBVIEW_INSTANCE_GET_AW_CONTENTS, CallSite.COUNT, }) public @interface CallSite { @@ -485,8 +486,9 @@ int GET_DEFAULT_COOKIE_MANAGER = 107; int GET_PROFILE_STORE = 108; int WEBVIEW_INSTANCE_GET_SETTINGS = 109; + int WEBVIEW_INSTANCE_GET_AW_CONTENTS = 110; // Remember to update WebViewStartupCallSite in enums.xml when adding new values here. - int COUNT = 110; + int COUNT = 111; }; // LINT.ThenChange(//tools/metrics/histograms/metadata/android/enums.xml:WebViewStartupCallSite)
diff --git a/ash/app_list/views/search_box_view.cc b/ash/app_list/views/search_box_view.cc index aaaebab..859e894 100644 --- a/ash/app_list/views/search_box_view.cc +++ b/ash/app_list/views/search_box_view.cc
@@ -51,7 +51,6 @@ #include "base/i18n/case_conversion.h" #include "base/i18n/rtl.h" #include "base/metrics/histogram_functions.h" -#include "base/metrics/histogram_macros.h" #include "base/metrics/user_metrics.h" #include "base/notreached.h" #include "base/rand_util.h" @@ -650,12 +649,8 @@ ResetHighlightRange(); if (initiated_by_user) { - const base::TimeTicks current_time = base::TimeTicks::Now(); if (current_query_.empty() && !query.empty()) { base::RecordAction(base::UserMetricsAction("AppList_SearchQueryStarted")); - // Set 'user_initiated_model_update_time_' when initiating a new query. - user_initiated_model_update_time_ = current_time; - if (features::IsWelcomeTourEnabled()) { welcome_tour_metrics::RecordInteraction( user_education_util::GetLastActiveUserPrefService(), @@ -663,18 +658,6 @@ } } else if (!current_query_.empty() && query.empty()) { base::RecordAction(base::UserMetricsAction("AppList_LeaveSearch")); - // Reset 'user_initiated_model_update_time_' when clearing the search_box. - user_initiated_model_update_time_ = base::TimeTicks(); - } else if (query != current_query_ && - !user_initiated_model_update_time_.is_null()) { - if (is_app_list_bubble_) { - UMA_HISTOGRAM_TIMES("Ash.SearchModelUpdateTime.ClamshellMode", - current_time - user_initiated_model_update_time_); - } else { - UMA_HISTOGRAM_TIMES("Ash.SearchModelUpdateTime.TabletMode", - current_time - user_initiated_model_update_time_); - } - user_initiated_model_update_time_ = current_time; } }
diff --git a/ash/app_list/views/search_box_view.h b/ash/app_list/views/search_box_view.h index 0a194f2..caea995 100644 --- a/ash/app_list/views/search_box_view.h +++ b/ash/app_list/views/search_box_view.h
@@ -334,11 +334,6 @@ raw_ptr<ResultSelectionController, DanglingUntriaged> result_selection_controller_ = nullptr; - // The timestamp taken when the search box model's query is updated by the - // user. Used in metrics. Metrics are only recorded for search model updates - // that occur after a search has been initiated. - base::TimeTicks user_initiated_model_update_time_; - // If true, `SelectPlaceholderText()` always returns a fixed placeholder text // instead of the one picked randomly. bool use_fixed_placeholder_text_for_test_ = false;
diff --git a/ash/user_education/views/help_bubble_view_ash.cc b/ash/user_education/views/help_bubble_view_ash.cc index c39fb8bc..3b9f3fe 100644 --- a/ash/user_education/views/help_bubble_view_ash.cc +++ b/ash/user_education/views/help_bubble_view_ash.cc
@@ -664,11 +664,10 @@ auto bubble = base::WrapUnique(new HelpBubbleViewAsh(id, anchor, std::move(params))); auto* const bubble_ptr = bubble.get(); - auto* const widget = views::BubbleDialogDelegateView::CreateBubble( - std::move(bubble), views::Widget::InitParams::CLIENT_OWNS_WIDGET); + std::unique_ptr<views::Widget> widget = + views::BubbleDialogDelegate::CreateBubble(std::move(bubble)); bubble_ptr->InitializeAndShow(); - return user_education::HelpBubbleViewInfo(base::WrapUnique(widget), - bubble_ptr); + return user_education::HelpBubbleViewInfo(std::move(widget), bubble_ptr); } void HelpBubbleViewAsh::InitializeAndShow() {
diff --git a/ash/webui/boca_ui/boca_app_page_handler.cc b/ash/webui/boca_ui/boca_app_page_handler.cc index fcc58ef..0a7ed64 100644 --- a/ash/webui/boca_ui/boca_app_page_handler.cc +++ b/ash/webui/boca_ui/boca_app_page_handler.cc
@@ -15,6 +15,7 @@ #include "ash/session/session_controller_impl.h" #include "ash/shell.h" #include "ash/webui/boca_ui/boca_util.h" +#include "ash/webui/boca_ui/mojom/boca.mojom-shared.h" #include "ash/webui/boca_ui/mojom/boca.mojom.h" #include "ash/webui/boca_ui/provider/classroom_page_handler_impl.h" #include "ash/webui/boca_ui/provider/content_settings_handler.h" @@ -89,6 +90,28 @@ return receiver_name ? *receiver_name : ""; } +std::optional<mojom::UrlType> ConvertUrlTypeProtoToMojom( + ::boca::UrlType url_type_proto) { + switch (url_type_proto) { + case ::boca::URL_TYPE_GEMINI_REGULAR: + return mojom::UrlType::kGeminiRegular; + case ::boca::URL_TYPE_GEMINI_GUIDED_LEARNING: + return mojom::UrlType::kGeminiGuidedLearning; + default: + return std::nullopt; + } +} + +::boca::UrlType ConvertUrlTypeMojomToProto(mojom::UrlType url_type) { + switch (url_type) { + case mojom::UrlType::kGeminiRegular: + return ::boca::URL_TYPE_GEMINI_REGULAR; + case mojom::UrlType::kGeminiGuidedLearning: + return ::boca::URL_TYPE_GEMINI_GUIDED_LEARNING; + } + return ::boca::URL_TYPE_UNSPECIFIED; +} + std::unique_ptr<::boca::OnTaskConfig> OnTaskConfigMojomToProto( const mojom::OnTaskConfigPtr& config) { auto on_task_config = std::make_unique<::boca::OnTaskConfig>(); @@ -103,6 +126,10 @@ content_config->set_favicon_url(item->tab->favicon.spec()); content_config->mutable_locked_navigation_options()->set_navigation_type( ::boca::LockedNavigationOptions::NavigationType(item->navigation_type)); + if (item->tab->url_type.has_value()) { + content_config->set_url_type( + ConvertUrlTypeMojomToProto(item->tab->url_type.value())); + } } return on_task_config; } @@ -159,7 +186,8 @@ for (auto tab : session_on_task_config.active_bundle().content_configs()) { tabs.push_back(mojom::ControlledTab::New( mojom::TabInfo::New(std::nullopt, tab.title(), GURL(tab.url()), - GURL(tab.favicon_url())), + GURL(tab.favicon_url()), + ConvertUrlTypeProtoToMojom(tab.url_type())), mojom::NavigationType( tab.locked_navigation_options().navigation_type()))); }
diff --git a/ash/webui/boca_ui/boca_app_page_handler_unittest.cc b/ash/webui/boca_ui/boca_app_page_handler_unittest.cc index 3c8a80f..abd8a534 100644 --- a/ash/webui/boca_ui/boca_app_page_handler_unittest.cc +++ b/ash/webui/boca_ui/boca_app_page_handler_unittest.cc
@@ -19,6 +19,7 @@ #include "ash/test/ash_test_base.h" #include "ash/webui/annotator/test/mock_annotator_client.h" #include "ash/webui/boca_ui/boca_util.h" +#include "ash/webui/boca_ui/mojom/boca.mojom-shared.h" #include "ash/webui/boca_ui/mojom/boca.mojom.h" #include "base/functional/bind.h" #include "base/functional/callback.h" @@ -141,11 +142,11 @@ std::vector<mojom::ControlledTabPtr> tabs; tabs.push_back(mojom::ControlledTab::New( mojom::TabInfo::New(1, "google", GURL("http://google.com/"), - GURL("http://data/image")), + GURL("http://data/image"), /*url_type=*/std::nullopt), /*navigation_type=*/mojom::NavigationType::kOpen)); tabs.push_back(mojom::ControlledTab::New( mojom::TabInfo::New(2, "youtube", GURL("http://youtube.com/"), - GURL("http://data/image")), + GURL("http://data/image"), /*url_type=*/std::nullopt), /*navigation_type=*/mojom::NavigationType::kBlock)); return mojom::OnTaskConfig::New(/*is_locked=*/true, /*is_paused=*/true, std::move(tabs)); @@ -155,12 +156,28 @@ std::vector<mojom::ControlledTabPtr> tabs; tabs.push_back(mojom::ControlledTab::New( mojom::TabInfo::New(1, "google", GURL("http://google.com/"), - GURL("http://data/image")), + GURL("http://data/image"), /*url_type=*/std::nullopt), /*navigation_type=*/mojom::NavigationType::kOpen)); return mojom::OnTaskConfig::New(/*is_locked=*/false, /*is_paused=*/false, std::move(tabs)); } +mojom::OnTaskConfigPtr GetCommonOnTaskConfigWithUrlType( + mojom::UrlType url_type) { + std::vector<mojom::ControlledTabPtr> tabs; + tabs.push_back(mojom::ControlledTab::New( + mojom::TabInfo::New(1, "google", GURL("http://google.com/"), + /*favicon=*/GURL("http://data/image"), + /*url_type=*/std::nullopt), + /*navigation_type=*/mojom::NavigationType::kOpen)); + tabs.push_back(mojom::ControlledTab::New( + mojom::TabInfo::New(2, "Special Url", GURL("http://specialurl.com/"), + /*favicon=*/GURL("http://data/image"), url_type), + /*navigation_type=*/mojom::NavigationType::kBlock)); + return mojom::OnTaskConfig::New(/*is_locked=*/true, /*is_paused=*/true, + std::move(tabs)); +} + ::boca::OnTaskConfig GetCommonTestLockOnTaskConfigProto() { ::boca::OnTaskConfig on_task_config; auto* active_bundle = on_task_config.mutable_active_bundle(); @@ -3736,5 +3753,161 @@ EXPECT_FALSE(annotator_tray()->visible_preferred()); } +struct UrlTypeTestParam { + std::string test_name; + mojom::UrlType mojom_type; + ::boca::UrlType proto_type; +}; + +class BocaAppPageHandlerProducerUrlTypeTest + : public BocaAppPageHandlerProducerTest, + public testing::WithParamInterface<UrlTypeTestParam> { + protected: + ::boca::SessionConfig GetSessionConfigWithUrlType( + ::boca::UrlType url_type_proto) { + ::boca::SessionConfig session_config; + auto* active_bundle = + session_config.mutable_on_task_config()->mutable_active_bundle(); + active_bundle->set_locked(true); + active_bundle->set_lock_to_app_home(true); + + auto* content = active_bundle->mutable_content_configs()->Add(); + content->set_url("http://google.com/"); + content->set_title("google"); + content->set_favicon_url("http://data/image"); + content->mutable_locked_navigation_options()->set_navigation_type( + ::boca::LockedNavigationOptions_NavigationType_OPEN_NAVIGATION); + + auto* special_content = active_bundle->mutable_content_configs()->Add(); + special_content->set_url("http://specialurl.com/"); + special_content->set_title("Special Url"); + special_content->set_favicon_url("http://data/image"); + special_content->mutable_locked_navigation_options()->set_navigation_type( + ::boca::LockedNavigationOptions_NavigationType_BLOCK_NAVIGATION); + special_content->set_url_type(url_type_proto); + return session_config; + } +}; + +TEST_P(BocaAppPageHandlerProducerUrlTypeTest, CreateSession) { + std::optional<::boca::OnTaskConfig> actual_on_task_config; + base::test::TestFuture<std::optional<mojom::CreateSessionError>> test_future; + auto session_duration = base::Minutes(2); + const auto config = mojom::Config::New( + session_duration, std::nullopt, nullptr, + std::vector<mojom::IdentityPtr>{}, std::vector<mojom::IdentityPtr>{}, + GetCommonOnTaskConfigWithUrlType(GetParam().mojom_type), + mojom::CaptionConfigPtr(nullptr), ""); + + EXPECT_CALL(*session_client_impl(), CreateSession(_)) + .WillOnce(WithArg<0>([&](std::unique_ptr<CreateSessionRequest> request) { + actual_on_task_config = *request->on_task_config(); + request->callback().Run(std::make_unique<::boca::Session>()); + })); + + EXPECT_CALL(*session_manager(), + UpdateCurrentSession(_, /*dispatch_event=*/true)) + .Times(1); + EXPECT_CALL(*session_manager(), disabled_on_non_managed_network()) + .WillOnce(Return(false)); + + boca_app_handler()->CreateSession(config.Clone(), test_future.GetCallback()); + ASSERT_TRUE(test_future.Wait()); + ASSERT_TRUE(actual_on_task_config.has_value()); + ASSERT_EQ(actual_on_task_config->active_bundle().content_configs_size(), 2); + EXPECT_EQ( + actual_on_task_config->active_bundle().content_configs(1).url_type(), + GetParam().proto_type); +} + +TEST_P(BocaAppPageHandlerProducerUrlTypeTest, UpdateOnTaskConfig) { + std::optional<::boca::OnTaskConfig> actual_on_task_config; + auto session = GetCommonActiveSessionProto(); + EXPECT_CALL(*session_manager(), + UpdateCurrentSession(_, /*dispatch_event=*/true)) + .Times(1); + EXPECT_CALL(*session_manager(), GetCurrentSession()) + .WillRepeatedly(Return(&session)); + base::test::TestFuture<std::optional<mojom::UpdateSessionError>> test_future; + + EXPECT_CALL(*session_client_impl(), UpdateSession(_)) + .WillOnce(WithArg<0>([&](std::unique_ptr<UpdateSessionRequest> request) { + actual_on_task_config = *request->on_task_config(); + request->callback().Run( + std::make_unique<::boca::Session>(GetCommonActiveSessionProto())); + })); + boca_app_handler()->UpdateOnTaskConfig( + GetCommonOnTaskConfigWithUrlType(GetParam().mojom_type), + test_future.GetCallback()); + + ASSERT_TRUE(test_future.Wait()); + ASSERT_TRUE(actual_on_task_config.has_value()); + ASSERT_EQ(actual_on_task_config->active_bundle().content_configs_size(), 2); + EXPECT_EQ( + actual_on_task_config->active_bundle().content_configs(1).url_type(), + GetParam().proto_type); +} + +TEST_P(BocaAppPageHandlerProducerUrlTypeTest, GetSession) { + base::test::TestFuture<mojom::SessionResultPtr> test_future; + EXPECT_CALL(*session_client_impl(), + GetSession(_, /*can_skip_duplicate_request=*/false)) + .WillOnce(WithArg<0>([&](auto request) { + auto session = std::make_unique<::boca::Session>(); + session->set_session_state(::boca::Session::ACTIVE); + session->mutable_student_group_configs()->insert( + {kMainStudentGroupName, + GetSessionConfigWithUrlType(GetParam().proto_type)}); + request->callback().Run(std::move(session)); + })); + + EXPECT_CALL(*session_manager(), + UpdateCurrentSession(NotNull(), /*dispatch_event=*/true)) + .Times(1); + EXPECT_CALL(*session_manager(), disabled_on_non_managed_network()) + .WillOnce(Return(false)); + + boca_app_handler()->GetSession(test_future.GetCallback()); + + auto result = std::move(test_future.Take()->get_session()->config); + ASSERT_EQ(result->on_task_config->tabs.size(), 2u); + EXPECT_EQ(result->on_task_config->tabs[1]->tab->url_type, + GetParam().mojom_type); +} + +TEST_P(BocaAppPageHandlerProducerUrlTypeTest, OnSessionConfigUpdated) { + ::boca::Session session; + session.set_session_state(::boca::Session::ACTIVE); + session.mutable_student_group_configs()->insert( + {kMainStudentGroupName, + GetSessionConfigWithUrlType(GetParam().proto_type)}); + EXPECT_CALL(*session_manager(), GetCurrentSession()) + .WillOnce(Return(&session)); + base::test::TestFuture<mojom::ConfigResultPtr> future; + fake_page()->SetSessionConfigInterceptorCallback(future.GetCallback()); + + boca_app_handler()->OnSessionStarted(std::string(), ::boca::UserIdentity()); + + auto result = future.Take(); + ASSERT_TRUE(result->is_config()); + ASSERT_EQ(result->get_config()->on_task_config->tabs.size(), 2u); + EXPECT_EQ(result->get_config()->on_task_config->tabs[1]->tab->url_type, + GetParam().mojom_type); +} + +INSTANTIATE_TEST_SUITE_P( + BocaAppPageHandlerProducerUrlTypeTests, + BocaAppPageHandlerProducerUrlTypeTest, + testing::Values(UrlTypeTestParam{"GeminiRegular", + mojom::UrlType::kGeminiRegular, + ::boca::URL_TYPE_GEMINI_REGULAR}, + UrlTypeTestParam{"GeminiGuidedLearning", + mojom::UrlType::kGeminiGuidedLearning, + ::boca::URL_TYPE_GEMINI_GUIDED_LEARNING}), + [](const testing::TestParamInfo< + BocaAppPageHandlerProducerUrlTypeTest::ParamType>& info) { + return info.param.test_name; + }); + } // namespace } // namespace ash::boca
diff --git a/ash/webui/boca_ui/mojom/boca.mojom b/ash/webui/boca_ui/mojom/boca.mojom index 287a2ff..296b73e 100644 --- a/ash/webui/boca_ui/mojom/boca.mojom +++ b/ash/webui/boca_ui/mojom/boca.mojom
@@ -14,6 +14,12 @@ // For detailed type definition. // TODO(b/356405813): Refactor documentation. +// Represents the url type. +enum UrlType { + kGeminiRegular, + kGeminiGuidedLearning, +}; + // Represents the tab information within browser window. struct TabInfo { // Tab id. Only present for local tab info. Will be absent for teacher-sent @@ -25,6 +31,8 @@ url.mojom.Url url; // Tab favicon URL. url.mojom.Url favicon; + // Tab url type. + UrlType? url_type; };
diff --git a/ash/webui/boca_ui/resources/app/boca_app.ts b/ash/webui/boca_ui/resources/app/boca_app.ts index 3142ebf..b8d9453a 100644 --- a/ash/webui/boca_ui/resources/app/boca_app.ts +++ b/ash/webui/boca_ui/resources/app/boca_app.ts
@@ -11,6 +11,14 @@ */ /** + * Declare url type enum type + */ +export enum UrlType { + GEMINI_REGULAR = 0, + GEMINI_GUIDED_LEARNING = 1, +} + +/** * Declare tab information */ export declare interface TabInfo { @@ -18,6 +26,7 @@ title: string; url: string; favicon: string; + urlType?: UrlType; } /** * Declare a browser window information
diff --git a/ash/webui/boca_ui/resources/app/client_delegate.ts b/ash/webui/boca_ui/resources/app/client_delegate.ts index 538d424..e9bced8 100644 --- a/ash/webui/boca_ui/resources/app/client_delegate.ts +++ b/ash/webui/boca_ui/resources/app/client_delegate.ts
@@ -112,6 +112,7 @@ url: item.tab.url, title: item.tab.title, favicon: item.tab.favicon, + urlType: item.tab.urlType?.valueOf(), }, navigationType: item.navigationType.valueOf(), }; @@ -150,6 +151,7 @@ title: tab.title, url: tab.url, favicon: tab.favicon, + urlType: tab.urlType?.valueOf(), }; }), }; @@ -219,6 +221,7 @@ url: item.tab.url, title: item.tab.title, favicon: item.tab.favicon, + urlType: item.tab.urlType?.valueOf() ?? null, }, navigationType: item.navigationType.valueOf(), }; @@ -286,6 +289,7 @@ url: item.tab.url, title: item.tab.title, favicon: item.tab.favicon, + urlType: item.tab.urlType?.valueOf() ?? null, }, navigationType: item.navigationType.valueOf(), };
diff --git a/base/test/BUILD.gn b/base/test/BUILD.gn index d1289a7..52d04948 100644 --- a/base/test/BUILD.gn +++ b/base/test/BUILD.gn
@@ -601,6 +601,8 @@ deps = [ ":leak_canary_test_resources", "//base:base_java_test_support", + "//base:command_line_java", + "//base:log_java", "//third_party/android_deps:com_squareup_leakcanary_leakcanary_android_core_java", "//third_party/android_deps:com_squareup_leakcanary_leakcanary_android_instrumentation_java", "//third_party/android_deps:com_squareup_leakcanary_leakcanary_android_java",
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/LeakCanaryChecker.java b/base/test/android/javatests/src/org/chromium/base/test/util/LeakCanaryChecker.java index 76fedf2..3e9262a5 100644 --- a/base/test/android/javatests/src/org/chromium/base/test/util/LeakCanaryChecker.java +++ b/base/test/android/javatests/src/org/chromium/base/test/util/LeakCanaryChecker.java
@@ -15,6 +15,8 @@ import shark.ReferencePattern.JavaLocalPattern; import shark.ReferencePattern.StaticFieldPattern; +import org.chromium.base.CommandLine; +import org.chromium.base.Log; import org.chromium.base.test.BaseJUnit4ClassRunner.AfterCleanupCheck; import org.chromium.build.annotations.ServiceImpl; @@ -31,10 +33,27 @@ @ServiceImpl(AfterCleanupCheck.class) public class LeakCanaryChecker implements AfterCleanupCheck { + private static final String TAG = "LeakCanaryChecker"; + @Override public void onAfterTestClass(Class<?> testClass) { - if (testClass.getAnnotation(EnableLeakChecks.class) != null) { - checkLeaks(); + boolean enabledByAnnotation = testClass.getAnnotation(EnableLeakChecks.class) != null; + boolean enabledByFlag = CommandLine.getInstance().hasSwitch("enable-leak-checks"); + boolean disabledByAnnotation = testClass.getAnnotation(DisableLeakCheck.class) != null; + + if (enabledByAnnotation && disabledByAnnotation) { + throw new IllegalStateException( + "Both @EnableLeakChecks and @DisableLeakCheck are specified on " + + testClass.getName()); + } + + if (enabledByAnnotation || enabledByFlag) { + if (disabledByAnnotation) { + Log.w(TAG, "Leak check skipped by @DisableLeakCheck"); + } else { + Log.i(TAG, "Running LeakCanary assertion"); + checkLeaks(); + } } } @@ -44,6 +63,12 @@ @Retention(RetentionPolicy.RUNTIME) public @interface EnableLeakChecks {} + // Annotate a test class with this to disable LeakCanary checks, even if + // @EnableLeakChecks is present or the --enable-leak-checks flag is used. + @Target({ElementType.TYPE}) + @Retention(RetentionPolicy.RUNTIME) + public @interface DisableLeakCheck {} + /** * Interface for providing leak patterns to LeakCanaryChecker. Implement this interface and * create a service file in META-INF/services/ to have LeakCanaryChecker pick up the custom leak @@ -140,6 +165,6 @@ private static void checkLeaks() { // Ensure LazyHolder is initialized, which sets up LeakCanary. var unused = LazyHolder.sInstanceLeaks; - LeakAssertions.INSTANCE.assertNoLeaks("LeakCanaryChecker"); + LeakAssertions.INSTANCE.assertNoLeaks(TAG); } }
diff --git a/base/tracing/protos/chrome_track_event.proto b/base/tracing/protos/chrome_track_event.proto index 64a6350..8cca948f 100644 --- a/base/tracing/protos/chrome_track_event.proto +++ b/base/tracing/protos/chrome_track_event.proto
@@ -2296,6 +2296,7 @@ GET_DEFAULT_COOKIE_MANAGER = 107; GET_PROFILE_STORE = 108; WEBVIEW_INSTANCE_GET_SETTINGS = 109; + WEBVIEW_INSTANCE_GET_AW_CONTENTS = 110; // Remember to update WebViewStartupCallSite in enums.xml when adding new // values here. }
diff --git a/build/android/gyp/generate_linker_version_script.py b/build/android/gyp/generate_linker_version_script.py index 3d0ad265..f7799fbe 100755 --- a/build/android/gyp/generate_linker_version_script.py +++ b/build/android/gyp/generate_linker_version_script.py
@@ -67,22 +67,22 @@ # The linker uses unix shell globbing patterns, not regex. So, we have to # include everything that doesn't end in "ForTest(ing)" with this set of # globs. - symbol_list.append('Java_*[!F]orTesting') - symbol_list.append('Java_*[!o]rTesting') - symbol_list.append('Java_*[!r]Testing') - symbol_list.append('Java_*[!T]esting') - symbol_list.append('Java_*[!e]sting') - symbol_list.append('Java_*[!s]ting') - symbol_list.append('Java_*[!t]ing') - symbol_list.append('Java_*[!i]ng') - symbol_list.append('Java_*[!n]g') - symbol_list.append('Java_*[!F]orTest') - symbol_list.append('Java_*[!o]rTest') - symbol_list.append('Java_*[!r]Test') - symbol_list.append('Java_*[!T]est') - symbol_list.append('Java_*[!e]st') - symbol_list.append('Java_*[!s]t') - symbol_list.append('Java_*[!gt]') + symbol_list.append('Java_*[^F]orTesting') + symbol_list.append('Java_*[^o]rTesting') + symbol_list.append('Java_*[^r]Testing') + symbol_list.append('Java_*[^T]esting') + symbol_list.append('Java_*[^e]sting') + symbol_list.append('Java_*[^s]ting') + symbol_list.append('Java_*[^t]ing') + symbol_list.append('Java_*[^i]ng') + symbol_list.append('Java_*[^n]g') + symbol_list.append('Java_*[^F]orTest') + symbol_list.append('Java_*[^o]rTest') + symbol_list.append('Java_*[^r]Test') + symbol_list.append('Java_*[^T]est') + symbol_list.append('Java_*[^e]st') + symbol_list.append('Java_*[^s]t') + symbol_list.append('Java_*[^gt]') if options.export_feature_registrations: symbol_list.append('JNI_OnLoad_*')
diff --git a/build/modules/modularize/config.py b/build/modules/modularize/config.py index b87338b..07ad47e 100644 --- a/build/modules/modularize/config.py +++ b/build/modules/modularize/config.py
@@ -139,7 +139,6 @@ if compiler.os == Os.Android: graph['android/legacy_stdlib_inlines.h'].textual = True graph['android/legacy_threads_inlines.h'].textual = True - graph['android/legacy_unistd_inlines.h'].textual = True graph['bits/threads_inlines.h'].textual = True graph['asm-generic/posix_types.h'].textual = True
diff --git a/cc/base/features.cc b/cc/base/features.cc index b476ed5..b403507 100644 --- a/cc/base/features.cc +++ b/cc/base/features.cc
@@ -242,6 +242,9 @@ "fling_continuity_threshold_pixels", 0.2); +BASE_FEATURE(kUseScrollIdToCalculateScrollJankV4FrameStages, + base::FEATURE_DISABLED_BY_DEFAULT); + BASE_FEATURE(kManualBeginFrame, base::FEATURE_DISABLED_BY_DEFAULT); BASE_FEATURE(kUnlockDuringGpuImageOperations, base::FEATURE_ENABLED_BY_DEFAULT);
diff --git a/cc/base/features.h b/cc/base/features.h index b34011d..48b2102a 100644 --- a/cc/base/features.h +++ b/cc/base/features.h
@@ -247,6 +247,16 @@ double, kScrollJankV4MetricFlingContinuityThreshold); +// When disabled, `cc::ScrollJankV4FrameStageCalculator` relies on the +// timestamps of arrival of individual `cc::ScrollEventMetrics` in the renderer +// compositor (`scroll_event_metrics->GetDispatchStageTimestamp( +// cc::EventMetrics::DispatchStage::kGenerated)`) when calculating the +// `ScrollJankV4Frame::Stage`s that happened in a single frame. When enabled, +// `cc::ScrollJankV4FrameStageCalculator` uses the scroll IDs +// (`scroll_event_metrics->scroll_begin_arrival_timestamp()`) instead. +CC_BASE_EXPORT BASE_DECLARE_FEATURE( + kUseScrollIdToCalculateScrollJankV4FrameStages); + // When enabled, AsyncLayerTreeFrameSink will generate its own BeginFrameArgs // when auto_needs_begin_frame_ is enabled. CC_BASE_EXPORT BASE_DECLARE_FEATURE(kManualBeginFrame);
diff --git a/cc/metrics/scroll_jank_v4_frame_stage_calculator.cc b/cc/metrics/scroll_jank_v4_frame_stage_calculator.cc index 1ad48c03..88256ba 100644 --- a/cc/metrics/scroll_jank_v4_frame_stage_calculator.cc +++ b/cc/metrics/scroll_jank_v4_frame_stage_calculator.cc
@@ -12,18 +12,20 @@ #include <variant> #include <vector> +#include "base/check_op.h" #include "base/notreached.h" #include "base/time/time.h" #include "base/trace_event/trace_event.h" #include "cc/base/features.h" #include "cc/metrics/event_metrics.h" +#include "cc/metrics/scroll_jank_v4_frame.h" namespace cc { namespace { template <typename EventMetricsPtr> -ScrollJankV4Frame::StageList CalculateStagesImpl( +ScrollJankV4Frame::StageList CalculateStagesDefaultImpl( std::vector<EventMetricsPtr>& events_metrics, uint64_t result_id) { ScrollJankV4Frame::StageList stages; @@ -271,21 +273,422 @@ ScrollJankV4Frame::StageList CalculateStages( EventMetrics::List& events_metrics, uint64_t result_id) override { - return CalculateStagesImpl(events_metrics, result_id); + return CalculateStagesDefaultImpl(events_metrics, result_id); } ScrollJankV4Frame::StageList CalculateStages( std::vector<ScrollEventMetrics*>& events_metrics, uint64_t result_id) override { - return CalculateStagesImpl(events_metrics, result_id); + return CalculateStagesDefaultImpl(events_metrics, result_id); } }; +// Implementation of `ScrollJankV4FrameStageCalculator` which takes the scroll +// ID (`ScrollEventMetrics::scroll_begin_arrival_timestamp()`) into account when +// calculating the `ScrollJankV4Frame::Stage`s that happened in a single frame. +// +// Rationale for using the scroll ID: We want to make sure that, in the rare +// case when scroll events arrive out of order, the scroll jank v4 metric +// doesn't emit blatantly incorrect data. Most importantly, if a GSU (gesture +// scroll update) arrives after a GSE (gesture scroll end) from the same scroll, +// the metric shouldn't treat the GSU as the beginning of a new scroll. +// +// The calculator therefore keeps track of the current / most recent scroll ID +// and whether it has already encountered GSUs and/or a GSE for that scroll. It +// filters out events as follows: +// +// 1. Once the calculator has encountered a GSE with a particular scroll ID, it +// will ignore GSUs/GSEs with the SAME OR LOWER scroll ID in all subsequent +// frames. +// 2. Once the calculator has encountered a GSU with a particular scroll ID, it +// will ignore GSUs/GSUs with a LOWER scroll ID in all subsequent frames. +// +// Furthermore, if two scrolls overlap in a single frame, we want the frame to +// count towards the previous scroll. So if a frame contains GSUs with multiple +// scroll IDs, the calculator will only take into account the GSUs with the +// LOWEST scroll ID. +// +// The calculator takes extra care to ensure that the sequence of +// `ScrollJankV4Frame::Stage`s emitted across all frames matches the regular +// expression `(ScrollStart ScrollUpdate+ ScrollEnd)*`. +class ScrollIdBasedCalculator : public ScrollJankV4FrameStageCalculator { + public: + ~ScrollIdBasedCalculator() override = default; + + ScrollJankV4Frame::StageList CalculateStages( + EventMetrics::List& events_metrics, + uint64_t result_id) override { + return CalculateStagesBasedOnScrollId(events_metrics, result_id); + } + + ScrollJankV4Frame::StageList CalculateStages( + std::vector<ScrollEventMetrics*>& events_metrics, + uint64_t result_id) override { + return CalculateStagesBasedOnScrollId(events_metrics, result_id); + } + + private: + // Information about GSUs and GSEs in a single frame. + // + // The calculator considers a GSU/GSE in the frame to be "ineligible" and thus + // ignores it IF: + // + // * the calculator has already encountered a GSU with a GREATER scroll ID + // (`ScrollEventMetrics::scroll_begin_arrival_timestamp()`) in an earlier + // frame OR + // * the calculator has already encountered a GSE with a GREATER OR EQUAL + // scroll ID in an earlier frame. + // + // Otherwise, the calculator considers a GSU/GSE "eligible". + struct FrameScrollEventBounds { + // Whether the frame contains one or more ineligible GSUs. + bool has_ineligible_updates = false; + + // The range of scroll IDs of eligible GSUs in the frame. + // + // Both endpoints are guaranteed to be greater than or equal to + // `current_scroll_id_`. If `has_seen_in_current_scroll_` is + // `HasSeen::kEnd`, both endpoints are guaranteed to be strictly greater + // than `current_scroll_id_`. + struct Range { + base::TimeTicks min; + base::TimeTicks max; + }; + std::optional<Range> eligible_updates_scroll_id_range = std::nullopt; + + // The maximum scroll ID of eligible GSEs in the frame. + // + // Guaranteed to be greater than or equal to `current_scroll_id_`. If + // `has_seen_in_current_scroll_` is `HasSeen::kEnd`, it's guaranteed to be + // strictly greater than `current_scroll_id_`. Can be less than, greater + // than, or overlap with `eligible_updates_scroll_id_range`. + std::optional<base::TimeTicks> eligible_end_max_scroll_id = std::nullopt; + }; + + // What the calculator has seen for the current / most recent scroll. + enum class HasSeen { + // The calculator hasn't seen any GSUs or GSE for the current scroll yet. + // + // It hasn't emitted a `ScrollJankV4Frame::Stage::ScrollStart` yet. + // + // The calculator will ignore any GSUs/GSEs with a scroll ID LOWER than + // `current_scroll_id_`. + kNoUpdates, + // The calculator has seen one or more GSUs for the current scroll (but no + // GSE). + // + // It has emitted one `ScrollJankV4Frame::Stage::ScrollStart` and one or + // more `ScrollJankV4Frame::Stage::ScrollUpdates`. + // + // The calculator will ignore any GSUs/GSEs with a scroll ID LOWER than + // `current_scroll_id_`. + kOneOrMoreUpdates, + // The calculator has seen a GSE for the most recent scroll. + // + // Either the calculator hasn't seen any scrolls yet, or it has emitted one + // `ScrollJankV4Frame::Stage::ScrollStart`, one or more + // `ScrollJankV4Frame::Stage::ScrollUpdates` and + // `ScrollJankV4Frame::Stage::ScrollEnd`. + // + // The calculator will ignore any GSUs/GSEs with a scroll ID LOWER OR EQUAL + // to `current_scroll_id_`. + kEnd + }; + + template <typename EventMetricsPtr> + ScrollJankV4Frame::StageList CalculateStagesBasedOnScrollId( + std::vector<EventMetricsPtr>& events_metrics, + uint64_t result_id) { + ScrollJankV4Frame::StageList stages; + + auto [has_ineligible_updates, eligible_update_scroll_id_range, + eligible_end_max_scroll_id] = + CalculateFrameScrollEventBoundsAndSetResultId(events_metrics, + result_id); + + if (has_ineligible_updates) { + TRACE_EVENT("input", + "CalculateStagesBasedOnScrollId: Ignoring GSUs from already " + "ended scrolls"); + } + + // There are many possible relationships between `current_scroll_id_` + // (CS), `eligible_update_scroll_id_range` (GSU-min, GSU-max) and + // `eligible_end_max_scroll_id` (GSE-max): + // + // 1. Frame with no GSUs or GSEs: + // CS + // 2. Frame with GSUs which continue an existing scroll: + // CS = GSU-min = GSU-max + // 3. Frame with GSUs which continue an existing scroll and a GSE which + // then ends that scroll: + // CS = GSU-min = GSU-max <= GSE-max + // 4. Frame with GSUs both from the existing and a new scroll: + // CS = GSU-min < GSU-max + // 5. Frame with GSUs both from the existing and a new scroll as well as a + // GSE which ends that scroll: + // CS = GSU-min < GSU-max <= GSE-max + // 6. Frame with GSUs from a new scroll: + // CS < GSU-min = GSU-max + // 7. Frame with GSUs from a new scroll and a GSE which immediately ends + // that scroll: + // CS < GSU-min = GSU-max <= GSE-max + // 8. Frame with GSUs from more than one new scroll, the last scroll hasn't + // ended yet: + // CS < GSU-min < GSU-max + // 9. Frame with GSUs from more than one new scroll and a GSE which ends + // the last one: + // CS < GSU-min < GSU-max <= GSE-max + // 10. Frame with a GSU which ends an existing scroll. + // CS <= GSE-max + // + // Note: We can ignore scenarios where GSE-max < GSU-max because the + // calculator will interpret GSU-max as "any scroll with a lower scroll ID + // has already ended" and emit any necessary + // `ScrollJankV4Frame::Stage::ScrollEnd` / + // `ScrollJankV4Frame::Stage::ScrollStart` events. + + // Are there any eligible GSUs in the frame (scenarios 2-9)? + if (eligible_update_scroll_id_range.has_value()) { + if (eligible_update_scroll_id_range->max > + eligible_update_scroll_id_range->min) { + // Scenarios 4, 5, 8, 9. + TRACE_EVENT("input", + "CalculateStagesBasedOnScrollId: Multiple scrolls overlap " + "in a single frame"); + } + // If so, the calculator might first need to emit a + // `ScrollJankV4Frame::Stage::ScrollEnd` and/or + // `ScrollJankV4Frame::Stage::ScrollStart`, depending on whether the GSUs + // continue an existing scroll or start a new one. + if (eligible_update_scroll_id_range->min > current_scroll_id_) { + // Scenarios 6-9. + if (has_seen_in_current_scroll_ == HasSeen::kOneOrMoreUpdates) { + stages.emplace_back(ScrollJankV4Frame::Stage::ScrollEnd{}); + } + stages.emplace_back(ScrollJankV4Frame::Stage::ScrollStart{}); + } else { + // Scenarios 2-5. + DCHECK_EQ(eligible_update_scroll_id_range->min, current_scroll_id_); + DCHECK_NE(has_seen_in_current_scroll_, HasSeen::kEnd); + if (has_seen_in_current_scroll_ == HasSeen::kNoUpdates) { + stages.emplace_back(ScrollJankV4Frame::Stage::ScrollStart{}); + } + } + + // The calculator then emits a single + // `ScrollJankV4Frame::Stage::ScrollUpdates`. + stages.emplace_back(CreateScrollUpdatesStageForScrollId( + events_metrics, eligible_update_scroll_id_range->min)); + } + + // Should we end the current scroll for any reason (either because of a GSE + // or because the frame contained GSUs with multiple scroll IDs)? + if (eligible_end_max_scroll_id.has_value() && + !eligible_update_scroll_id_range.has_value()) { + // Yes, because the frame contained an eligible GSE and no eligible GSUs + // (scenario 10). + if (has_seen_in_current_scroll_ == HasSeen::kOneOrMoreUpdates) { + stages.emplace_back(ScrollJankV4Frame::Stage::ScrollEnd{}); + } + current_scroll_id_ = *eligible_end_max_scroll_id; + has_seen_in_current_scroll_ = HasSeen::kEnd; + } else if (eligible_end_max_scroll_id.has_value() && + *eligible_end_max_scroll_id >= + eligible_update_scroll_id_range->max) { + // Yes, because the frame contained an eligible GSE whose scroll ID was + // greater than or equal to that of all eligible GSUs (scenarios 3, 5, 7, + // 9). + stages.emplace_back(ScrollJankV4Frame::Stage::ScrollEnd{}); + current_scroll_id_ = *eligible_end_max_scroll_id; + has_seen_in_current_scroll_ = HasSeen::kEnd; + } else if (eligible_update_scroll_id_range.has_value()) { + if (eligible_update_scroll_id_range->max > + eligible_update_scroll_id_range->min) { + // Yes, because the frame contained eligible GSUs with multiple scroll + // IDs (scenarios 4, 8). + stages.emplace_back(ScrollJankV4Frame::Stage::ScrollEnd{}); + current_scroll_id_ = eligible_update_scroll_id_range->max; + has_seen_in_current_scroll_ = HasSeen::kNoUpdates; + } else { + // No, all eligible GSUs in the frame had the same scroll ID and there + // were no GSEs with a scroll ID that's greater or equal (scenarios 2, + // 6). + DCHECK_EQ(eligible_update_scroll_id_range->max, + eligible_update_scroll_id_range->min); + current_scroll_id_ = eligible_update_scroll_id_range->min; + has_seen_in_current_scroll_ = HasSeen::kOneOrMoreUpdates; + } + } + + return stages; + } + + template <typename EventMetricsPtr> + FrameScrollEventBounds CalculateFrameScrollEventBoundsAndSetResultId( + std::vector<EventMetricsPtr>& events_metrics, + uint64_t result_id) { + bool has_ineligible_updates = false; + std::optional<FrameScrollEventBounds::Range> + eligible_update_scroll_id_range = std::nullopt; + std::optional<base::TimeTicks> eligible_end_max_scroll_id = std::nullopt; + + for (auto& event : events_metrics) { + auto* scroll_event = event->AsScroll(); + if (!scroll_event) { + continue; + } + DCHECK(!scroll_event->scroll_jank_v4_result_id().has_value()); + scroll_event->set_scroll_jank_v4_result_id(result_id); + if (!IsEligible(*scroll_event)) { + if (scroll_event->AsScrollUpdate()) { + has_ineligible_updates = true; + } + continue; + } + base::TimeTicks scroll_id = + scroll_event->scroll_begin_arrival_timestamp(); + EventMetrics::EventType event_type = scroll_event->type(); + if (event_type == EventMetrics::EventType::kGestureScrollEnd || + event_type == EventMetrics::EventType::kInertialGestureScrollEnd) { + if (!eligible_end_max_scroll_id.has_value() || + scroll_id > *eligible_end_max_scroll_id) { + eligible_end_max_scroll_id = scroll_id; + } + } else if (scroll_event->AsScrollUpdate()) { + if (!eligible_update_scroll_id_range.has_value()) { + eligible_update_scroll_id_range = {.min = scroll_id, + .max = scroll_id}; + } else if (scroll_id < eligible_update_scroll_id_range->min) { + eligible_update_scroll_id_range->min = scroll_id; + } else if (scroll_id > eligible_update_scroll_id_range->max) { + eligible_update_scroll_id_range->max = scroll_id; + } + DCHECK_LE(eligible_update_scroll_id_range->min, + eligible_update_scroll_id_range->max); + } + } + return { + .has_ineligible_updates = has_ineligible_updates, + .eligible_updates_scroll_id_range = eligible_update_scroll_id_range, + .eligible_end_max_scroll_id = eligible_end_max_scroll_id, + }; + } + + bool IsEligible(const ScrollEventMetrics& scroll_event) { + if (has_seen_in_current_scroll_ == HasSeen::kEnd) { + return scroll_event.scroll_begin_arrival_timestamp() > current_scroll_id_; + } + return scroll_event.scroll_begin_arrival_timestamp() >= current_scroll_id_; + } + + template <typename EventMetricsPtr> + static ScrollJankV4Frame::Stage::ScrollUpdates + CreateScrollUpdatesStageForScrollId( + const std::vector<EventMetricsPtr>& events_metrics, + base::TimeTicks scroll_id) { + // Real scroll updates. + bool had_real_input = false; + base::TimeTicks first_real_input_generation_ts = base::TimeTicks::Max(); + base::TimeTicks last_real_input_generation_ts = base::TimeTicks::Min(); + bool has_real_inertial_input = false; + float total_real_raw_delta_pixels = 0; + float max_abs_real_inertial_raw_delta_pixels = 0; + std::optional<EventMetrics::TraceId> first_real_input_trace_id = + std::nullopt; + + // Synthetic scroll updates. + bool had_synthetic_input = false; + bool has_synthetic_inertial_input = false; + base::TimeTicks first_synthetic_input_begin_frame_ts = + base::TimeTicks::Max(); + std::optional<EventMetrics::TraceId> first_synthetic_input_trace_id = + std::nullopt; + + for (auto& event : events_metrics) { + auto* scroll_update = event->AsScrollUpdate(); + if (!scroll_update || + scroll_update->scroll_begin_arrival_timestamp() != scroll_id) { + continue; + } + + bool is_synthetic = scroll_update->is_synthetic(); + bool is_inertial = event->type() == + EventMetrics::EventType::kInertialGestureScrollUpdate; + if (is_synthetic) { + had_synthetic_input = true; + base::TimeTicks begin_frame_ts = + scroll_update->dispatch_args().frame_time; + if (begin_frame_ts < first_synthetic_input_begin_frame_ts) { + first_synthetic_input_begin_frame_ts = begin_frame_ts; + first_synthetic_input_trace_id = scroll_update->trace_id(); + } + if (is_inertial) { + has_synthetic_inertial_input = true; + } + } else { + had_real_input = true; + last_real_input_generation_ts = std::max( + last_real_input_generation_ts, scroll_update->last_timestamp()); + total_real_raw_delta_pixels += scroll_update->delta(); + base::TimeTicks generation_ts = event->GetDispatchStageTimestamp( + EventMetrics::DispatchStage::kGenerated); + if (generation_ts < first_real_input_generation_ts) { + first_real_input_generation_ts = generation_ts; + first_real_input_trace_id = scroll_update->trace_id(); + } + if (is_inertial) { + has_real_inertial_input = true; + max_abs_real_inertial_raw_delta_pixels = + std::max(max_abs_real_inertial_raw_delta_pixels, + std::abs(scroll_update->delta())); + } + } + } + + CHECK(had_real_input || had_synthetic_input); + std::optional<ScrollJankV4Frame::Stage::ScrollUpdates::Real> real_updates = + had_real_input + ? std::make_optional(ScrollJankV4Frame::Stage::ScrollUpdates::Real{ + .first_input_generation_ts = first_real_input_generation_ts, + .last_input_generation_ts = last_real_input_generation_ts, + .has_inertial_input = has_real_inertial_input, + .abs_total_raw_delta_pixels = + std::abs(total_real_raw_delta_pixels), + .max_abs_inertial_raw_delta_pixels = + max_abs_real_inertial_raw_delta_pixels, + .first_input_trace_id = first_real_input_trace_id, + }) + : std::nullopt; + std::optional<ScrollJankV4Frame::Stage::ScrollUpdates::Synthetic> + synthetic_updates = + had_synthetic_input + ? std::make_optional( + ScrollJankV4Frame::Stage::ScrollUpdates::Synthetic{ + .first_input_begin_frame_ts = + first_synthetic_input_begin_frame_ts, + .has_inertial_input = has_synthetic_inertial_input, + .first_input_trace_id = + first_synthetic_input_trace_id, + }) + : std::nullopt; + return ScrollJankV4Frame::Stage::ScrollUpdates(real_updates, + synthetic_updates); + } + + base::TimeTicks current_scroll_id_ = base::TimeTicks::Min(); + HasSeen has_seen_in_current_scroll_ = HasSeen::kEnd; +}; + } // namespace // static std::unique_ptr<ScrollJankV4FrameStageCalculator> ScrollJankV4FrameStageCalculator::Create() { + if (base::FeatureList::IsEnabled( + features::kUseScrollIdToCalculateScrollJankV4FrameStages)) { + return std::make_unique<ScrollIdBasedCalculator>(); + } return std::make_unique<DefaultCalculator>(); }
diff --git a/cc/metrics/scroll_jank_v4_frame_stage_calculator.h b/cc/metrics/scroll_jank_v4_frame_stage_calculator.h index 01ce311..2b1e71e 100644 --- a/cc/metrics/scroll_jank_v4_frame_stage_calculator.h +++ b/cc/metrics/scroll_jank_v4_frame_stage_calculator.h
@@ -25,8 +25,7 @@ // associated with a frame. // // Sets `ScrollEventMetrics::scroll_jank_v4_result_id()` to `result_id` for - // all scroll updates and ends which this method uses to calculate the stages. - // Otherwise doesn't modify `event_metrics`. + // all scroll events in `event_metrics`. virtual ScrollJankV4Frame::StageList CalculateStages( EventMetrics::List& events_metrics, uint64_t result_id) = 0;
diff --git a/cc/metrics/scroll_jank_v4_frame_stage_calculator_unittest.cc b/cc/metrics/scroll_jank_v4_frame_stage_calculator_unittest.cc index 19b64de..84b1a59 100644 --- a/cc/metrics/scroll_jank_v4_frame_stage_calculator_unittest.cc +++ b/cc/metrics/scroll_jank_v4_frame_stage_calculator_unittest.cc
@@ -4,9 +4,12 @@ #include "cc/metrics/scroll_jank_v4_frame_stage_calculator.h" +#include <cstdint> #include <optional> +#include "base/test/scoped_feature_list.h" #include "base/time/time.h" +#include "cc/base/features.h" #include "cc/metrics/event_metrics.h" #include "cc/metrics/scroll_jank_v4_frame.h" #include "cc/test/event_metrics_test_creator.h" @@ -15,7 +18,6 @@ #include "ui/events/types/event_type.h" namespace cc { - namespace { using DispatchBeginFrameArgs = ScrollEventMetrics::DispatchBeginFrameArgs; @@ -30,30 +32,51 @@ constexpr uint64_t kResultId = 123456; -} // namespace +// A matcher which matches a `EventMetrics::List` iff each element in the list +// points to a `ScrollEventMetrics` whose `scroll_jank_v4_result_id()` property +// has value `result_id`. +constexpr ::testing::Matcher<const EventMetrics::List&> AllHaveResultId( + uint64_t result_id) { + return ::testing::Each(::testing::Pointee(::testing::Property( + &EventMetrics::AsScroll, + ::testing::Property(&ScrollEventMetrics::scroll_jank_v4_result_id, + result_id)))); +} class ScrollJankV4FrameStageCalculatorTest : public testing::Test { - public: - ScrollJankV4FrameStageCalculatorTest() = default; - ~ScrollJankV4FrameStageCalculatorTest() override = default; - protected: + explicit ScrollJankV4FrameStageCalculatorTest( + bool use_scroll_id_to_calculate_stages) { + feature_list_.InitWithFeatureState( + features::kUseScrollIdToCalculateScrollJankV4FrameStages, + use_scroll_id_to_calculate_stages); + calculator_ = ScrollJankV4FrameStageCalculator::Create(); + } + static base::TimeTicks MillisecondsTicks(int ms) { return base::TimeTicks() + base::Milliseconds(ms); } + base::test::ScopedFeatureList feature_list_; EventMetricsTestCreator metrics_creator_; - std::unique_ptr<ScrollJankV4FrameStageCalculator> calculator_ = - ScrollJankV4FrameStageCalculator::Create(); + std::unique_ptr<ScrollJankV4FrameStageCalculator> calculator_; }; -TEST_F(ScrollJankV4FrameStageCalculatorTest, EmptyEventMetricsList) { +class ScrollJankV4FrameStageDefaultCalculatorTest + : public ScrollJankV4FrameStageCalculatorTest { + public: + ScrollJankV4FrameStageDefaultCalculatorTest() + : ScrollJankV4FrameStageCalculatorTest( + /* use_scroll_id_to_calculate_stages= */ false) {} +}; + +TEST_F(ScrollJankV4FrameStageDefaultCalculatorTest, EmptyEventMetricsList) { EventMetrics::List events_metrics; auto stages = calculator_->CalculateStages(events_metrics, kResultId); EXPECT_THAT(stages, IsEmpty()); } -TEST_F(ScrollJankV4FrameStageCalculatorTest, FirstGestureScrollUpdate) { +TEST_F(ScrollJankV4FrameStageDefaultCalculatorTest, FirstGestureScrollUpdate) { EventMetrics::List events_metrics; events_metrics.push_back(metrics_creator_.FirstGestureScrollUpdateBuilder() .SetTimestamp(MillisecondsTicks(16)) @@ -79,7 +102,7 @@ kResultId); } -TEST_F(ScrollJankV4FrameStageCalculatorTest, +TEST_F(ScrollJankV4FrameStageDefaultCalculatorTest, SyntheticFirstGestureScrollUpdate) { EventMetrics::List events_metrics; events_metrics.push_back(metrics_creator_.FirstGestureScrollUpdateBuilder() @@ -105,7 +128,7 @@ kResultId); } -TEST_F(ScrollJankV4FrameStageCalculatorTest, GestureScrollUpdate) { +TEST_F(ScrollJankV4FrameStageDefaultCalculatorTest, GestureScrollUpdate) { EventMetrics::List events_metrics; events_metrics.push_back(metrics_creator_.GestureScrollUpdateBuilder() .SetTimestamp(MillisecondsTicks(16)) @@ -127,7 +150,8 @@ kResultId); } -TEST_F(ScrollJankV4FrameStageCalculatorTest, SyntheticGestureScrollUpdate) { +TEST_F(ScrollJankV4FrameStageDefaultCalculatorTest, + SyntheticGestureScrollUpdate) { EventMetrics::List events_metrics; events_metrics.push_back(metrics_creator_.GestureScrollUpdateBuilder() .SetTimestamp(MillisecondsTicks(16)) @@ -150,7 +174,7 @@ kResultId); } -TEST_F(ScrollJankV4FrameStageCalculatorTest, +TEST_F(ScrollJankV4FrameStageDefaultCalculatorTest, SyntheticInertialGestureScrollUpdate) { EventMetrics::List events_metrics; events_metrics.push_back(metrics_creator_.InertialGestureScrollUpdateBuilder() @@ -174,7 +198,8 @@ kResultId); } -TEST_F(ScrollJankV4FrameStageCalculatorTest, InertialGestureScrollUpdate) { +TEST_F(ScrollJankV4FrameStageDefaultCalculatorTest, + InertialGestureScrollUpdate) { EventMetrics::List events_metrics; events_metrics.push_back(metrics_creator_.InertialGestureScrollUpdateBuilder() .SetTimestamp(MillisecondsTicks(16)) @@ -198,7 +223,7 @@ kResultId); } -TEST_F(ScrollJankV4FrameStageCalculatorTest, GestureScrollEnd) { +TEST_F(ScrollJankV4FrameStageDefaultCalculatorTest, GestureScrollEnd) { EventMetrics::List events_metrics; events_metrics.push_back(metrics_creator_.GestureScrollEndBuilder() .SetTimestamp(MillisecondsTicks(16)) @@ -209,7 +234,7 @@ kResultId); } -TEST_F(ScrollJankV4FrameStageCalculatorTest, InertialGestureScrollEnd) { +TEST_F(ScrollJankV4FrameStageDefaultCalculatorTest, InertialGestureScrollEnd) { EventMetrics::List events_metrics; events_metrics.push_back(metrics_creator_.InertialGestureScrollEndBuilder() .SetTimestamp(MillisecondsTicks(16)) @@ -220,7 +245,7 @@ kResultId); } -TEST_F(ScrollJankV4FrameStageCalculatorTest, NonScrollEventType) { +TEST_F(ScrollJankV4FrameStageDefaultCalculatorTest, NonScrollEventType) { EventMetrics::List events_metrics; events_metrics.push_back( metrics_creator_.CreateEventBuilder(ui::EventType::kMouseMoved) @@ -230,7 +255,7 @@ EXPECT_THAT(stages, IsEmpty()); } -TEST_F(ScrollJankV4FrameStageCalculatorTest, MultipleScrollUpdates) { +TEST_F(ScrollJankV4FrameStageDefaultCalculatorTest, MultipleScrollUpdates) { EventMetrics::List events_metrics; // Intentionally in "random" order to make sure that the calculation doesn't // rely on the list being sorted (because the list isn't sorted in general). @@ -304,7 +329,7 @@ } } -TEST_F(ScrollJankV4FrameStageCalculatorTest, +TEST_F(ScrollJankV4FrameStageDefaultCalculatorTest, MultipleScrollUpdatesIncludingSynthetic) { EventMetrics::List events_metrics; // Intentionally in "random" order to make sure that the calculation doesn't @@ -385,7 +410,7 @@ } } -TEST_F(ScrollJankV4FrameStageCalculatorTest, +TEST_F(ScrollJankV4FrameStageDefaultCalculatorTest, ScrollEndForPreviousScrollThenScrollUpdates) { EventMetrics::List events_metrics; events_metrics.push_back(metrics_creator_.GestureScrollUpdateBuilder() @@ -423,7 +448,7 @@ } } -TEST_F(ScrollJankV4FrameStageCalculatorTest, +TEST_F(ScrollJankV4FrameStageDefaultCalculatorTest, ScrollUpdatesThenScrollEndForCurrentScroll) { EventMetrics::List events_metrics; events_metrics.push_back(metrics_creator_.InertialGestureScrollUpdateBuilder() @@ -470,7 +495,7 @@ // // Since the IGSE's timestamp of arrival in the renderer compositor (4 ms) is // greater than that of the IGSU (3 ms), the expected ordering is [IGSU, IGSE]. -TEST_F(ScrollJankV4FrameStageCalculatorTest, +TEST_F(ScrollJankV4FrameStageDefaultCalculatorTest, OrdersEventsByArrivedInRendererCompositor) { EventMetrics::List events_metrics; events_metrics.push_back( @@ -506,4 +531,794 @@ kResultId); } +class ScrollJankV4FrameStageScrollIdBasedCalculatorTest + : public ScrollJankV4FrameStageCalculatorTest { + public: + ScrollJankV4FrameStageScrollIdBasedCalculatorTest() + : ScrollJankV4FrameStageCalculatorTest( + /* use_scroll_id_to_calculate_stages= */ true) {} +}; + +TEST_F(ScrollJankV4FrameStageScrollIdBasedCalculatorTest, + EmptyEventMetricsList) { + EventMetrics::List events_metrics; + auto stages = calculator_->CalculateStages(events_metrics, kResultId); + EXPECT_THAT(stages, IsEmpty()); +} + +TEST_F(ScrollJankV4FrameStageScrollIdBasedCalculatorTest, RegularScrolls) { + // Frame 1: 1st GSU of scroll 1. + base::TimeTicks scroll1_id = MillisecondsTicks(100); + { + EventMetrics::List events_metrics; + events_metrics.push_back(metrics_creator_.FirstGestureScrollUpdateBuilder() + .SetTimestamp(MillisecondsTicks(105)) + .SetScrollBeginArrivalTimestamp(scroll1_id) + .SetDelta(10) + .SetIsSynthetic(false) + .SetTraceId(TraceId(1)) + .Build()); + auto stages = + calculator_->CalculateStages(events_metrics, /* result_id= */ 1001); + EXPECT_THAT( + stages, + ElementsAre( + ScrollJankV4Frame::Stage{ScrollStart{}}, + ScrollJankV4Frame::Stage{ScrollUpdates( + Real{.first_input_generation_ts = MillisecondsTicks(105), + .last_input_generation_ts = MillisecondsTicks(105), + .has_inertial_input = false, + .abs_total_raw_delta_pixels = 10, + .max_abs_inertial_raw_delta_pixels = 0, + .first_input_trace_id = TraceId(1)}, + /* synthetic= */ std::nullopt)})); + EXPECT_THAT(events_metrics, AllHaveResultId(1001)); + } + + // Frame 2: 2nd GSU of scroll 1. + { + EventMetrics::List events_metrics; + events_metrics.push_back(metrics_creator_.GestureScrollUpdateBuilder() + .SetTimestamp(MillisecondsTicks(120)) + .SetScrollBeginArrivalTimestamp(scroll1_id) + .SetDelta(20) + .SetIsSynthetic(false) + .SetTraceId(TraceId(2)) + .Build()); + auto stages = + calculator_->CalculateStages(events_metrics, /* result_id= */ 1002); + EXPECT_THAT(stages, + ElementsAre(ScrollJankV4Frame::Stage{ScrollUpdates( + Real{.first_input_generation_ts = MillisecondsTicks(120), + .last_input_generation_ts = MillisecondsTicks(120), + .has_inertial_input = false, + .abs_total_raw_delta_pixels = 20, + .max_abs_inertial_raw_delta_pixels = 0, + .first_input_trace_id = TraceId(2)}, + /* synthetic= */ std::nullopt)})); + EXPECT_THAT(events_metrics, AllHaveResultId(1002)); + } + + // Frame 3: GSE of scroll 1 and 1st GSU of scroll 2 + base::TimeTicks scroll2_id = MillisecondsTicks(130); + { + EventMetrics::List events_metrics; + events_metrics.push_back(metrics_creator_.GestureScrollEndBuilder() + .SetTimestamp(MillisecondsTicks(135)) + .SetScrollBeginArrivalTimestamp(scroll1_id) + .Build()); + events_metrics.push_back(metrics_creator_.GestureScrollUpdateBuilder() + .SetTimestamp(MillisecondsTicks(140)) + .SetScrollBeginArrivalTimestamp(scroll2_id) + .SetDelta(30) + .SetIsSynthetic(false) + .SetTraceId(TraceId(3)) + .Build()); + auto stages = + calculator_->CalculateStages(events_metrics, /* result_id= */ 1003); + EXPECT_THAT( + stages, + ElementsAre(ScrollJankV4Frame::Stage{ScrollEnd{}}, + ScrollJankV4Frame::Stage{ScrollStart{}}, + ScrollJankV4Frame::Stage{ScrollUpdates( + Real{ + .first_input_generation_ts = MillisecondsTicks(140), + .last_input_generation_ts = MillisecondsTicks(140), + .has_inertial_input = false, + .abs_total_raw_delta_pixels = 30, + .max_abs_inertial_raw_delta_pixels = 0, + .first_input_trace_id = TraceId(3), + }, + /* synthetic= */ std::nullopt)})); + EXPECT_THAT(events_metrics, AllHaveResultId(1003)); + } + + // Frame 4: no scroll events. + { + EventMetrics::List events_metrics; + events_metrics.push_back( + metrics_creator_.CreateEventBuilder(ui::EventType::kTouchMoved) + .SetTimestamp(MillisecondsTicks(190)) + .Build()); + auto stages = + calculator_->CalculateStages(events_metrics, /* result_id= */ 1004); + EXPECT_THAT(stages, IsEmpty()); + } + + // Frame 5: 2nd-3rd GSU of scroll 2. + { + EventMetrics::List events_metrics; + events_metrics.push_back(metrics_creator_.GestureScrollUpdateBuilder() + .SetTimestamp(MillisecondsTicks(155)) + .SetScrollBeginArrivalTimestamp(scroll2_id) + .SetDelta(40) + .SetIsSynthetic(false) + .SetTraceId(TraceId(4)) + .Build()); + events_metrics.push_back(metrics_creator_.GestureScrollUpdateBuilder() + .SetTimestamp(MillisecondsTicks(160)) + .SetScrollBeginArrivalTimestamp(scroll2_id) + .SetDelta(50) + .SetIsSynthetic(false) + .SetTraceId(TraceId(5)) + .Build()); + auto stages = + calculator_->CalculateStages(events_metrics, /* result_id= */ 1005); + EXPECT_THAT(stages, + ElementsAre(ScrollJankV4Frame::Stage{ScrollUpdates( + Real{.first_input_generation_ts = MillisecondsTicks(155), + .last_input_generation_ts = MillisecondsTicks(160), + .has_inertial_input = false, + .abs_total_raw_delta_pixels = 90, + .max_abs_inertial_raw_delta_pixels = 0, + .first_input_trace_id = TraceId(4)}, + /* synthetic= */ std::nullopt)})); + EXPECT_THAT(events_metrics, AllHaveResultId(1005)); + } + + // Frame 6: 4th GSU and GSE of scroll 2 + { + EventMetrics::List events_metrics; + events_metrics.push_back(metrics_creator_.GestureScrollUpdateBuilder() + .SetTimestamp(MillisecondsTicks(175)) + .SetScrollBeginArrivalTimestamp(scroll2_id) + .SetDelta(60) + .SetIsSynthetic(false) + .SetTraceId(TraceId(6)) + .Build()); + events_metrics.push_back(metrics_creator_.GestureScrollEndBuilder() + .SetTimestamp(MillisecondsTicks(180)) + .SetScrollBeginArrivalTimestamp(scroll2_id) + .Build()); + auto stages = + calculator_->CalculateStages(events_metrics, /* result_id= */ 1006); + EXPECT_THAT( + stages, + ElementsAre(ScrollJankV4Frame::Stage{ScrollUpdates( + Real{ + .first_input_generation_ts = MillisecondsTicks(175), + .last_input_generation_ts = MillisecondsTicks(175), + .has_inertial_input = false, + .abs_total_raw_delta_pixels = 60, + .max_abs_inertial_raw_delta_pixels = 0, + .first_input_trace_id = TraceId(6), + }, + /* synthetic= */ std::nullopt)}, + ScrollJankV4Frame::Stage{ScrollEnd{}})); + EXPECT_THAT(events_metrics, AllHaveResultId(1006)); + } + + // Frame 7: no scroll events. + { + EventMetrics::List events_metrics; + events_metrics.push_back( + metrics_creator_.CreateEventBuilder(ui::EventType::kGestureTap) + .SetTimestamp(MillisecondsTicks(190)) + .Build()); + auto stages = + calculator_->CalculateStages(events_metrics, /* result_id= */ 1007); + EXPECT_THAT(stages, IsEmpty()); + } + + // Frame 8: 1st GSU of scroll 3. + base::TimeTicks scroll3_id = MillisecondsTicks(195); + { + EventMetrics::List events_metrics; + events_metrics.push_back(metrics_creator_.FirstGestureScrollUpdateBuilder() + .SetTimestamp(MillisecondsTicks(205)) + .SetScrollBeginArrivalTimestamp(scroll3_id) + .SetDelta(70) + .SetIsSynthetic(false) + .SetTraceId(TraceId(7)) + .Build()); + auto stages = + calculator_->CalculateStages(events_metrics, /* result_id= */ 1008); + EXPECT_THAT( + stages, + ElementsAre( + ScrollJankV4Frame::Stage{ScrollStart{}}, + ScrollJankV4Frame::Stage{ScrollUpdates( + Real{.first_input_generation_ts = MillisecondsTicks(205), + .last_input_generation_ts = MillisecondsTicks(205), + .has_inertial_input = false, + .abs_total_raw_delta_pixels = 70, + .max_abs_inertial_raw_delta_pixels = 0, + .first_input_trace_id = TraceId(7)}, + /* synthetic= */ std::nullopt)})); + EXPECT_THAT(events_metrics, AllHaveResultId(1008)); + } + + // Frame 9: 2nd GSU of scroll 3. + { + EventMetrics::List events_metrics; + events_metrics.push_back(metrics_creator_.GestureScrollUpdateBuilder() + .SetTimestamp(MillisecondsTicks(220)) + .SetScrollBeginArrivalTimestamp(scroll3_id) + .SetDelta(80) + .SetIsSynthetic(false) + .SetTraceId(TraceId(8)) + .Build()); + auto stages = + calculator_->CalculateStages(events_metrics, /* result_id= */ 1009); + EXPECT_THAT(stages, + ElementsAre(ScrollJankV4Frame::Stage{ScrollUpdates( + Real{.first_input_generation_ts = MillisecondsTicks(220), + .last_input_generation_ts = MillisecondsTicks(220), + .has_inertial_input = false, + .abs_total_raw_delta_pixels = 80, + .max_abs_inertial_raw_delta_pixels = 0, + .first_input_trace_id = TraceId(8)}, + /* synthetic= */ std::nullopt)})); + EXPECT_THAT(events_metrics, AllHaveResultId(1009)); + } + + // Frame 10: Standalone GSE of scroll 3. + { + EventMetrics::List events_metrics; + events_metrics.push_back(metrics_creator_.GestureScrollEndBuilder() + .SetTimestamp(MillisecondsTicks(235)) + .SetScrollBeginArrivalTimestamp(scroll3_id) + .Build()); + auto stages = + calculator_->CalculateStages(events_metrics, /* result_id= */ 1010); + EXPECT_THAT(stages, ElementsAre(ScrollJankV4Frame::Stage{ScrollEnd{}})); + EXPECT_THAT(events_metrics, AllHaveResultId(1010)); + } +} + +TEST_F(ScrollJankV4FrameStageScrollIdBasedCalculatorTest, OverlappingScrolls) { + // Frame 1: 1st GSU of scroll 1. + base::TimeTicks scroll1_id = MillisecondsTicks(100); + { + EventMetrics::List events_metrics; + events_metrics.push_back(metrics_creator_.FirstGestureScrollUpdateBuilder() + .SetTimestamp(MillisecondsTicks(105)) + .SetScrollBeginArrivalTimestamp(scroll1_id) + .SetDelta(100) + .SetIsSynthetic(false) + .SetTraceId(TraceId(1)) + .Build()); + auto stages = + calculator_->CalculateStages(events_metrics, /* result_id= */ 1001); + EXPECT_THAT( + stages, + ElementsAre( + ScrollJankV4Frame::Stage{ScrollStart{}}, + ScrollJankV4Frame::Stage{ScrollUpdates( + Real{.first_input_generation_ts = MillisecondsTicks(105), + .last_input_generation_ts = MillisecondsTicks(105), + .has_inertial_input = false, + .abs_total_raw_delta_pixels = 100, + .max_abs_inertial_raw_delta_pixels = 0, + .first_input_trace_id = TraceId(1)}, + /* synthetic= */ std::nullopt)})); + EXPECT_THAT(events_metrics, AllHaveResultId(1001)); + } + + // Frame 2: 2nd GSU of scroll 1 and 1st GSU of scroll 2. The calculator should + // count the frame towards scroll 1 and end scroll 1. + base::TimeTicks scroll2_id = MillisecondsTicks(115); + { + EventMetrics::List events_metrics; + events_metrics.push_back(metrics_creator_.GestureScrollUpdateBuilder() + .SetTimestamp(MillisecondsTicks(120)) + .SetScrollBeginArrivalTimestamp(scroll2_id) + .SetDelta(200) + .SetIsSynthetic(false) + .SetTraceId(TraceId(2)) + .Build()); + events_metrics.push_back(metrics_creator_.GestureScrollUpdateBuilder() + .SetTimestamp(MillisecondsTicks(125)) + .SetScrollBeginArrivalTimestamp(scroll1_id) + .SetDelta(50) + .SetIsSynthetic(false) + .SetTraceId(TraceId(3)) + .Build()); + auto stages = + calculator_->CalculateStages(events_metrics, /* result_id= */ 1002); + EXPECT_THAT( + stages, + ElementsAre(ScrollJankV4Frame::Stage{ScrollUpdates( + Real{ + .first_input_generation_ts = MillisecondsTicks(125), + .last_input_generation_ts = MillisecondsTicks(125), + .has_inertial_input = false, + .abs_total_raw_delta_pixels = 50, + .max_abs_inertial_raw_delta_pixels = 0, + .first_input_trace_id = TraceId(3), + }, + /* synthetic= */ std::nullopt)}, + ScrollJankV4Frame::Stage{ScrollEnd{}})); + EXPECT_THAT(events_metrics, AllHaveResultId(1002)); + } + + // Frame 3: 2nd GSU of scroll 2. The calculator should treat this as the first + // frame of scroll 2. + { + EventMetrics::List events_metrics; + events_metrics.push_back(metrics_creator_.GestureScrollUpdateBuilder() + .SetTimestamp(MillisecondsTicks(135)) + .SetScrollBeginArrivalTimestamp(scroll2_id) + .SetDelta(300) + .SetIsSynthetic(false) + .SetTraceId(TraceId(4)) + .Build()); + auto stages = + calculator_->CalculateStages(events_metrics, /* result_id= */ 1003); + EXPECT_THAT( + stages, + ElementsAre( + ScrollJankV4Frame::Stage{ScrollStart{}}, + ScrollJankV4Frame::Stage{ScrollUpdates( + Real{.first_input_generation_ts = MillisecondsTicks(135), + .last_input_generation_ts = MillisecondsTicks(135), + .has_inertial_input = false, + .abs_total_raw_delta_pixels = 300, + .max_abs_inertial_raw_delta_pixels = 0, + .first_input_trace_id = TraceId(4)}, + /* synthetic= */ std::nullopt)})); + EXPECT_THAT(events_metrics, AllHaveResultId(1003)); + } +} + +TEST_F(ScrollJankV4FrameStageScrollIdBasedCalculatorTest, + IgnoreUpdatesAfterScrollAlreadyEnded) { + // Frame 1: 1st GSU and GSE of scroll 1. + base::TimeTicks scroll1_id = MillisecondsTicks(100); + { + EventMetrics::List events_metrics; + events_metrics.push_back(metrics_creator_.FirstGestureScrollUpdateBuilder() + .SetTimestamp(MillisecondsTicks(105)) + .SetScrollBeginArrivalTimestamp(scroll1_id) + .SetDelta(100) + .SetIsSynthetic(false) + .SetTraceId(TraceId(1)) + .Build()); + events_metrics.push_back(metrics_creator_.GestureScrollEndBuilder() + .SetTimestamp(MillisecondsTicks(110)) + .SetScrollBeginArrivalTimestamp(scroll1_id) + .Build()); + auto stages = + calculator_->CalculateStages(events_metrics, /* result_id= */ 1001); + EXPECT_THAT( + stages, + ElementsAre( + ScrollJankV4Frame::Stage{ScrollStart{}}, + ScrollJankV4Frame::Stage{ScrollUpdates( + Real{.first_input_generation_ts = MillisecondsTicks(105), + .last_input_generation_ts = MillisecondsTicks(105), + .has_inertial_input = false, + .abs_total_raw_delta_pixels = 100, + .max_abs_inertial_raw_delta_pixels = 0, + .first_input_trace_id = TraceId(1)}, + /* synthetic= */ std::nullopt)}, + ScrollJankV4Frame::Stage{ScrollEnd{}})); + EXPECT_THAT(events_metrics, AllHaveResultId(1001)); + } + + // Frame 2: 2nd GSU for scroll 1. The calculator should ignore this late GSU + // because it's already seen a GSE for the same scroll. + { + EventMetrics::List events_metrics; + events_metrics.push_back(metrics_creator_.GestureScrollUpdateBuilder() + .SetTimestamp(MillisecondsTicks(120)) + .SetScrollBeginArrivalTimestamp(scroll1_id) + .SetDelta(200) + .SetIsSynthetic(false) + .SetTraceId(TraceId(2)) + .Build()); + auto stages = + calculator_->CalculateStages(events_metrics, /* result_id= */ 1002); + EXPECT_THAT(stages, IsEmpty()); + EXPECT_THAT(events_metrics, AllHaveResultId(1002)); + } +} + +TEST_F(ScrollJankV4FrameStageScrollIdBasedCalculatorTest, + IgnoreUpdatesFromPreviousScrolls) { + // Frame 1: 1st GSU for scroll 1. + base::TimeTicks scroll1_id = MillisecondsTicks(100); + { + EventMetrics::List events_metrics; + events_metrics.push_back(metrics_creator_.FirstGestureScrollUpdateBuilder() + .SetTimestamp(MillisecondsTicks(105)) + .SetScrollBeginArrivalTimestamp(scroll1_id) + .SetDelta(100) + .SetIsSynthetic(false) + .SetTraceId(TraceId(1)) + .Build()); + auto stages = + calculator_->CalculateStages(events_metrics, /* result_id= */ 1001); + EXPECT_THAT( + stages, + ElementsAre( + ScrollJankV4Frame::Stage{ScrollStart{}}, + ScrollJankV4Frame::Stage{ScrollUpdates( + Real{.first_input_generation_ts = MillisecondsTicks(105), + .last_input_generation_ts = MillisecondsTicks(105), + .has_inertial_input = false, + .abs_total_raw_delta_pixels = 100, + .max_abs_inertial_raw_delta_pixels = 0, + .first_input_trace_id = TraceId(1)}, + /* synthetic= */ std::nullopt)})); + EXPECT_THAT(events_metrics, AllHaveResultId(1001)); + } + + // Frame 2: 1st GSU for scroll 2. + base::TimeTicks scroll2_id = MillisecondsTicks(110); + { + EventMetrics::List events_metrics; + events_metrics.push_back(metrics_creator_.FirstGestureScrollUpdateBuilder() + .SetTimestamp(MillisecondsTicks(115)) + .SetScrollBeginArrivalTimestamp(scroll2_id) + .SetDelta(200) + .SetIsSynthetic(false) + .SetTraceId(TraceId(2)) + .Build()); + auto stages = + calculator_->CalculateStages(events_metrics, /* result_id= */ 1002); + EXPECT_THAT( + stages, + ElementsAre( + ScrollJankV4Frame::Stage{ScrollEnd{}}, + ScrollJankV4Frame::Stage{ScrollStart{}}, + ScrollJankV4Frame::Stage{ScrollUpdates( + Real{.first_input_generation_ts = MillisecondsTicks(115), + .last_input_generation_ts = MillisecondsTicks(115), + .has_inertial_input = false, + .abs_total_raw_delta_pixels = 200, + .max_abs_inertial_raw_delta_pixels = 0, + .first_input_trace_id = TraceId(2)}, + /* synthetic= */ std::nullopt)})); + EXPECT_THAT(events_metrics, AllHaveResultId(1002)); + } + + // Frame 3: 2nd GSU for scroll 1. The calculator should IGNORE this late GSU + // because it's already seen a GSU for the next scroll. + { + EventMetrics::List events_metrics; + events_metrics.push_back(metrics_creator_.GestureScrollUpdateBuilder() + .SetTimestamp(MillisecondsTicks(120)) + .SetScrollBeginArrivalTimestamp(scroll1_id) + .SetDelta(300) + .SetIsSynthetic(false) + .SetTraceId(TraceId(3)) + .Build()); + auto stages = + calculator_->CalculateStages(events_metrics, /* result_id= */ 1003); + EXPECT_THAT(stages, IsEmpty()); + EXPECT_THAT(events_metrics, AllHaveResultId(1003)); + } + + // Frame 4: 2nd GSU for scroll 2. The calculator should process this GSU + // because scroll 2 hasn't ended yet. + { + EventMetrics::List events_metrics; + events_metrics.push_back(metrics_creator_.GestureScrollUpdateBuilder() + .SetTimestamp(MillisecondsTicks(125)) + .SetScrollBeginArrivalTimestamp(scroll2_id) + .SetDelta(400) + .SetIsSynthetic(false) + .SetTraceId(TraceId(4)) + .Build()); + auto stages = + calculator_->CalculateStages(events_metrics, /* result_id= */ 1004); + EXPECT_THAT(stages, + ElementsAre(ScrollJankV4Frame::Stage{ScrollUpdates( + Real{.first_input_generation_ts = MillisecondsTicks(125), + .last_input_generation_ts = MillisecondsTicks(125), + .has_inertial_input = false, + .abs_total_raw_delta_pixels = 400, + .max_abs_inertial_raw_delta_pixels = 0, + .first_input_trace_id = TraceId(4)}, + /* synthetic= */ std::nullopt)})); + EXPECT_THAT(events_metrics, AllHaveResultId(1004)); + } +} + +TEST_F(ScrollJankV4FrameStageScrollIdBasedCalculatorTest, + IgnoreEndsFromPreviousScrolls) { + // Frame 1: 1st GSU of scroll 1. + base::TimeTicks scroll1_id = MillisecondsTicks(100); + { + EventMetrics::List events_metrics; + events_metrics.push_back(metrics_creator_.FirstGestureScrollUpdateBuilder() + .SetTimestamp(MillisecondsTicks(105)) + .SetScrollBeginArrivalTimestamp(scroll1_id) + .SetDelta(100) + .SetIsSynthetic(false) + .SetTraceId(TraceId(1)) + .Build()); + auto stages = + calculator_->CalculateStages(events_metrics, /* result_id= */ 1001); + EXPECT_THAT( + stages, + ElementsAre( + ScrollJankV4Frame::Stage{ScrollStart{}}, + ScrollJankV4Frame::Stage{ScrollUpdates( + Real{.first_input_generation_ts = MillisecondsTicks(105), + .last_input_generation_ts = MillisecondsTicks(105), + .has_inertial_input = false, + .abs_total_raw_delta_pixels = 100, + .max_abs_inertial_raw_delta_pixels = 0, + .first_input_trace_id = TraceId(1)}, + /* synthetic= */ std::nullopt)})); + EXPECT_THAT(events_metrics, AllHaveResultId(1001)); + } + + // Frame 2: 1st GSU of scroll 2. + base::TimeTicks scroll2_id = MillisecondsTicks(110); + { + EventMetrics::List events_metrics; + events_metrics.push_back(metrics_creator_.FirstGestureScrollUpdateBuilder() + .SetTimestamp(MillisecondsTicks(115)) + .SetScrollBeginArrivalTimestamp(scroll2_id) + .SetDelta(200) + .SetIsSynthetic(false) + .SetTraceId(TraceId(2)) + .Build()); + auto stages = + calculator_->CalculateStages(events_metrics, /* result_id= */ 1002); + EXPECT_THAT( + stages, + ElementsAre( + ScrollJankV4Frame::Stage{ScrollEnd{}}, + ScrollJankV4Frame::Stage{ScrollStart{}}, + ScrollJankV4Frame::Stage{ScrollUpdates( + Real{.first_input_generation_ts = MillisecondsTicks(115), + .last_input_generation_ts = MillisecondsTicks(115), + .has_inertial_input = false, + .abs_total_raw_delta_pixels = 200, + .max_abs_inertial_raw_delta_pixels = 0, + .first_input_trace_id = TraceId(2)}, + /* synthetic= */ std::nullopt)})); + EXPECT_THAT(events_metrics, AllHaveResultId(1002)); + } + + // Frame 3: GSE for scroll 1. The calculator should IGNORE this late GSE + // because it's already seen a GSU for the next scroll. + { + EventMetrics::List events_metrics; + events_metrics.push_back(metrics_creator_.GestureScrollEndBuilder() + .SetTimestamp(MillisecondsTicks(120)) + .SetScrollBeginArrivalTimestamp(scroll1_id) + .Build()); + auto stages = + calculator_->CalculateStages(events_metrics, /* result_id= */ 1003); + EXPECT_THAT(stages, IsEmpty()); + EXPECT_THAT(events_metrics, AllHaveResultId(1003)); + } + + // Frame 4: 2nd GSU for scroll 2. The calculator should process this GSU + // because scroll 2 hasn't ended yet. + { + EventMetrics::List events_metrics; + events_metrics.push_back(metrics_creator_.GestureScrollUpdateBuilder() + .SetTimestamp(MillisecondsTicks(125)) + .SetScrollBeginArrivalTimestamp(scroll2_id) + .SetDelta(400) + .SetIsSynthetic(false) + .SetTraceId(TraceId(4)) + .Build()); + auto stages = + calculator_->CalculateStages(events_metrics, /* result_id= */ 1004); + EXPECT_THAT(stages, + ElementsAre(ScrollJankV4Frame::Stage{ScrollUpdates( + Real{.first_input_generation_ts = MillisecondsTicks(125), + .last_input_generation_ts = MillisecondsTicks(125), + .has_inertial_input = false, + .abs_total_raw_delta_pixels = 400, + .max_abs_inertial_raw_delta_pixels = 0, + .first_input_trace_id = TraceId(4)}, + /* synthetic= */ std::nullopt)})); + EXPECT_THAT(events_metrics, AllHaveResultId(1004)); + } +} + +TEST_F(ScrollJankV4FrameStageScrollIdBasedCalculatorTest, RealUpdatesOnly) { + base::TimeTicks scroll1_id = MillisecondsTicks(100); + + EventMetrics::List events_metrics; + events_metrics.push_back(metrics_creator_.FirstGestureScrollUpdateBuilder() + .SetTimestamp(MillisecondsTicks(105)) + .SetScrollBeginArrivalTimestamp(scroll1_id) + .SetDelta(200) + .SetIsSynthetic(false) + .SetTraceId(TraceId(2)) + .Build()); + events_metrics.push_back(metrics_creator_.GestureScrollUpdateBuilder() + .SetTimestamp(MillisecondsTicks(120)) + .SetScrollBeginArrivalTimestamp(scroll1_id) + .SetDelta(300) + .SetIsSynthetic(false) + .SetTraceId(TraceId(3)) + .Build()); + + auto stages = calculator_->CalculateStages(events_metrics, kResultId); + EXPECT_THAT( + stages, + ElementsAre(ScrollJankV4Frame::Stage{ScrollStart{}}, + ScrollJankV4Frame::Stage{ScrollUpdates( + Real{ + .first_input_generation_ts = MillisecondsTicks(105), + .last_input_generation_ts = MillisecondsTicks(120), + .has_inertial_input = false, + .abs_total_raw_delta_pixels = 500, + .max_abs_inertial_raw_delta_pixels = 0, + .first_input_trace_id = TraceId(2), + }, + /* synthetic= */ std::nullopt)})); +} + +TEST_F(ScrollJankV4FrameStageScrollIdBasedCalculatorTest, + RealUpdatesOnlyInertial) { + base::TimeTicks scroll1_id = MillisecondsTicks(100); + + EventMetrics::List events_metrics; + events_metrics.push_back(metrics_creator_.InertialGestureScrollUpdateBuilder() + .SetTimestamp(MillisecondsTicks(130)) + .SetScrollBeginArrivalTimestamp(scroll1_id) + .SetDelta(-20) + .SetIsSynthetic(false) + .SetTraceId(TraceId(2)) + .Build()); + events_metrics.push_back(metrics_creator_.InertialGestureScrollUpdateBuilder() + .SetTimestamp(MillisecondsTicks(110)) + .SetScrollBeginArrivalTimestamp(scroll1_id) + .SetDelta(-30) + .SetIsSynthetic(false) + .SetTraceId(TraceId(3)) + .Build()); + + auto stages = calculator_->CalculateStages(events_metrics, kResultId); + EXPECT_THAT( + stages, + ElementsAre(ScrollJankV4Frame::Stage{ScrollStart{}}, + ScrollJankV4Frame::Stage{ScrollUpdates( + Real{ + .first_input_generation_ts = MillisecondsTicks(110), + .last_input_generation_ts = MillisecondsTicks(130), + .has_inertial_input = true, + .abs_total_raw_delta_pixels = 50, + .max_abs_inertial_raw_delta_pixels = 30, + .first_input_trace_id = TraceId(3), + }, + /* synthetic= */ std::nullopt)})); +} + +TEST_F(ScrollJankV4FrameStageScrollIdBasedCalculatorTest, + SyntheticUpdatesOnly) { + base::TimeTicks scroll1_id = MillisecondsTicks(100); + + EventMetrics::List events_metrics; + events_metrics.push_back(metrics_creator_.GestureScrollUpdateBuilder() + .SetTimestamp(MillisecondsTicks(105)) + .SetScrollBeginArrivalTimestamp(scroll1_id) + .SetIsSynthetic(true) + .SetDispatchArgs(DispatchBeginFrameArgs{ + .frame_time = MillisecondsTicks(110)}) + .SetTraceId(TraceId(2)) + .Build()); + events_metrics.push_back(metrics_creator_.GestureScrollUpdateBuilder() + .SetTimestamp(MillisecondsTicks(104)) + .SetScrollBeginArrivalTimestamp(scroll1_id) + .SetIsSynthetic(true) + .SetDispatchArgs(DispatchBeginFrameArgs{ + .frame_time = MillisecondsTicks(125)}) + .SetTraceId(TraceId(3)) + .Build()); + + auto stages = calculator_->CalculateStages(events_metrics, kResultId); + EXPECT_THAT( + stages, + ElementsAre(ScrollJankV4Frame::Stage{ScrollStart{}}, + ScrollJankV4Frame::Stage{ScrollUpdates( + /* real= */ std::nullopt, + Synthetic{ + .first_input_begin_frame_ts = MillisecondsTicks(110), + .has_inertial_input = false, + .first_input_trace_id = TraceId(2), + })})); +} + +TEST_F(ScrollJankV4FrameStageScrollIdBasedCalculatorTest, + SyntheticUpdatesOnlyInertial) { + base::TimeTicks scroll1_id = MillisecondsTicks(100); + + EventMetrics::List events_metrics; + events_metrics.push_back(metrics_creator_.InertialGestureScrollUpdateBuilder() + .SetTimestamp(MillisecondsTicks(104)) + .SetScrollBeginArrivalTimestamp(scroll1_id) + .SetIsSynthetic(true) + .SetDispatchArgs(DispatchBeginFrameArgs{ + .frame_time = MillisecondsTicks(125)}) + .SetTraceId(TraceId(2)) + .Build()); + events_metrics.push_back(metrics_creator_.InertialGestureScrollUpdateBuilder() + .SetTimestamp(MillisecondsTicks(105)) + .SetScrollBeginArrivalTimestamp(scroll1_id) + .SetIsSynthetic(true) + .SetDispatchArgs(DispatchBeginFrameArgs{ + .frame_time = MillisecondsTicks(110)}) + .SetTraceId(TraceId(3)) + .Build()); + + auto stages = calculator_->CalculateStages(events_metrics, kResultId); + EXPECT_THAT( + stages, + ElementsAre(ScrollJankV4Frame::Stage{ScrollStart{}}, + ScrollJankV4Frame::Stage{ScrollUpdates( + /* real= */ std::nullopt, + Synthetic{ + .first_input_begin_frame_ts = MillisecondsTicks(110), + .has_inertial_input = true, + .first_input_trace_id = TraceId(3), + })})); +} + +TEST_F(ScrollJankV4FrameStageScrollIdBasedCalculatorTest, + StatsRealAndSyntheticUpdates) { + base::TimeTicks scroll1_id = MillisecondsTicks(100); + + EventMetrics::List events_metrics; + events_metrics.push_back(metrics_creator_.GestureScrollUpdateBuilder() + .SetTimestamp(MillisecondsTicks(105)) + .SetScrollBeginArrivalTimestamp(scroll1_id) + .SetDelta(200) + .SetIsSynthetic(false) + .SetDispatchArgs(DispatchBeginFrameArgs{ + .frame_time = MillisecondsTicks(124)}) + .SetTraceId(TraceId(2)) + .Build()); + events_metrics.push_back(metrics_creator_.GestureScrollUpdateBuilder() + .SetTimestamp(MillisecondsTicks(104)) + .SetScrollBeginArrivalTimestamp(scroll1_id) + .SetDelta(300) + .SetIsSynthetic(true) + .SetDispatchArgs(DispatchBeginFrameArgs{ + .frame_time = MillisecondsTicks(125)}) + .SetTraceId(TraceId(3)) + .Build()); + + auto stages = calculator_->CalculateStages(events_metrics, kResultId); + EXPECT_THAT( + stages, + ElementsAre(ScrollJankV4Frame::Stage{ScrollStart{}}, + ScrollJankV4Frame::Stage{ScrollUpdates( + Real{ + .first_input_generation_ts = MillisecondsTicks(105), + .last_input_generation_ts = MillisecondsTicks(105), + .has_inertial_input = false, + .abs_total_raw_delta_pixels = 200, + .max_abs_inertial_raw_delta_pixels = 0, + .first_input_trace_id = TraceId(2), + }, + Synthetic{ + .first_input_begin_frame_ts = MillisecondsTicks(125), + .has_inertial_input = false, + .first_input_trace_id = TraceId(3), + })})); +} + +} // namespace } // namespace cc
diff --git a/cc/trees/layer_tree_frame_sink.cc b/cc/trees/layer_tree_frame_sink.cc index 299fc2c..3ef06da6 100644 --- a/cc/trees/layer_tree_frame_sink.cc +++ b/cc/trees/layer_tree_frame_sink.cc
@@ -38,6 +38,9 @@ ContextLostForwarder& operator=(const ContextLostForwarder&) = delete; void OnContextLost() override { + if (!task_runner_) { + return; + } task_runner_->PostTask( FROM_HERE, base::BindOnce(&LayerTreeFrameSink::OnContextLost, frame_sink_));
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index 996e5c3..6bc62d6 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn
@@ -1281,6 +1281,7 @@ android_library("xr_java") { sources = [ + "java/src/org/chromium/chrome/browser/xr/scenecore/XrModuleBridge.java", "java/src/org/chromium/chrome/browser/xr/scenecore/XrModuleProvider.java", ] @@ -1292,6 +1293,7 @@ "//components/module_installer/android:module_interface_java", "//third_party/androidx:androidx_annotation_annotation_java", "//third_party/androidx:androidx_appcompat_appcompat_java", + "//third_party/jni_zero:jni_zero_java", "//ui/android:ui_java", ] @@ -2394,6 +2396,7 @@ ":chrome_test_java", "//chrome/android/features/keyboard_accessory:test_java", "//chrome/android/modules/on_demand:javatests", + "//chrome/android/modules/xr:javatests", "//chrome/browser/autofill/android:test_java", "//chrome/browser/autofill/test:test_java", "//chrome/browser/banners/android:javatests", @@ -3046,6 +3049,7 @@ "java/src/org/chromium/chrome/browser/media/MediaCaptureDevicesDispatcherAndroid.java", "java/src/org/chromium/chrome/browser/media/PictureInPictureActivity.java", "java/src/org/chromium/chrome/browser/media/PictureInPictureBoundsCacheBridge.java", + "java/src/org/chromium/chrome/browser/media/VideoOverlayActivity.java", "java/src/org/chromium/chrome/browser/media/router/ChromeMediaRouterClient.java", "java/src/org/chromium/chrome/browser/metrics/LaunchMetrics.java", "java/src/org/chromium/chrome/browser/metrics/UmaSessionStats.java", @@ -3130,6 +3134,7 @@ "java/src/org/chromium/chrome/browser/webapps/WebApkUpdateDataFetcher.java", "java/src/org/chromium/chrome/browser/webapps/WebApkUpdateManager.java", "java/src/org/chromium/chrome/browser/webapps/WebappRegistry.java", + "java/src/org/chromium/chrome/browser/xr/scenecore/XrModuleBridge.java", ] if (enable_screen_capture) {
diff --git a/chrome/android/chrome_java_resources.gni b/chrome/android/chrome_java_resources.gni index af758b6..eac0f0e 100644 --- a/chrome/android/chrome_java_resources.gni +++ b/chrome/android/chrome_java_resources.gni
@@ -396,6 +396,7 @@ "java/res/drawable/tab_indicator.xml", "java/res/drawable/tablet_black_24dp.xml", "java/res/drawable/tablet_recent_tab_empty_state_illustration.xml", + "java/res/drawable/task_spark_24dp.xml", "java/res/drawable/text_cursor_lowend.xml", "java/res/drawable/tips_opt_in_logo.xml", "java/res/drawable/tips_promo_bottom_omnibox_logo.xml",
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni index d928318..a332444 100644 --- a/chrome/android/chrome_java_sources.gni +++ b/chrome/android/chrome_java_sources.gni
@@ -794,6 +794,7 @@ "java/src/org/chromium/chrome/browser/media/PictureInPicture.java", "java/src/org/chromium/chrome/browser/media/PictureInPictureActivity.java", "java/src/org/chromium/chrome/browser/media/PictureInPictureBoundsCacheBridge.java", + "java/src/org/chromium/chrome/browser/media/VideoOverlayActivity.java", "java/src/org/chromium/chrome/browser/media/document_picture_in_picture_header/DocumentPictureInPictureHeaderCoordinator.java", "java/src/org/chromium/chrome/browser/media/document_picture_in_picture_header/DocumentPictureInPictureHeaderDelegate.java", "java/src/org/chromium/chrome/browser/media/document_picture_in_picture_header/DocumentPictureInPictureHeaderMediator.java",
diff --git a/chrome/android/expectations/trichrome_chrome_64_32_bundle__xr.AndroidManifest.expected b/chrome/android/expectations/trichrome_chrome_64_32_bundle__xr.AndroidManifest.expected index 31b0f8d8..6497eb2 100644 --- a/chrome/android/expectations/trichrome_chrome_64_32_bundle__xr.AndroidManifest.expected +++ b/chrome/android/expectations/trichrome_chrome_64_32_bundle__xr.AndroidManifest.expected
@@ -22,6 +22,15 @@ <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="36"/> <uses-split android:name="chrome"/> <application> + <activity # DIFF-ANCHOR: 1f566b69 + android:name="org.chromium.chrome.browser.media.immersive_playback.ImmersiveVideoPlaybackActivity" + android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation" + android:excludeFromRecents="true" + android:exported="false" + android:noHistory="true" + android:theme="@style/Theme.Chromium.Activity"> + <property android:name="android.window.PROPERTY_XR_ACTIVITY_START_MODE" android:value="XR_ACTIVITY_START_MODE_FULL_SPACE_MANAGED"/> + </activity> # DIFF-ANCHOR: 1f566b69 <uses-library android:name="com.android.extensions.xr" android:required="false"/> </application> </manifest>
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_component/AccessorySheetViewTest.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_component/AccessorySheetViewTest.java index d0af9b0d..d683a7e9 100644 --- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_component/AccessorySheetViewTest.java +++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_component/AccessorySheetViewTest.java
@@ -60,6 +60,7 @@ import org.chromium.base.ThreadUtils; import org.chromium.base.test.util.CommandLineFlags; +import org.chromium.base.test.util.DisableIf; import org.chromium.base.test.util.Features.DisableFeatures; import org.chromium.base.test.util.Features.EnableFeatures; import org.chromium.chrome.browser.flags.ChromeFeatureList; @@ -74,6 +75,7 @@ import org.chromium.ui.AsyncViewProvider; import org.chromium.ui.AsyncViewStub; import org.chromium.ui.ViewProvider; +import org.chromium.ui.base.DeviceFormFactor; import org.chromium.ui.modelutil.LazyConstructionPropertyMcp; import org.chromium.ui.modelutil.PropertyModel; @@ -321,6 +323,7 @@ @Test @MediumTest + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testHeader() { Runnable runnable = mock(Runnable.class);
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/ArchivedTabsDialogCoordinatorTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/ArchivedTabsDialogCoordinatorTest.java index 0aaaf88..2b28527 100644 --- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/ArchivedTabsDialogCoordinatorTest.java +++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/ArchivedTabsDialogCoordinatorTest.java
@@ -118,6 +118,7 @@ ChromeFeatureList.DRAW_CHROME_PAGES_EDGE_TO_EDGE, ChromeFeatureList.EDGE_TO_EDGE_BOTTOM_CHIN }) +@DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public class ArchivedTabsDialogCoordinatorTest { private static final String SYNC_GROUP_ID1 = "test_sync_group_id1"; private static final String SYNC_GROUP_ID2 = "test_sync_group_id2";
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupDialogPTTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupDialogPTTest.java index c9bc11614a..7c19176 100644 --- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupDialogPTTest.java +++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupDialogPTTest.java
@@ -23,6 +23,7 @@ import org.chromium.base.test.util.Batch; import org.chromium.base.test.util.CommandLineFlags; +import org.chromium.base.test.util.DisableIf; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.Features.DisableFeatures; import org.chromium.base.test.util.Features.EnableFeatures; @@ -66,6 +67,7 @@ ChromeFeatureList.ANDROID_THEME_MODULE }) @EnableFeatures(ChromeFeatureList.DATA_SHARING) +@DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public class TabGroupDialogPTTest { @Rule public AutoResetCtaTransitTestRule mCtaTestRule =
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupListBottomSheetTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupListBottomSheetTest.java index a6fa0e51..224dcb3f 100644 --- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupListBottomSheetTest.java +++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupListBottomSheetTest.java
@@ -21,6 +21,7 @@ import org.chromium.base.ThreadUtils; import org.chromium.base.test.util.Batch; import org.chromium.base.test.util.CommandLineFlags; +import org.chromium.base.test.util.DisableIf; import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.Features; import org.chromium.base.test.util.Features.DisableFeatures; @@ -57,6 +58,7 @@ ChromeFeatureList.ANDROID_THEME_MODULE }) @Batch(Batch.PER_CLASS) +@DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public class TabGroupListBottomSheetTest { @Rule public AutoResetCtaTransitTestRule mCtaTestRule =
diff --git a/chrome/android/java/res/drawable/task_spark_24dp.xml b/chrome/android/java/res/drawable/task_spark_24dp.xml new file mode 100644 index 0000000..aef2c7f9 --- /dev/null +++ b/chrome/android/java/res/drawable/task_spark_24dp.xml
@@ -0,0 +1,15 @@ +<?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="M480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480ZM880,480Q880,490 879.5,500Q879,510 878,520Q860,520 840.5,520Q821,520 800,520Q800,494 800,488Q800,482 800,480Q800,461 798,443Q796,425 792,408L856,344Q867,376 873.5,410Q880,444 880,480ZM80,480Q80,397 111.5,324Q143,251 197,197Q251,143 324,111.5Q397,80 480,80Q544,80 602.5,98.5Q661,117 710,152L652,210Q614,186 571,173Q528,160 480,160Q346,160 253,253Q160,346 160,480Q160,614 253,707Q346,800 480,800Q482,800 488,800Q494,800 520,800Q520,821 520,840.5Q520,860 520,878Q510,879 500,879.5Q490,880 480,880Q397,880 324,848.5Q251,817 197,763Q143,709 111.5,636Q80,563 80,480ZM740,920Q734,920 732,914Q716,853 671.5,808.5Q627,764 566,748Q560,746 560,740Q560,733 566,732Q627,716 671.5,671.5Q716,627 732,566Q734,560 740,560Q747,560 748,566Q765,627 809,671.5Q853,716 914,732Q920,733 920,740Q920,746 914,748Q853,764 808.5,808.5Q764,853 748,914Q747,920 740,920ZM424,664L880,207Q866,193 852,179Q838,165 824,151L424,552L310,438L254,494L424,664Z" /> +</vector> \ No newline at end of file
diff --git a/chrome/android/java/res/layout/gesture_user_education_iph_layout.xml b/chrome/android/java/res/layout/gesture_user_education_iph_layout.xml index 6b2b98f..ba1fcc60 100644 --- a/chrome/android/java/res/layout/gesture_user_education_iph_layout.xml +++ b/chrome/android/java/res/layout/gesture_user_education_iph_layout.xml
@@ -9,7 +9,8 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:accessibilityPaneTitle="@string/iph_gesture_user_education_layout_description" - xmlns:tools="http://schemas.android.com/tools"> + xmlns:tools="http://schemas.android.com/tools" + xmlns:app="http://schemas.android.com/apk/res-auto"> <LinearLayout android:layout_width="match_parent" @@ -48,7 +49,8 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="@dimen/gesture_user_education_arrow_margin_bottom" - android:layout_gravity="start" /> + android:layout_gravity="start" + app:lottie_colorFilter="@macro/default_control_color_active" /> </LinearLayout> <TextView
diff --git a/chrome/android/java/res/raw/back_gesture_arrow_animation.json b/chrome/android/java/res/raw/back_gesture_arrow_animation.json index 848a796..2b8d9b97b 100644 --- a/chrome/android/java/res/raw/back_gesture_arrow_animation.json +++ b/chrome/android/java/res/raw/back_gesture_arrow_animation.json
@@ -1 +1 @@ -{"v":"5.9.0","fr":60,"ip":0,"op":119,"w":175,"h":147,"nm":"Back Gesture Arrow","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Small Arrow","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":45,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.543],"y":[-0.003]},"t":55,"s":[100]},{"i":{"x":[0.298],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":80,"s":[60]},{"t":100,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"s":true,"x":{"a":1,"k":[{"i":{"x":[0.148],"y":[0.996]},"o":{"x":[0.167],"y":[0.167]},"t":15,"s":[16]},{"t":45,"s":[140.836]}],"ix":3},"y":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":15,"s":[90]},{"t":45,"s":[90.154]}],"ix":4}},"a":{"a":0,"k":[19.113,21.725,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":55,"s":[100,100,100]},{"t":80,"s":[130,130,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-2.967,1.928],[-1.529,1.691],[0.141,2.246],[1.385,1.443],[1.69,1.103],[4.566,2.982],[2.582,0.392],[2.075,-2.264],[-0.595,-2.882],[0.004,-3.222],[0.66,-2.686],[-0.976,-2.589],[-3.528,0.063],[-2.678,1.735],[-1.285,0.837]],"o":[[2.967,-1.928],[1.926,-1.251],[1.533,-1.691],[-0.126,-1.972],[-1.385,-1.443],[-4.562,-2.982],[-2.167,-1.417],[-3.12,-0.474],[-2.17,2.368],[0.652,3.159],[0,2.76],[-0.656,2.682],[1.209,3.215],[3.219,-0.06],[1.285,-0.836],[0,0]],"v":[[21.422,37.341],[30.329,31.559],[35.737,27.345],[38.213,21.218],[35.642,15.976],[30.863,12.31],[17.173,3.361],[10.163,0.098],[1.791,3.165],[0.391,12.251],[2.267,21.722],[0.7,29.835],[0.616,37.988],[8.79,43.449],[17.562,39.853],[21.422,37.344]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.827450980392,0.890196078431,0.992156862745,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[2.285,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":"Small Arrow","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Medium Arrow","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.543],"y":[-0.003]},"t":55,"s":[70]},{"i":{"x":[0.298],"y":[1.001]},"o":{"x":[0.167],"y":[0.167]},"t":80,"s":[30]},{"t":100,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"s":true,"x":{"a":1,"k":[{"i":{"x":[0.173],"y":[0.999]},"o":{"x":[0.167],"y":[0.167]},"t":15,"s":[16]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0],"y":[0]},"t":45,"s":[131.474]},{"t":80,"s":[132.659]}],"ix":3},"y":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":15,"s":[90]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":45,"s":[90]},{"t":80,"s":[90]}],"ix":4}},"a":{"a":0,"k":[27.8,31.6,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":55,"s":[100,100,100]},{"t":80,"s":[120,120,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-4.316,2.804],[-2.225,2.459],[0.205,3.266],[2.014,2.099],[2.458,1.604],[6.641,4.337],[3.756,0.57],[3.018,-3.293],[-0.865,-4.192],[0.006,-4.687],[0.96,-3.907],[-1.42,-3.767],[-5.132,0.092],[-3.895,2.523],[-1.87,1.216]],"o":[[4.316,-2.804],[2.802,-1.819],[2.23,-2.459],[-0.183,-2.868],[-2.014,-2.099],[-6.635,-4.337],[-3.151,-2.061],[-4.538,-0.689],[-3.157,3.444],[0.949,4.596],[0,4.014],[-0.954,3.901],[1.759,4.676],[4.682,-0.086],[1.87,-1.216],[0,0]],"v":[[31.16,54.314],[44.114,45.903],[51.981,39.774],[55.582,30.863],[51.843,23.238],[44.891,17.906],[24.98,4.889],[14.782,0.143],[2.605,4.604],[0.569,17.819],[3.298,31.595],[1.018,43.396],[0.896,55.256],[12.785,63.198],[25.545,57.968],[31.16,54.319]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.827450980392,0.890196078431,0.992156862745,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","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":"Medium Arrow","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Large Arrow","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.543],"y":[-0.003]},"t":55,"s":[70]},{"i":{"x":[0.298],"y":[1.001]},"o":{"x":[0.167],"y":[0.167]},"t":80,"s":[30]},{"t":100,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"s":true,"x":{"a":1,"k":[{"i":{"x":[0.262],"y":[0.995]},"o":{"x":[0.167],"y":[0.167]},"t":15,"s":[16]},{"t":45,"s":[122.119]}],"ix":3},"y":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":15,"s":[90]},{"t":45,"s":[90]}],"ix":4}},"a":{"a":0,"k":[34.75,39.5,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":55,"s":[100,100,100]},{"t":80,"s":[120,120,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-5.395,3.505],[-2.781,3.074],[0.257,4.083],[2.517,2.623],[3.072,2.005],[8.301,5.421],[4.695,0.713],[3.773,-4.117],[-1.082,-5.24],[0.007,-5.859],[1.2,-4.884],[-1.775,-4.709],[-6.415,0.114],[-4.868,3.154],[-2.337,1.52]],"o":[[5.395,-3.505],[3.502,-2.273],[2.788,-3.074],[-0.229,-3.585],[-2.517,-2.623],[-8.294,-5.421],[-3.939,-2.576],[-5.673,-0.861],[-3.946,4.305],[1.186,5.744],[0,5.018],[-1.193,4.876],[2.198,5.845],[5.853,-0.108],[2.337,-1.52],[0,0]],"v":[[38.95,67.893],[55.143,57.379],[64.977,49.718],[69.478,38.579],[64.803,29.048],[56.114,22.382],[31.224,6.111],[18.478,0.178],[3.256,5.755],[0.711,22.274],[4.123,39.494],[1.272,54.245],[1.12,69.07],[15.981,78.998],[31.932,72.46],[38.95,67.899]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.827450980392,0.890196078431,0.992156862745,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","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":"Large Arrow","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0}],"markers":[{"tm":123,"cm":"1","dr":0}]} \ No newline at end of file +{"v":"5.9.0","fr":60,"ip":0,"op":120,"w":175,"h":147,"nm":"Back Gesture Arrow","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Small Arrow","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":45,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.543],"y":[-0.003]},"t":55,"s":[100]},{"i":{"x":[0.298],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":80,"s":[60]},{"t":100,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"s":true,"x":{"a":1,"k":[{"i":{"x":[0.148],"y":[0.996]},"o":{"x":[0.167],"y":[0.167]},"t":15,"s":[16]},{"t":45,"s":[140.836]}],"ix":3},"y":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":15,"s":[90]},{"t":45,"s":[90.154]}],"ix":4}},"a":{"a":0,"k":[19.113,21.725,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":55,"s":[100,100,100]},{"t":80,"s":[130,130,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-2.967,1.928],[-1.529,1.691],[0.141,2.246],[1.385,1.443],[1.69,1.103],[4.566,2.982],[2.582,0.392],[2.075,-2.264],[-0.595,-2.882],[0.004,-3.222],[0.66,-2.686],[-0.976,-2.589],[-3.528,0.063],[-2.678,1.735],[-1.285,0.837]],"o":[[2.967,-1.928],[1.926,-1.251],[1.533,-1.691],[-0.126,-1.972],[-1.385,-1.443],[-4.562,-2.982],[-2.167,-1.417],[-3.12,-0.474],[-2.17,2.368],[0.652,3.159],[0,2.76],[-0.656,2.682],[1.209,3.215],[3.219,-0.06],[1.285,-0.836],[0,0]],"v":[[21.422,37.341],[30.329,31.559],[35.737,27.345],[38.213,21.218],[35.642,15.976],[30.863,12.31],[17.173,3.361],[10.163,0.098],[1.791,3.165],[0.391,12.251],[2.267,21.722],[0.7,29.835],[0.616,37.988],[8.79,43.449],[17.562,39.853],[21.422,37.344]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.827450980392,0.890196078431,0.992156862745,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[2.285,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":"Small Arrow","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Medium Arrow","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.543],"y":[-0.003]},"t":55,"s":[70]},{"i":{"x":[0.298],"y":[1.001]},"o":{"x":[0.167],"y":[0.167]},"t":80,"s":[30]},{"t":100,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"s":true,"x":{"a":1,"k":[{"i":{"x":[0.173],"y":[0.999]},"o":{"x":[0.167],"y":[0.167]},"t":15,"s":[16]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0],"y":[0]},"t":45,"s":[131.474]},{"t":80,"s":[132.659]}],"ix":3},"y":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":15,"s":[90]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":45,"s":[90]},{"t":80,"s":[90]}],"ix":4}},"a":{"a":0,"k":[27.8,31.6,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":55,"s":[100,100,100]},{"t":80,"s":[120,120,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-4.316,2.804],[-2.225,2.459],[0.205,3.266],[2.014,2.099],[2.458,1.604],[6.641,4.337],[3.756,0.57],[3.018,-3.293],[-0.865,-4.192],[0.006,-4.687],[0.96,-3.907],[-1.42,-3.767],[-5.132,0.092],[-3.895,2.523],[-1.87,1.216]],"o":[[4.316,-2.804],[2.802,-1.819],[2.23,-2.459],[-0.183,-2.868],[-2.014,-2.099],[-6.635,-4.337],[-3.151,-2.061],[-4.538,-0.689],[-3.157,3.444],[0.949,4.596],[0,4.014],[-0.954,3.901],[1.759,4.676],[4.682,-0.086],[1.87,-1.216],[0,0]],"v":[[31.16,54.314],[44.114,45.903],[51.981,39.774],[55.582,30.863],[51.843,23.238],[44.891,17.906],[24.98,4.889],[14.782,0.143],[2.605,4.604],[0.569,17.819],[3.298,31.595],[1.018,43.396],[0.896,55.256],[12.785,63.198],[25.545,57.968],[31.16,54.319]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.827450980392,0.890196078431,0.992156862745,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","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":"Medium Arrow","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Large Arrow","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.543],"y":[-0.003]},"t":55,"s":[70]},{"i":{"x":[0.298],"y":[1.001]},"o":{"x":[0.167],"y":[0.167]},"t":80,"s":[30]},{"t":100,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"s":true,"x":{"a":1,"k":[{"i":{"x":[0.262],"y":[0.995]},"o":{"x":[0.167],"y":[0.167]},"t":15,"s":[16]},{"t":45,"s":[122.119]}],"ix":3},"y":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":15,"s":[90]},{"t":45,"s":[90]}],"ix":4}},"a":{"a":0,"k":[34.75,39.5,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":55,"s":[100,100,100]},{"t":80,"s":[120,120,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-5.395,3.505],[-2.781,3.074],[0.257,4.083],[2.517,2.623],[3.072,2.005],[8.301,5.421],[4.695,0.713],[3.773,-4.117],[-1.082,-5.24],[0.007,-5.859],[1.2,-4.884],[-1.775,-4.709],[-6.415,0.114],[-4.868,3.154],[-2.337,1.52]],"o":[[5.395,-3.505],[3.502,-2.273],[2.788,-3.074],[-0.229,-3.585],[-2.517,-2.623],[-8.294,-5.421],[-3.939,-2.576],[-5.673,-0.861],[-3.946,4.305],[1.186,5.744],[0,5.018],[-1.193,4.876],[2.198,5.845],[5.853,-0.108],[2.337,-1.52],[0,0]],"v":[[38.95,67.893],[55.143,57.379],[64.977,49.718],[69.478,38.579],[64.803,29.048],[56.114,22.382],[31.224,6.111],[18.478,0.178],[3.256,5.755],[0.711,22.274],[4.123,39.494],[1.272,54.245],[1.12,69.07],[15.981,78.998],[31.932,72.46],[38.95,67.899]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.827450980392,0.890196078431,0.992156862745,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","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":"Large Arrow","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0}],"markers":[{"tm":123,"cm":"1","dr":0}]} \ No newline at end of file
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 b7b8882..c07f61e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -3489,11 +3489,6 @@ } @Override - public void showTipsNotificationsChannelSettings() { - TipsUtils.launchTipsNotificationsSettings(getContext()); - } - - @Override public void showPasswordCheckup() { Profile profile = getProfileSupplier().get(); if (profile == null) return;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java index fd47f3f..cfa5722e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
@@ -860,12 +860,6 @@ ControlContainer controlContainer = (ControlContainer) findViewById(R.id.control_container); - if (controlContainer == null) { - // omnibox_results_container_stub anchors off of control_container, and will - // crash during layout if control_container doesn't exist. - UiUtils.removeViewFromParent(findViewById(R.id.omnibox_results_container_stub)); - } - // Inflate the correct toolbar layout for the device. int toolbarLayoutId = getToolbarLayoutId(); if (toolbarLayoutId != ActivityUtils.NO_RESOURCE_ID && controlContainer != null) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutTrailingButtonsCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutTrailingButtonsCoordinator.java index 387093d..377a3405 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutTrailingButtonsCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutTrailingButtonsCoordinator.java
@@ -358,8 +358,11 @@ if (activity == null) return; var task = mTaskTracker.get(activity.getTaskId()); if (task == null) return; - long browserWindowPtr = task.getOrCreateNativeBrowserWindowPtr(mProfile); - boolean isOpened = mGlicKeyedService.isPanelShowingForBrowser(browserWindowPtr); + long browserWindowPtr = task.getNativeBrowserWindowPtr(mProfile, activity); + boolean isOpened = false; + if (browserWindowPtr != 0) { + isOpened = mGlicKeyedService.isPanelShowingForBrowser(browserWindowPtr); + } mIsGlicUiVisible = isOpened; if (mGlicButton != null) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/BrowserControlsManager.java b/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/BrowserControlsManager.java index 38badf44..f45be6f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/BrowserControlsManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/BrowserControlsManager.java
@@ -1399,7 +1399,6 @@ // When V2 flag is enabled, this logic is coordinated in TopControlsStacker. if (BrowserControlsUtils.doSyncMinHeightWithTotalHeightV2(mActivity)) return false; if (mDisableSyncMinHeightWithTotalHeight) return false; - return BrowserControlsUtils.doSyncMinHeightWithTotalHeight(mActivity); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/GestureUserEducationIphController.java b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/GestureUserEducationIphController.java index 599bdcf1..1cbdccf 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/GestureUserEducationIphController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/GestureUserEducationIphController.java
@@ -4,12 +4,16 @@ package org.chromium.chrome.browser.gesturenav; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.Keyframe; +import android.animation.ObjectAnimator; +import android.animation.PropertyValuesHolder; import android.view.GestureDetector; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; -import android.view.ViewPropertyAnimator; import android.view.Window; import android.view.accessibility.AccessibilityEvent; import android.widget.TextView; @@ -46,9 +50,7 @@ @NullMarked public class GestureUserEducationIphController { public static final int PAGE_HISTORY_MIN_OFFSET = -3; - // TODO(crbug.com/493307156): Confirm animation durations. - private static final int SLIDE_ANIMATION_DURATION_MS = 750; - private static final int ANIMATION_DELAY_MS = 750; + private static final int SLIDE_ANIMATION_DURATION_MS = 2000; private static final float ANIMATION_X_TRANSLATION = 24; private final ViewGroup mAnchorView; @@ -70,10 +72,11 @@ private @Nullable GestureDetector mDetector; private @Nullable View mGestureUserEducationIphLayout; private @Nullable LottieAnimationView mBackArrowAnimation; - private @Nullable ViewPropertyAnimator mTextBubbleAnimation; + private @Nullable ObjectAnimator mTextBubbleAnimation; private @Nullable Profile mProfile; private boolean mIsIphShowing; private boolean mIsGestureNavModeForTesting; + private boolean mDisableAnimationsForTesting; private @Nullable WebContentsAccessibility mWebContentsAccessibility; /** @@ -205,23 +208,42 @@ View iphBubble = mGestureUserEducationIphLayout.findViewById(R.id.iph_bubble); float density = iphBubble.getResources().getDisplayMetrics().density; - mTextBubbleAnimation = - iphBubble - .animate() - .translationX(rtlSign * ANIMATION_X_TRANSLATION * density) - .setInterpolator(Interpolators.STANDARD_INTERPOLATOR) - .setDuration(SLIDE_ANIMATION_DURATION_MS) - .withEndAction( - () -> { - iphBubble - .animate() - .setStartDelay(ANIMATION_DELAY_MS) - .translationX(0) - .setDuration(SLIDE_ANIMATION_DURATION_MS) - .setInterpolator( - Interpolators.STANDARD_INTERPOLATOR) - .start(); - }); + + float startValue = 0f; + float endValue = rtlSign * ANIMATION_X_TRANSLATION * density; + + // Define Keyframes based on the back arrow animation timings (120 frames total). + float f1 = 45f / 120f; + float f2 = 110f / 120f; + + Keyframe t0 = Keyframe.ofFloat(0f, startValue); + Keyframe t1 = Keyframe.ofFloat(f1, endValue); + Keyframe t2 = Keyframe.ofFloat(f2, endValue); + Keyframe t3 = Keyframe.ofFloat(1f, startValue); + + PropertyValuesHolder pvhX = + PropertyValuesHolder.ofKeyframe(View.TRANSLATION_X, t0, t1, t2, t3); + + mTextBubbleAnimation = ObjectAnimator.ofPropertyValuesHolder(iphBubble, pvhX); + mTextBubbleAnimation.setInterpolator(Interpolators.FAST_OUT_SLOW_IN_INTERPOLATOR); + mTextBubbleAnimation.setDuration(SLIDE_ANIMATION_DURATION_MS); + + // Keep back arrow lottie animation in sync. + mTextBubbleAnimation.addListener( + new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (mTextBubbleAnimation != null && mBackArrowAnimation != null) { + mTextBubbleAnimation.start(); + mBackArrowAnimation.playAnimation(); + } + } + }); + + if (mDisableAnimationsForTesting) { + return; + } + mTextBubbleAnimation.start(); mBackArrowAnimation.playAnimation(); } @@ -241,11 +263,11 @@ } if (mScrimPropertyModel != null) { - mScrimManager.hideScrim(mScrimPropertyModel, false); + mScrimManager.hideScrim(mScrimPropertyModel, true); } if (mTextBubbleAnimation != null) { - mTextBubbleAnimation.setListener(null); + mTextBubbleAnimation.removeAllListeners(); mTextBubbleAnimation.cancel(); } @@ -303,4 +325,8 @@ void setWebContentsAccessibilityForTesting(WebContentsAccessibility webContentsAccessibility) { mWebContentsAccessibility = webContentsAccessibility; } + + void setDisableAnimationsForTesting(boolean disableAnimationsForTesting) { + mDisableAnimationsForTesting = disableAnimationsForTesting; + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/PictureInPictureActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/media/PictureInPictureActivity.java index fa17fa2..fa6ec3a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/media/PictureInPictureActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/media/PictureInPictureActivity.java
@@ -34,7 +34,6 @@ import androidx.annotation.VisibleForTesting; import org.jni_zero.CalledByNative; -import org.jni_zero.NativeMethods; import org.chromium.base.ContextUtils; import org.chromium.base.IntentUtils; @@ -42,27 +41,18 @@ import org.chromium.base.MathUtils; import org.chromium.base.UnguessableToken; import org.chromium.base.metrics.RecordHistogram; -import org.chromium.base.supplier.OneshotSupplier; -import org.chromium.base.supplier.OneshotSupplierImpl; 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.flags.ChromeFeatureList; -import org.chromium.chrome.browser.init.AsyncInitializationActivity; -import org.chromium.chrome.browser.profiles.Profile; -import org.chromium.chrome.browser.profiles.ProfileProvider; -import org.chromium.chrome.browser.tab.EmptyTabObserver; import org.chromium.chrome.browser.tab.Tab; -import org.chromium.chrome.browser.tab.TabUtils; import org.chromium.components.thinwebview.CompositorView; import org.chromium.components.thinwebview.CompositorViewFactory; import org.chromium.components.thinwebview.ThinWebViewConstraints; -import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.overlay_window.PlaybackState; import org.chromium.media.MediaFeatures; import org.chromium.media_session.mojom.MediaSessionAction; -import org.chromium.ui.base.ActivityWindowAndroid; import org.chromium.ui.base.WindowAndroid; import java.lang.annotation.Retention; @@ -75,7 +65,7 @@ * will connect to web API through OverlayWindowAndroid. */ @NullMarked -public class PictureInPictureActivity extends AsyncInitializationActivity { +public class PictureInPictureActivity extends VideoOverlayActivity { // These values are persisted to logs. Entries should not be renumbered and numeric values // should never be reused. // @@ -125,13 +115,6 @@ private static final String CONTROL_STATE = "org.chromium.chrome.browser.media.PictureInPictureActivity.ControlState"; - // Use for passing unique window id to each PictureInPictureActivity instance. This is an - // UnguessableToken that the native side trades for the underlying raw ptr. - private static final String NATIVE_TOKEN_KEY = - "org.chromium.chrome.browser.media.PictureInPictureActivity.NativeToken"; - // Used for passing webcontents to PictureInPictureActivity. - private static final String WEB_CONTENTS_KEY = - "org.chromium.chrome.browser.media.PictureInPicture.WebContents"; // If present, it indicates that the intent launches into PiP. public static final String LAUNCHED_KEY = "com.android.chrome.pictureinpicture.launched"; // If present, these provide our aspect ratio hint. @@ -147,15 +130,6 @@ // TODO(crbug.com/421606013): add pip watch time metrics and fine tune this threshold. private static final int QUICK_DISMISSAL_THRESHOLD_MS = 10000; - // The token and corresponding raw pointer to the native side. - private UnguessableToken mNativeToken; - private long mNativeOverlayWindowAndroid; - - private Tab mInitiatorTab; - private @Nullable InitiatorTabObserver mTabObserver; - - private @Nullable CompositorView mCompositorView; - // If present, this is the video's aspect ratio. private @Nullable Rational mAspectRatio; @@ -480,7 +454,7 @@ intent.setPackage(getApplicationContext().getPackageName()); IntentUtils.addTrustedIntentExtras(intent); intent.putExtra(CONTROL_TYPE, action); - intent.putExtra(NATIVE_TOKEN_KEY, mNativeToken); + intent.putExtra(NATIVE_TOKEN_KEY, getNativeToken()); if (controlState != null) { intent.putExtra(CONTROL_STATE, controlState); } @@ -550,8 +524,8 @@ // Make sure that this intent is for our instance. UnguessableToken nativeToken = intent.getParcelableExtra(NATIVE_TOKEN_KEY); if (nativeToken == null - || !nativeToken.equals(mNativeToken) - || mNativeOverlayWindowAndroid == 0) { + || !nativeToken.equals(getNativeToken()) + || !isNativeHandleInitialized()) { return; } @@ -567,45 +541,39 @@ switch (controlType) { case MediaSessionAction.PLAY: - PictureInPictureActivityJni.get() - .togglePlayPause(mNativeOverlayWindowAndroid, /* toggleOn= */ true); + togglePlayPause(/* toggleOn= */ true); return; case MediaSessionAction.PAUSE: - PictureInPictureActivityJni.get() - .togglePlayPause(mNativeOverlayWindowAndroid, /* toggleOn= */ false); + togglePlayPause(/* toggleOn= */ false); return; case MediaSessionAction.PREVIOUS_TRACK: - PictureInPictureActivityJni.get().previousTrack(mNativeOverlayWindowAndroid); + previousTrack(); return; case MediaSessionAction.NEXT_TRACK: - PictureInPictureActivityJni.get().nextTrack(mNativeOverlayWindowAndroid); + nextTrack(); return; case MediaSessionAction.PREVIOUS_SLIDE: - PictureInPictureActivityJni.get().previousSlide(mNativeOverlayWindowAndroid); + previousSlide(); return; case MediaSessionAction.NEXT_SLIDE: - PictureInPictureActivityJni.get().nextSlide(mNativeOverlayWindowAndroid); + nextSlide(); return; case MediaSessionAction.TOGGLE_MICROPHONE: // controlState should be non-null if MediaSessionAction toggles control state - PictureInPictureActivityJni.get() - .toggleMicrophone( - mNativeOverlayWindowAndroid, !assumeNonNull(controlState)); + toggleMicrophone(!assumeNonNull(controlState)); return; case MediaSessionAction.TOGGLE_CAMERA: // controlState should be non-null if MediaSessionAction toggles control state - PictureInPictureActivityJni.get() - .toggleCamera( - mNativeOverlayWindowAndroid, !assumeNonNull(controlState)); + toggleCamera(!assumeNonNull(controlState)); return; case MediaSessionAction.HANG_UP: - PictureInPictureActivityJni.get().hangUp(mNativeOverlayWindowAndroid); + hangUp(); return; case MediaSessionAction.EXIT_PICTURE_IN_PICTURE: if (ChromeFeatureList.isEnabled( MediaFeatures.AUTO_PICTURE_IN_PICTURE_ANDROID)) { mHideButtonClicked = true; - PictureInPictureActivityJni.get().hide(mNativeOverlayWindowAndroid); + hide(); } return; default: @@ -614,31 +582,10 @@ } } - private class InitiatorTabObserver extends EmptyTabObserver { - @Override - public void onClosingStateChanged(Tab tab, boolean closing) { - if (closing) { - PictureInPictureActivity.this.onExitPictureInPicture(/* closeByNative= */ false); - } - } - - @Override - public void onDestroyed(Tab tab) { - if (tab.isClosing()) { - PictureInPictureActivity.this.onExitPictureInPicture(/* closeByNative= */ false); - } - } - - @Override - public void onCrash(Tab tab) { - PictureInPictureActivity.this.onExitPictureInPicture(/* closeByNative= */ false); - } - } - /** * Interface to abstract makeLaunchIntoPip, which is only available in android T+. * Implementations of this API should expect to be called even on older version of Android, and - * do nothing. This allows tests to mock out the behavior. + * do nothing. This allows tests to mock out the behavior. */ interface LaunchIntoPipHelper { // Return a bundle to launch Picture in picture with `bounds` as the source rectangle. @@ -665,35 +612,6 @@ }; @Override - protected void triggerLayoutInflation() { - onInitialLayoutInflationComplete(); - } - - @Override - protected OneshotSupplier<ProfileProvider> createProfileProvider() { - OneshotSupplierImpl<ProfileProvider> supplier = new OneshotSupplierImpl<>(); - ProfileProvider profileProvider = - new ProfileProvider() { - - @Override - public Profile getOriginalProfile() { - return mInitiatorTab.getProfile().getOriginalProfile(); - } - - @Override - public @Nullable Profile getOffTheRecordProfile(boolean createIfNeeded) { - if (!mInitiatorTab.getProfile().isOffTheRecord()) { - assert !createIfNeeded; - return null; - } - return mInitiatorTab.getProfile(); - } - }; - supplier.set(profileProvider); - return supplier; - } - - @Override public void finishNativeInitialization() { super.finishNativeInitialization(); @@ -702,15 +620,16 @@ // resizes messages that are above it, since they're spurious. mMaxWidth = (int) (assumeNonNull(getWindowAndroid()).getDisplay().getDisplayWidth() * 0.95); - mCompositorView = + CompositorView compositorView = CompositorViewFactory.create( this, getWindowAndroid(), new ThinWebViewConstraints()); + addContentView( - mCompositorView.getView(), + compositorView.getView(), new ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); - mCompositorView + compositorView .getView() .addOnLayoutChangeListener( new OnLayoutChangeListener() { @@ -725,7 +644,7 @@ int oldTop, int oldRight, int oldBottom) { - if (mNativeOverlayWindowAndroid == 0) return; + if (!isNativeHandleInitialized()) return; // We sometimes get an initial update of zero before getting // something reasonable. if (top == bottom || left == right) return; @@ -736,60 +655,28 @@ final int width = right - left; if (width > mMaxWidth) return; - PictureInPictureActivityJni.get() - .onViewSizeChanged( - mNativeOverlayWindowAndroid, width, bottom - top); + onViewSizeChanged(width, bottom - top); } }); - PictureInPictureActivityJni.get() - .compositorViewCreated(mNativeOverlayWindowAndroid, mCompositorView); + setCompositorView(compositorView); } @Override - public boolean shouldStartGpuProcess() { - return true; - } - - @Override - @Initializer - protected void onPreCreate() { - super.onPreCreate(); - final Intent intent = getIntent(); - intent.setExtrasClassLoader(WebContents.class.getClassLoader()); - mInitiatorTab = TabUtils.fromWebContents(intent.getParcelableExtra(WEB_CONTENTS_KEY)); - - // Look up the native side from our token. - UnguessableToken token = intent.getParcelableExtra(NATIVE_TOKEN_KEY); - mNativeToken = assumeNonNull(token); - if (token == null) { - this.finish(); - return; - } - } - - @Override - @SuppressLint("NewAPI") // Picture-in-Picture API will not be enabled for oldver versions. @Initializer public void onStart() { super.onStart(); - final Intent intent = getIntent(); - // Finish the activity if OverlayWindowAndroid has already been destroyed // or InitiatorTab has been destroyed by user or crashed. - if (TabUtils.getActivity(mInitiatorTab) == null) { - onExitPictureInPicture(/* closeByNative= */ false); + if (isInitiatorTabDestroyed()) { return; } - finishInitialize(intent); + finishInitialize(getIntent()); } @Initializer private void finishInitialize(Intent intent) { - mTabObserver = new InitiatorTabObserver(); - mInitiatorTab.addObserver(mTabObserver); - mMediaSessionReceiver = new MediaSessionBroadcastReceiver(); ContextUtils.registerNonExportedBroadcastReceiver( this, mMediaSessionReceiver, new IntentFilter(MEDIA_ACTION)); @@ -806,11 +693,9 @@ mQuickDismissalRunnable, QUICK_DISMISSAL_THRESHOLD_MS); } - mNativeOverlayWindowAndroid = - PictureInPictureActivityJni.get() - .onActivityStart(mNativeToken, this, getWindowAndroid()); - if (mNativeOverlayWindowAndroid == 0) { - onExitPictureInPicture(/* closeByNative= */ true); + onActivityStart(); + if (!isNativeHandleInitialized()) { + finishOverlay(/* closeByNative= */ true); return; } @@ -835,66 +720,23 @@ boolean isInPictureInPictureMode, Configuration newConfig) { super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig); if (isInPictureInPictureMode) return; - PictureInPictureActivityJni.get().onBackToTab(mNativeOverlayWindowAndroid); - onExitPictureInPicture(/* closeByNative= */ false); + onBackToTab(); + finishOverlay(/* closeByNative= */ false); } @Override - protected ActivityWindowAndroid createWindowAndroid() { - return new ActivityWindowAndroid( - this, - /* listenToActivityState= */ true, - getIntentRequestTracker(), - getInsetObserver(), - /* occlusionTrackingAllowed= */ true); - } - - @CalledByNative - public void close() { - onExitPictureInPicture(/* closeByNative= */ true); - } - - @SuppressWarnings("NullAway") - private void onExitPictureInPicture(boolean closeByNative) { + protected void cleanup() { // If PiP window was dismissed, notify the native side. We must check that the // native window still exists, as this cleanup path can be called after the native // side has been destroyed. - if (handleUserDismissal() && mNativeOverlayWindowAndroid != 0) { - PictureInPictureActivityJni.get().onDismissal(mNativeOverlayWindowAndroid); - } - - if (!closeByNative && mNativeOverlayWindowAndroid != 0) { - PictureInPictureActivityJni.get().destroyStartedByJava(mNativeOverlayWindowAndroid); - } - // If called by `closeByNative`, it means that the native side will be freed at some point - // after this returns. If `!closeByNative`, then we asked the native side to start cleaning - // up just now via `destroyStartedByJava()` (if we have a native side). Either way, we - // shouldn't refer to the native side after this. - // - // See crbug.com/40063137 for details. - // - // Also note that, if there's no native side when this fn is called, then there's probably - // no compositor etc. either. This isn't immediately obvious, and we'd still want to call - // `finish()` in this case if our goal is to clean up after an init failure anyway. - mNativeOverlayWindowAndroid = 0; - - if (mCompositorView != null) { - mCompositorView.destroy(); - mCompositorView = null; + if (handleUserDismissal() && isNativeHandleInitialized()) { + onDismissal(); } if (mMediaSessionReceiver != null) { unregisterReceiver(mMediaSessionReceiver); mMediaSessionReceiver = null; } - - if (mInitiatorTab != null) { - mInitiatorTab.removeObserver(mTabObserver); - mInitiatorTab = null; - } - mTabObserver = null; - - this.finish(); } /** @@ -940,9 +782,10 @@ } } + @Override @CalledByNative @SuppressLint("NewApi") - private void updateVideoSize(int width, int height) { + public void updateVideoSize(int width, int height) { clampAndStoreAspectRatio(width, height); updatePictureInPictureParams(); } @@ -962,30 +805,34 @@ mAspectRatio = new Rational(width, height); } + @Override @VisibleForTesting @CalledByNative - void setPlaybackState(@PlaybackState int playbackState) { + public void setPlaybackState(@PlaybackState int playbackState) { mMediaActionsButtonsManager.updatePlaybackState(playbackState); updatePictureInPictureParams(); } + @Override @VisibleForTesting @CalledByNative - void setMicrophoneMuted(boolean muted) { + public void setMicrophoneMuted(boolean muted) { mMediaActionsButtonsManager.setMicrophoneMuted(muted); updatePictureInPictureParams(); } + @Override @VisibleForTesting @CalledByNative - void setCameraState(boolean turnedOn) { + public void setCameraState(boolean turnedOn) { mMediaActionsButtonsManager.setCameraOn(turnedOn); updatePictureInPictureParams(); } + @Override @VisibleForTesting @CalledByNative - void updateVisibleActions(int[] actions) { + public void updateVisibleActions(int[] actions) { HashSet<Integer> visibleActions = new HashSet<>(); for (int action : actions) visibleActions.add(action); mMediaActionsButtonsManager.updateVisibleActions(visibleActions); @@ -1047,17 +894,6 @@ context.startActivity(intent, optionsBundle); } - // Called when the native side is destroyed. - @CalledByNative - private void onWindowDestroyed() { - if (mNativeOverlayWindowAndroid == 0) { - // We've already cleaned up. - return; - } - mNativeOverlayWindowAndroid = 0; - onExitPictureInPicture(/* closeByNative= */ true); - } - // Allow tests to mock out our LaunchIntoPipHelper. Returns the outgoing one. @VisibleForTesting /* package */ static LaunchIntoPipHelper setLaunchIntoPipHelper(LaunchIntoPipHelper helper) { @@ -1067,7 +903,7 @@ } /* package */ @Nullable View getViewForTesting() { - return mCompositorView == null ? null : mCompositorView.getView(); + return getCompositorView() == null ? null : getCompositorView().getView(); } public void expireQuickDismissalTimerForTesting() { @@ -1092,40 +928,4 @@ public ArrayList<RemoteAction> getActionsForTesting() { return mMediaActionsButtonsManager.getActionsForPictureInPictureParams(); } - - @NativeMethods - public interface Natives { - long onActivityStart( - UnguessableToken token, - PictureInPictureActivity self, - @Nullable WindowAndroid window); - - void destroyStartedByJava(long nativeOverlayWindowAndroid); - - void togglePlayPause(long nativeOverlayWindowAndroid, boolean toggleOn); - - void nextTrack(long nativeOverlayWindowAndroid); - - void previousTrack(long nativeOverlayWindowAndroid); - - void nextSlide(long nativeOverlayWindowAndroid); - - void previousSlide(long nativeOverlayWindowAndroid); - - void toggleMicrophone(long nativeOverlayWindowAndroid, boolean toggleOn); - - void toggleCamera(long nativeOverlayWindowAndroid, boolean toggleOn); - - void hangUp(long nativeOverlayWindowAndroid); - - void hide(long nativeOverlayWindowAndroid); - - void compositorViewCreated(long nativeOverlayWindowAndroid, CompositorView compositorView); - - void onViewSizeChanged(long nativeOverlayWindowAndroid, int width, int height); - - void onBackToTab(long nativeOverlayWindowAndroid); - - void onDismissal(long nativeOverlayWindowAndroid); - } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/VideoOverlayActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/media/VideoOverlayActivity.java new file mode 100644 index 0000000..1cdbef40 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/media/VideoOverlayActivity.java
@@ -0,0 +1,364 @@ +// 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.media; + +import static org.chromium.build.NullUtil.assumeNonNull; + +import android.content.Intent; + +import org.jni_zero.CalledByNative; +import org.jni_zero.NativeMethods; + +import org.chromium.base.UnguessableToken; +import org.chromium.base.supplier.OneshotSupplier; +import org.chromium.base.supplier.OneshotSupplierImpl; +import org.chromium.build.annotations.Initializer; +import org.chromium.build.annotations.NullMarked; +import org.chromium.build.annotations.Nullable; +import org.chromium.chrome.browser.init.AsyncInitializationActivity; +import org.chromium.chrome.browser.profiles.Profile; +import org.chromium.chrome.browser.profiles.ProfileProvider; +import org.chromium.chrome.browser.tab.EmptyTabObserver; +import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.browser.tab.TabUtils; +import org.chromium.components.thinwebview.CompositorView; +import org.chromium.content_public.browser.WebContents; +import org.chromium.content_public.browser.overlay_window.PlaybackState; +import org.chromium.ui.base.ActivityWindowAndroid; +import org.chromium.ui.base.WindowAndroid; + +/** + * A base class for video overlay activities (e.g. Picture-in-Picture, Immersive Playback). This + * class handles the common lifecycle and JNI logic. + */ +@NullMarked +public abstract class VideoOverlayActivity extends AsyncInitializationActivity { + protected static final String NATIVE_TOKEN_KEY = + "org.chromium.chrome.browser.media.VideoOverlayActivity.NativeToken"; + protected static final String WEB_CONTENTS_KEY = + "org.chromium.chrome.browser.media.VideoOverlayActivity.WebContents"; + + private @Nullable UnguessableToken mNativeToken; + private long mNativeOverlayWindowAndroid; + + private @Nullable Tab mInitiatorTab; + private @Nullable InitiatorTabObserver mTabObserver; + + private @Nullable CompositorView mCompositorView; + + private class InitiatorTabObserver extends EmptyTabObserver { + @Override + public void onClosingStateChanged(Tab tab, boolean closing) { + if (closing) { + finishOverlay(/* closeByNative= */ false); + } + } + + @Override + public void onDestroyed(Tab tab) { + if (tab.isClosing()) { + finishOverlay(/* closeByNative= */ false); + } + } + + @Override + public void onCrash(Tab tab) { + finishOverlay(/* closeByNative= */ false); + } + } + + @Override + protected void triggerLayoutInflation() { + onInitialLayoutInflationComplete(); + } + + @Override + protected OneshotSupplier<ProfileProvider> createProfileProvider() { + OneshotSupplierImpl<ProfileProvider> supplier = new OneshotSupplierImpl<>(); + ProfileProvider profileProvider = + new ProfileProvider() { + @Override + public Profile getOriginalProfile() { + return assumeNonNull(mInitiatorTab).getProfile().getOriginalProfile(); + } + + @Override + public @Nullable Profile getOffTheRecordProfile(boolean createIfNeeded) { + if (!assumeNonNull(mInitiatorTab).getProfile().isOffTheRecord()) { + assert !createIfNeeded; + return null; + } + return mInitiatorTab.getProfile(); + } + }; + supplier.set(profileProvider); + return supplier; + } + + @Override + public boolean shouldStartGpuProcess() { + return true; + } + + @Override + protected ActivityWindowAndroid createWindowAndroid() { + return new ActivityWindowAndroid( + this, + /* listenToActivityState= */ true, + getIntentRequestTracker(), + getInsetObserver(), + /* occlusionTrackingAllowed= */ true); + } + + @Override + @Initializer + protected void onPreCreate() { + super.onPreCreate(); + + final Intent intent = getIntent(); + UnguessableToken token = intent.getParcelableExtra(NATIVE_TOKEN_KEY); + if (token == null) { + finishOverlay(/* closeByNative= */ false); + return; + } + + mNativeToken = assumeNonNull(token); + intent.setExtrasClassLoader(WebContents.class.getClassLoader()); + mInitiatorTab = TabUtils.fromWebContents(intent.getParcelableExtra(WEB_CONTENTS_KEY)); + if (mInitiatorTab != null) { + mTabObserver = new InitiatorTabObserver(); + mInitiatorTab.addObserver(mTabObserver); + } + } + + @Override + @Initializer + public void onStart() { + super.onStart(); + + if (isInitiatorTabDestroyed()) { + finishOverlay(/* closeByNative= */ false); + return; + } + } + + protected boolean isInitiatorTabDestroyed() { + return mInitiatorTab == null || TabUtils.getActivity(mInitiatorTab) == null; + } + + @CalledByNative + public void close() { + finishOverlay(/* closeByNative= */ true); + } + + @CalledByNative + protected void onWindowDestroyed() { + if (mNativeOverlayWindowAndroid == 0) { + return; + } + mNativeOverlayWindowAndroid = 0; + finishOverlay(/* closeByNative= */ true); + } + + @CalledByNative + public abstract void setPlaybackState(@PlaybackState int playbackState); + + @CalledByNative + public abstract void updateVideoSize(int width, int height); + + @CalledByNative + public void updateVisibleActions(int[] actions) {} + + @CalledByNative + public void setMicrophoneMuted(boolean muted) {} + + @CalledByNative + public void setCameraState(boolean turnedOn) {} + + @CalledByNative + public void setMediaPosition(long durationMs, long positionMs, double playbackRate) {} + + @CalledByNative + public void setImmersiveVideoOptions(int stereoMode, int projectionType) {} + + protected void togglePlayPause(boolean toggleOn) { + if (mNativeOverlayWindowAndroid != 0) { + VideoOverlayActivityJni.get().togglePlayPause(mNativeOverlayWindowAndroid, toggleOn); + } + } + + protected void nextTrack() { + if (mNativeOverlayWindowAndroid != 0) { + VideoOverlayActivityJni.get().nextTrack(mNativeOverlayWindowAndroid); + } + } + + protected void previousTrack() { + if (mNativeOverlayWindowAndroid != 0) { + VideoOverlayActivityJni.get().previousTrack(mNativeOverlayWindowAndroid); + } + } + + protected void nextSlide() { + if (mNativeOverlayWindowAndroid != 0) { + VideoOverlayActivityJni.get().nextSlide(mNativeOverlayWindowAndroid); + } + } + + protected void previousSlide() { + if (mNativeOverlayWindowAndroid != 0) { + VideoOverlayActivityJni.get().previousSlide(mNativeOverlayWindowAndroid); + } + } + + protected void toggleMicrophone(boolean toggleOn) { + if (mNativeOverlayWindowAndroid != 0) { + VideoOverlayActivityJni.get().toggleMicrophone(mNativeOverlayWindowAndroid, toggleOn); + } + } + + protected void toggleCamera(boolean toggleOn) { + if (mNativeOverlayWindowAndroid != 0) { + VideoOverlayActivityJni.get().toggleCamera(mNativeOverlayWindowAndroid, toggleOn); + } + } + + protected void hangUp() { + if (mNativeOverlayWindowAndroid != 0) { + VideoOverlayActivityJni.get().hangUp(mNativeOverlayWindowAndroid); + } + } + + protected void hide() { + if (mNativeOverlayWindowAndroid != 0) { + VideoOverlayActivityJni.get().hide(mNativeOverlayWindowAndroid); + } + } + + private void compositorViewCreated(CompositorView compositorView) { + if (mNativeOverlayWindowAndroid != 0) { + VideoOverlayActivityJni.get() + .compositorViewCreated(mNativeOverlayWindowAndroid, compositorView); + } + } + + protected void onViewSizeChanged(int width, int height) { + if (mNativeOverlayWindowAndroid != 0) { + VideoOverlayActivityJni.get() + .onViewSizeChanged(mNativeOverlayWindowAndroid, width, height); + } + } + + protected void onBackToTab() { + if (mNativeOverlayWindowAndroid != 0) { + VideoOverlayActivityJni.get().onBackToTab(mNativeOverlayWindowAndroid); + } + } + + protected void onDismissal() { + if (mNativeOverlayWindowAndroid != 0) { + VideoOverlayActivityJni.get().onDismissal(mNativeOverlayWindowAndroid); + } + } + + protected void seekTo(long positionMs) { + if (mNativeOverlayWindowAndroid != 0) { + VideoOverlayActivityJni.get().seekTo(mNativeOverlayWindowAndroid, positionMs); + } + } + + protected @Nullable CompositorView getCompositorView() { + return mCompositorView; + } + + protected void setCompositorView(CompositorView compositorView) { + if (mCompositorView == null && compositorView != null) { + mCompositorView = compositorView; + compositorViewCreated(compositorView); + } + } + + public boolean isNativeHandleInitialized() { + return mNativeOverlayWindowAndroid != 0; + } + + protected UnguessableToken getNativeToken() { + return assumeNonNull(mNativeToken); + } + + protected void onActivityStart() { + mNativeOverlayWindowAndroid = + VideoOverlayActivityJni.get() + .onActivityStart(assumeNonNull(mNativeToken), this, getWindowAndroid()); + // If the compositor view was created earlier during finishNativeInitialization (part of + // onCreate), notify native now that the native handle is ready. + if (mCompositorView != null) { + compositorViewCreated(mCompositorView); + } + } + + protected void finishOverlay(boolean closeByNative) { + cleanup(); + + if (!closeByNative && mNativeOverlayWindowAndroid != 0) { + VideoOverlayActivityJni.get().destroyStartedByJava(mNativeOverlayWindowAndroid); + } + mNativeOverlayWindowAndroid = 0; + + if (mCompositorView != null) { + mCompositorView.destroy(); + mCompositorView = null; + } + + if (mInitiatorTab != null) { + if (mTabObserver != null) { + mInitiatorTab.removeObserver(mTabObserver); + } + mInitiatorTab = null; + } + mTabObserver = null; + + this.finish(); + } + + /** Subclasses should implement this to perform their own cleanup. */ + protected abstract void cleanup(); + + @NativeMethods + public interface Natives { + long onActivityStart( + UnguessableToken token, VideoOverlayActivity self, @Nullable WindowAndroid window); + + void destroyStartedByJava(long nativeOverlayWindowAndroid); + + void togglePlayPause(long nativeOverlayWindowAndroid, boolean toggleOn); + + void nextTrack(long nativeOverlayWindowAndroid); + + void previousTrack(long nativeOverlayWindowAndroid); + + void nextSlide(long nativeOverlayWindowAndroid); + + void previousSlide(long nativeOverlayWindowAndroid); + + void toggleMicrophone(long nativeOverlayWindowAndroid, boolean toggleOn); + + void toggleCamera(long nativeOverlayWindowAndroid, boolean toggleOn); + + void hangUp(long nativeOverlayWindowAndroid); + + void hide(long nativeOverlayWindowAndroid); + + void compositorViewCreated(long nativeOverlayWindowAndroid, CompositorView compositorView); + + void onViewSizeChanged(long nativeOverlayWindowAndroid, int width, int height); + + void onBackToTab(long nativeOverlayWindowAndroid); + + void onDismissal(long nativeOverlayWindowAndroid); + + void seekTo(long nativeOverlayWindowAndroid, long positionMs); + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedAdaptiveToolbarBehavior.java b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedAdaptiveToolbarBehavior.java index be303d1..20212b5 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedAdaptiveToolbarBehavior.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedAdaptiveToolbarBehavior.java
@@ -4,7 +4,7 @@ package org.chromium.chrome.browser.tabbed_mode; -import android.content.Context; +import android.app.Activity; import androidx.appcompat.content.res.AppCompatResources; @@ -43,7 +43,7 @@ /** Implements tabbed browser-specific behavior of adaptive toolbar button. */ @NullMarked public class TabbedAdaptiveToolbarBehavior implements AdaptiveToolbarBehavior { - private final Context mContext; + private final Activity mActivity; private final ActivityTabProvider mActivityTabProvider; private final ActivityLifecycleDispatcher mActivityLifecycleDispatcher; private final Supplier<@Nullable TabBookmarker> mTabBookmarkerSupplier; @@ -60,7 +60,7 @@ private final BrowserControlsVisibilityManager mBrowserControlsVisibilityManager; /** - * @param context The Android context. + * @param activity The Android activity. * @param activityLifecycleDispatcher Dispatcher for activity lifecycle events. * @param tabCreatorManagerSupplier Used to create new tabs. * @param tabBookmarkerSupplier Used to bookmark tabs. @@ -75,7 +75,7 @@ * @param browserControlsVisibilityManager Manager for browser controls. */ public TabbedAdaptiveToolbarBehavior( - Context context, + Activity activity, ActivityLifecycleDispatcher activityLifecycleDispatcher, Supplier<@Nullable TabCreatorManager> tabCreatorManagerSupplier, Supplier<@Nullable TabBookmarker> tabBookmarkerSupplier, @@ -88,7 +88,7 @@ GlicToolbarButtonController.GlicButtonDelegate toggleGlicCallback, Supplier<@Nullable ChromeAndroidTask> chromeAndroidTaskSupplier, BrowserControlsVisibilityManager browserControlsVisibilityManager) { - mContext = context; + mActivity = activity; mActivityLifecycleDispatcher = activityLifecycleDispatcher; mTabCreatorManagerSupplier = tabCreatorManagerSupplier; mTabBookmarkerSupplier = tabBookmarkerSupplier; @@ -107,11 +107,11 @@ public void registerPerSurfaceButtons( AdaptiveToolbarButtonController controller, Supplier<@Nullable Tracker> trackerSupplier) { - if (!BottomBarConfigUtils.isBottomBarEnabled(mContext)) { + if (!BottomBarConfigUtils.isBottomBarEnabled(mActivity)) { var newTabButton = new OptionalNewTabButtonController( - mContext, - AppCompatResources.getDrawable(mContext, R.drawable.new_tab_icon), + mActivity, + AppCompatResources.getDrawable(mActivity, R.drawable.new_tab_icon), mActivityLifecycleDispatcher, mTabCreatorManagerSupplier, mActivityTabProvider, @@ -122,7 +122,7 @@ var addToBookmarks = new AddToBookmarksToolbarButtonController( mActivityTabProvider.asObservable(), - mContext, + mActivity, mActivityLifecycleDispatcher, mTabBookmarkerSupplier, trackerSupplier, @@ -132,19 +132,19 @@ var tabGrouping = new GroupSuggestionsButtonDataProvider( mActivityTabProvider, - mContext, - AppCompatResources.getDrawable(mContext, R.drawable.ic_widgets), + mActivity, + AppCompatResources.getDrawable(mActivity, R.drawable.ic_widgets), mGroupSuggestionsButtonControllerSupplier, mTabModelSelectorSupplier); controller.addButtonVariant(AdaptiveToolbarButtonVariant.TAB_GROUPING, tabGrouping); } - if (!BottomBarConfigUtils.isBottomBarEnabled(mContext) + if (!BottomBarConfigUtils.isBottomBarEnabled(mActivity) && AdaptiveToolbarFeatures.isGlicActionEnabled()) { controller.addButtonVariant( AdaptiveToolbarButtonVariant.GLIC, new GlicToolbarButtonController( - mContext, + mActivity, mActivityTabProvider, mToggleGlicCallback, trackerSupplier, @@ -162,13 +162,13 @@ if (selector != null) { Profile profile = selector.getCurrentModel().getProfile(); if (profile != null - && AdaptiveToolbarFeatures.shouldForciblyShowGlicButton(mContext, profile)) { + && AdaptiveToolbarFeatures.shouldForciblyShowGlicButton(mActivity, profile)) { return AdaptiveToolbarButtonVariant.GLIC; } } List<Integer> filteredResults; - if (!BottomBarConfigUtils.isBottomBarEnabled(mContext)) { + if (!BottomBarConfigUtils.isBottomBarEnabled(mActivity)) { filteredResults = segmentationResults; } else { filteredResults = new ArrayList<>(); @@ -180,14 +180,14 @@ } } - return AdaptiveToolbarBehavior.defaultResultFilter(mContext, filteredResults); + return AdaptiveToolbarBehavior.defaultResultFilter(mActivity, filteredResults); } @Override public boolean canShowManualOverride(int manualOverride) { // Ignore manual overrides for GLIC and New Tab when the Android Bottom Bar is enabled as // these buttons have a dedicated spot in the bottom bar. - if (BottomBarConfigUtils.isBottomBarEnabled(mContext) + if (BottomBarConfigUtils.isBottomBarEnabled(mActivity) && (manualOverride == AdaptiveToolbarButtonVariant.GLIC || manualOverride == AdaptiveToolbarButtonVariant.NEW_TAB)) { return false; @@ -197,11 +197,11 @@ @Override public boolean useRawResults() { - return DeviceFormFactor.isNonMultiDisplayContextOnTablet(mContext); + return DeviceFormFactor.isNonMultiDisplayContextOnTablet(mActivity); } @Override public @AdaptiveToolbarButtonVariant int getSegmentationDefault(Profile profile) { - return AdaptiveToolbarFeatures.getDefaultButtonVariant(mContext, profile); + return AdaptiveToolbarFeatures.getDefaultButtonVariant(mActivity, profile); } }
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 7cdb655..01b0da2c 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
@@ -2111,6 +2111,7 @@ mSideUiCoordinator = SideUiCoordinatorFactory.create( + mActivity, anchorContainerParent, sideUiStartAnchorContainerStub, sideUiEndAnchorContainerStub,
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 ba8cfea..f260417 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
@@ -209,9 +209,9 @@ import org.chromium.chrome.browser.ui.edge_to_edge.TopInsetProvider; import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager; import org.chromium.chrome.browser.ui.native_page.NativePage; -import org.chromium.chrome.browser.ui.side_ui.MarginContainerSideUiObserver; import org.chromium.chrome.browser.ui.side_ui.SideUiObserver; import org.chromium.chrome.browser.ui.side_ui.SideUiStateProvider; +import org.chromium.chrome.browser.ui.side_ui.ViewMarginAdjusterForSideUi; import org.chromium.chrome.browser.ui.system.StatusBarColorController; import org.chromium.chrome.browser.ui.theme.BrandedColorScheme; import org.chromium.chrome.browser.undo_tab_close_snackbar.UndoBarThrottle; @@ -1888,7 +1888,7 @@ } }; mSideUiStateProvider.addObserver(mSideUiObserver); - mControlContainerSideUiObserver = new MarginContainerSideUiObserver(mControlContainer); + mControlContainerSideUiObserver = new ViewMarginAdjusterForSideUi(mControlContainer); mSideUiStateProvider.addObserver(mControlContainerSideUiObserver); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/xr/scenecore/XrModuleBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/xr/scenecore/XrModuleBridge.java new file mode 100644 index 0000000..3941aaa2 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/xr/scenecore/XrModuleBridge.java
@@ -0,0 +1,26 @@ +// 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.xr.scenecore; + +import org.jni_zero.CalledByNative; + +import org.chromium.base.UnguessableToken; +import org.chromium.build.annotations.NullMarked; + +/** Bridges native queries into the dynamic XR module installer state. */ +@NullMarked +public class XrModuleBridge { + /** Returns true if the XR module is installed. */ + @CalledByNative + public static boolean isModuleInstalled() { + return XrModule.isInstalled(); + } + + @CalledByNative + public static void createImmersiveVideoPlaybackActivity( + UnguessableToken nativeToken, Object initiatorTab) { + XrModule.getImpl().createImmersiveVideoPlaybackActivity(nativeToken, initiatorTab); + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/xr/scenecore/XrModuleProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/xr/scenecore/XrModuleProvider.java index 26905f2b..596ffe7 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/xr/scenecore/XrModuleProvider.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/xr/scenecore/XrModuleProvider.java
@@ -6,6 +6,7 @@ import android.app.Activity; +import org.chromium.base.UnguessableToken; import org.chromium.build.annotations.NullMarked; import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; import org.chromium.components.module_installer.builder.ModuleInterface; @@ -21,4 +22,6 @@ XrSceneCoreSessionInitializer getXrSceneCoreSessionInitializer( ActivityLifecycleDispatcher dispatcher, XrSceneCoreSessionManager manager); + + void createImmersiveVideoPlaybackActivity(UnguessableToken nativeToken, Object initiatorTab); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/PopupMultiwindowPTTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/PopupMultiwindowPTTest.java index ef6ac65f..243fff0 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/PopupMultiwindowPTTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/PopupMultiwindowPTTest.java
@@ -16,6 +16,7 @@ import org.chromium.base.test.transit.TransitAsserts; import org.chromium.base.test.util.CommandLineFlags; +import org.chromium.base.test.util.DisableIf; import org.chromium.base.test.util.DoNotBatch; import org.chromium.base.test.util.Features.EnableFeatures; import org.chromium.base.test.util.Restriction; @@ -53,6 +54,7 @@ @Test @MediumTest + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testBasic() { PopupOnClickPageStation page = PopupOnClickPageStation.loadInCurrentTab(
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/app/appmenu/MultiWindowAppMenuTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/app/appmenu/MultiWindowAppMenuTest.java index 29979b4..0963add 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/app/appmenu/MultiWindowAppMenuTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/app/appmenu/MultiWindowAppMenuTest.java
@@ -54,6 +54,7 @@ @Test @LargeTest @DisableFeatures(ChromeFeatureList.ROBUST_WINDOW_MANAGEMENT_EXPERIMENTAL) + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testOpenNewWindow_fromWebPage() { doTestOpenNewWindow(); } @@ -96,6 +97,7 @@ @Test @LargeTest @EnableFeatures(OPEN_WINDOW_ON_TOP) + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testOpenAndCloseNewWindow_robustWindowManagementExperimentalEnabled() { doTestOpenAndCloseNewWindow(); } @@ -149,6 +151,7 @@ @LargeTest @EnableFeatures(OPEN_WINDOW_ON_TOP) @DisableFeatures(ChromeFeatureList.SETTINGS_MULTI_COLUMN) + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testInteractWithBothWindows_robustWindowManagementExperimentalEnabled() { doTestInteractWithBothWindows(); } @@ -159,6 +162,7 @@ ChromeFeatureList.ROBUST_WINDOW_MANAGEMENT_EXPERIMENTAL, ChromeFeatureList.SETTINGS_MULTI_COLUMN }) + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testInteractWithBothWindows() { doTestInteractWithBothWindows(); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/app/appmenu/OverviewAppMenuTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/app/appmenu/OverviewAppMenuTest.java index f0e7fcbb..794afde 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/app/appmenu/OverviewAppMenuTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/app/appmenu/OverviewAppMenuTest.java
@@ -19,6 +19,7 @@ import org.chromium.base.test.util.Batch; import org.chromium.base.test.util.CommandLineFlags; +import org.chromium.base.test.util.DisableIf; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.HistogramWatcher; import org.chromium.chrome.R; @@ -35,6 +36,7 @@ import org.chromium.chrome.test.transit.hub.TabSwitcherAppMenuFacility; import org.chromium.chrome.test.transit.quick_delete.QuickDeleteDialogFacility; import org.chromium.components.feature_engagement.Tracker; +import org.chromium.ui.base.DeviceFormFactor; import java.util.ArrayList; import java.util.List; @@ -86,6 +88,7 @@ @Test @LargeTest @Feature({"Browser", "Main"}) + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testIncognitoAllMenuItems() { IncognitoTabSwitcherStation incognitoTabSwitcher = mTabSwitcher.openAppMenu().openNewIncognitoTabOrWindow().openIncognitoTabSwitcher();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/app/appmenu/TabbedAppMenuPTTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/app/appmenu/TabbedAppMenuPTTest.java index 263c6c2..4464a4d 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/app/appmenu/TabbedAppMenuPTTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/app/appmenu/TabbedAppMenuPTTest.java
@@ -15,6 +15,7 @@ import org.chromium.base.ThreadUtils; import org.chromium.base.test.util.Batch; import org.chromium.base.test.util.CommandLineFlags; +import org.chromium.base.test.util.DisableIf; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.Features.DisableFeatures; import org.chromium.base.test.util.Restriction; @@ -157,6 +158,7 @@ @Test @LargeTest @Feature({"RenderTest"}) + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testNewTabPageIncognitoAppMenuItems() throws IOException { IncognitoNewTabPageStation incognitoNewTabPage = mCtaTestRule.startOnBlankPage().openRegularTabAppMenu().openNewIncognitoTab(); @@ -202,6 +204,7 @@ @Test @LargeTest @Feature({"RenderTest"}) + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testWebPageIncognitoAppMenuItems() throws IOException { IncognitoNewTabPageStation incognitoNtp = mCtaTestRule.startOnBlankPage().openRegularTabAppMenu().openNewIncognitoTab();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/app/bookmarks/ReadingListTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/app/bookmarks/ReadingListTest.java index d90daee7..56ec470 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/app/bookmarks/ReadingListTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/app/bookmarks/ReadingListTest.java
@@ -50,6 +50,7 @@ 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.DisableIf; import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.DoNotBatch; import org.chromium.base.test.util.ImportantFormFactors; @@ -266,6 +267,7 @@ @Test @SmallTest + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testReadingListItemMenuItems_ReadItem() throws Exception { SigninPromoCoordinator.disablePromoForTesting(); BookmarkId id = addReadingListBookmark(TEST_PAGE_TITLE_GOOGLE, mTestUrlA); @@ -339,6 +341,7 @@ @Test @SmallTest + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testReadingListEmptyStateView() throws Exception { SigninPromoCoordinator.disablePromoForTesting(); openBookmarkManager();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/app/tabmodel/ArchivedTabModelOrchestratorTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/app/tabmodel/ArchivedTabModelOrchestratorTest.java index 38e2d7de..0b72908 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/app/tabmodel/ArchivedTabModelOrchestratorTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/app/tabmodel/ArchivedTabModelOrchestratorTest.java
@@ -4,6 +4,9 @@ package org.chromium.chrome.browser.app.tabmodel; +import org.chromium.base.test.util.DisableIf; +import org.chromium.ui.base.DeviceFormFactor; + import static androidx.test.espresso.Espresso.onView; import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist; import static androidx.test.espresso.matcher.ViewMatchers.withId; @@ -481,6 +484,7 @@ @Test @MediumTest + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testOpenArchivedTabFromHubSearch_Incognito() { finishLoading(); String declutterUrl = mActivityTestRule.getTestServer().getURL(TEST_PATH);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/browsing_data/BrowsingDataBridgeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/browsing_data/BrowsingDataBridgeTest.java index 324bd20..9fbf2487 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/browsing_data/BrowsingDataBridgeTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/browsing_data/BrowsingDataBridgeTest.java
@@ -4,6 +4,9 @@ package org.chromium.chrome.browser.browsing_data; +import org.chromium.base.test.util.DisableIf; +import org.chromium.ui.base.DeviceFormFactor; + import static androidx.test.espresso.matcher.ViewMatchers.assertThat; import static org.junit.Assert.assertEquals; @@ -230,6 +233,7 @@ /** Test deleting all browsing data. (Except bookmarks, they are deleted in Java code) */ @Test @SmallTest + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testClearingAll() throws Exception { ThreadUtils.runOnUiThreadBlocking( () -> {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/overlays/strip/TabStripGroupContextMenuTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/overlays/strip/TabStripGroupContextMenuTest.java index a4321a3..f24cc0ec 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/overlays/strip/TabStripGroupContextMenuTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/overlays/strip/TabStripGroupContextMenuTest.java
@@ -55,6 +55,7 @@ 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.DisableIf; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.Features; import org.chromium.base.test.util.Restriction; @@ -86,6 +87,7 @@ }) @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) @Restriction(DeviceFormFactor.TABLET_OR_DESKTOP) +@DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public class TabStripGroupContextMenuTest { @Rule public AutoResetCtaTransitTestRule mActivityTestRule =
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/overlays/strip/TabStripPinUnpinTabsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/overlays/strip/TabStripPinUnpinTabsTest.java index cf3a37c..dfa9f5e 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/overlays/strip/TabStripPinUnpinTabsTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/overlays/strip/TabStripPinUnpinTabsTest.java
@@ -33,6 +33,7 @@ import org.chromium.base.ThreadUtils; import org.chromium.base.test.util.Batch; import org.chromium.base.test.util.CommandLineFlags; +import org.chromium.base.test.util.DisableIf; import org.chromium.base.test.util.Restriction; import org.chromium.chrome.R; import org.chromium.chrome.browser.flags.ChromeSwitches; @@ -51,6 +52,7 @@ @Batch(Batch.PER_CLASS) @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) @Restriction(DeviceFormFactor.TABLET_OR_DESKTOP) +@DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public class TabStripPinUnpinTabsTest { @Rule public AutoResetCtaTransitTestRule mActivityTestRule =
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/overlays/strip/TabStripTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/overlays/strip/TabStripTest.java index 1853d92..133a16f7 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/overlays/strip/TabStripTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/overlays/strip/TabStripTest.java
@@ -37,6 +37,7 @@ 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.DisableIf; import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.DoNotBatch; import org.chromium.base.test.util.Feature; @@ -900,6 +901,7 @@ @LargeTest @Restriction(DeviceFormFactor.TABLET_OR_DESKTOP) @Feature({"TabStrip"}) + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testScrollingStripStackersWithLastTabSelected() throws Exception { testScrollingStripStackersWithLastTabSelected(/* isRtl= */ false); } @@ -908,6 +910,7 @@ @LargeTest @Restriction(DeviceFormFactor.TABLET_OR_DESKTOP) @Feature({"TabStrip", "RTL"}) + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testScrollingStripStackersWithLastTabSelectedRtl() throws Exception { testScrollingStripStackersWithLastTabSelected(/* isRtl= */ true); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java index eb5b2a33..8048e5e7 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
@@ -2397,6 +2397,7 @@ @Restriction(DeviceRestriction.RESTRICTION_TYPE_NON_AUTO) // Bug in O that's been fixed in 8.1 // https://issuetracker.google.com/issues/68427483 + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testLaunchPartialCustomTabActivity_Transition() throws Exception { Intent intent = createMinimalCustomTabIntent(); var token = SessionHolder.getSessionHolderFromIntent(intent);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabPostMessageTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabPostMessageTest.java index 9f17f11..3f33fb70 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabPostMessageTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabPostMessageTest.java
@@ -40,6 +40,7 @@ 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.DisableIf; import org.chromium.base.test.util.DisabledTest; import org.chromium.chrome.browser.browserservices.intents.SessionHolder; import org.chromium.chrome.browser.document.ChromeLauncherActivity; @@ -51,6 +52,7 @@ import org.chromium.content_public.browser.WebContentsObserver; import org.chromium.content_public.browser.test.util.WebContentsUtils; import org.chromium.net.test.util.TestWebServer; +import org.chromium.ui.base.DeviceFormFactor; /** Integration tests for the Custom Tab post message support. */ @RunWith(ChromeJUnit4ClassRunner.class) @@ -289,6 +291,7 @@ /** Tests the postMessage requests sent from the page is received on the client side. */ @Test @SmallTest + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testPostMessageReceivedFromPage() throws Exception { final CallbackHelper messageChannelHelper = new CallbackHelper(); final CallbackHelper onPostMessageHelper = new CallbackHelper();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/MismatchNotificationControllerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/MismatchNotificationControllerTest.java index a7473b1..418b2cf8 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/MismatchNotificationControllerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/MismatchNotificationControllerTest.java
@@ -32,6 +32,7 @@ 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.DisableIf; import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.DoNotBatch; import org.chromium.base.test.util.Features.DisableFeatures; @@ -54,6 +55,7 @@ import org.chromium.components.messages.MessageDispatcherProvider; import org.chromium.components.signin.SigninFeatures; import org.chromium.components.signin.test.util.TestAccounts; +import org.chromium.ui.base.DeviceFormFactor; import org.chromium.ui.base.WindowAndroid; import org.chromium.ui.modelutil.PropertyModel; @@ -69,6 +71,7 @@ SigninFeatures.ENABLE_SEAMLESS_SIGNIN, SigninFeatures.ENABLE_ACTIVITYLESS_SIGNIN_ALL_ENTRY_POINT }) +@DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public class MismatchNotificationControllerTest { private static final String TEST_URL = "https://www.google.com";
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/desktop_windowing/AppHeaderCoordinatorBrowserTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/desktop_windowing/AppHeaderCoordinatorBrowserTest.java index 942b4274..b505a74 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/desktop_windowing/AppHeaderCoordinatorBrowserTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/desktop_windowing/AppHeaderCoordinatorBrowserTest.java
@@ -38,6 +38,7 @@ 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.DisableIf; import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.Features; import org.chromium.base.test.util.Features.EnableFeatures; @@ -134,6 +135,7 @@ @Test @MediumTest + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testTabStripHeightChangeInDesktopWindow() { ChromeTabbedActivity activity = mActivityTestRule.getActivity(); triggerDesktopWindowingModeChange(activity, true);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/dragdrop/DragAndDropLauncherActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/dragdrop/DragAndDropLauncherActivityTest.java index 7de0120..b5b606e 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/dragdrop/DragAndDropLauncherActivityTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/dragdrop/DragAndDropLauncherActivityTest.java
@@ -30,6 +30,7 @@ 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.DisableIf; import org.chromium.base.test.util.DoNotBatch; import org.chromium.base.test.util.HistogramWatcher; import org.chromium.base.test.util.Matchers; @@ -54,6 +55,7 @@ import org.chromium.chrome.test.transit.FreshCtaTransitTestRule; import org.chromium.chrome.test.transit.page.WebPageStation; import org.chromium.chrome.test.util.ChromeTabUtils; +import org.chromium.ui.base.DeviceFormFactor; import org.chromium.ui.dragdrop.DragDropMetricUtils.DragDropType; import org.chromium.ui.dragdrop.DragDropMetricUtils.UrlIntentSource; import org.chromium.url.GURL; @@ -292,6 +294,7 @@ */ @Test @LargeTest + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testDraggedTabGroup_newWindow() throws Exception { var sourceActivity = mActivityTestRule.getActivity();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/findinpage/FindTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/findinpage/FindTest.java index 0431e02..d23dd4f 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/findinpage/FindTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/findinpage/FindTest.java
@@ -37,6 +37,7 @@ 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.DisableIf; import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.Features.EnableFeatures; @@ -53,6 +54,7 @@ import org.chromium.chrome.test.util.MenuUtils; import org.chromium.content_public.browser.test.util.TouchCommon; import org.chromium.content_public.browser.test.util.UiUtils; +import org.chromium.ui.base.DeviceFormFactor; /** Find in page tests. */ @RunWith(ChromeJUnit4ClassRunner.class) @@ -466,6 +468,7 @@ @Test @SmallTest @Feature({"FindInPage"}) + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testFindNextPreviousIncognitoTab() { String query = "pitts"; var incognitoPage = mPage.openNewIncognitoTabOrWindowFast();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/history/HistoryTabHelperTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/history/HistoryTabHelperTest.java index a76147e..5a75f96 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/history/HistoryTabHelperTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/history/HistoryTabHelperTest.java
@@ -37,6 +37,7 @@ import org.chromium.chrome.test.transit.ChromeTransitTestRules; import org.chromium.chrome.test.transit.FreshCtaTransitTestRule; import org.chromium.content_public.browser.LoadUrlParams; +import org.chromium.ui.base.DeviceFormFactor; import org.chromium.url.GURL; /** Tests for history tab helper. */ @@ -56,6 +57,7 @@ @DisableIf.Build( sdk_is_less_than = VERSION_CODES.UPSIDE_DOWN_CAKE, message = "This test is using an API introduced in Android U.") + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testAppHistory() throws Exception { Context context = ContextUtils.getApplicationContext(); Intent viewIntent =
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/media/PictureInPictureActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/media/PictureInPictureActivityTest.java index fbe3607..1ca7d24 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/media/PictureInPictureActivityTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/media/PictureInPictureActivityTest.java
@@ -85,7 +85,7 @@ // Token that the native side will convert to `NATIVE_OVERLAY` private final UnguessableToken mNativeWindowToken = UnguessableToken.createForTesting(); - @Mock private PictureInPictureActivity.Natives mNativeMock; + @Mock private VideoOverlayActivity.Natives mNativeMock; private Tab mTab; @@ -116,7 +116,7 @@ PictureInPictureActivity.interceptMoveTaskToBackForTesting(); mActivityTestRule.startOnBlankPage(); mTab = mActivityTestRule.getActivityTab(); - PictureInPictureActivityJni.setInstanceForTesting(mNativeMock); + VideoOverlayActivityJni.setInstanceForTesting(mNativeMock); mOriginalHelper = PictureInPictureActivity.setLaunchIntoPipHelper(mLaunchIntoPipHelper); when(mNativeMock.onActivityStart(eq(mNativeWindowToken), any(), any())) .thenReturn(NATIVE_OVERLAY);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/media/ui/MediaSessionTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/media/ui/MediaSessionTest.java index f81fd89..9bfdc0fa 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/media/ui/MediaSessionTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/media/ui/MediaSessionTest.java
@@ -4,6 +4,7 @@ package org.chromium.chrome.browser.media.ui; +import static org.chromium.build.NullUtil.assumeNonNull; import static org.chromium.chrome.browser.url_constants.UrlConstantResolver.getOriginalNativeNtpUrl; import android.content.Intent; @@ -19,7 +20,6 @@ import org.junit.runner.RunWith; import org.chromium.base.FakeTimeTestRule; -import org.chromium.base.ScreenStateReceiver; import org.chromium.base.ThreadUtils; import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.CriteriaHelper; @@ -37,6 +37,7 @@ import org.chromium.components.browser_ui.media.MediaFeatureList; import org.chromium.components.browser_ui.media.MediaNotificationController; import org.chromium.components.browser_ui.media.MediaNotificationManager; +import org.chromium.components.browser_ui.media.MediaSessionHelper; import org.chromium.components.url_formatter.SchemeDisplay; import org.chromium.components.url_formatter.UrlFormatter; import org.chromium.content_public.browser.test.util.DOMUtils; @@ -160,8 +161,9 @@ ThreadUtils.runOnUiThreadBlocking( () -> { Intent i = new Intent(Intent.ACTION_SCREEN_OFF); - ScreenStateReceiver.getInstance() - .onReceive(ApplicationProvider.getApplicationContext(), i); + assumeNonNull(MediaSessionHelper.sInstanceForTesting) + .getScreenStateObserverForTesting() + .onScreenOff(ApplicationProvider.getApplicationContext(), i); }); } @@ -169,8 +171,9 @@ ThreadUtils.runOnUiThreadBlocking( () -> { Intent i = new Intent(Intent.ACTION_SCREEN_ON); - ScreenStateReceiver.getInstance() - .onReceive(ApplicationProvider.getApplicationContext(), i); + assumeNonNull(MediaSessionHelper.sInstanceForTesting) + .getScreenStateObserverForTesting() + .onScreenOn(ApplicationProvider.getApplicationContext(), i); }); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/metrics/UmaActivityObserverTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/metrics/UmaActivityObserverTest.java index 26eed20b..31192ea 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/metrics/UmaActivityObserverTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/metrics/UmaActivityObserverTest.java
@@ -26,6 +26,7 @@ import org.chromium.base.test.transit.TravelException; import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.CriteriaHelper; +import org.chromium.base.test.util.DisableIf; import org.chromium.base.test.util.DoNotBatch; import org.chromium.base.test.util.Features.DisableFeatures; import org.chromium.base.test.util.Features.EnableFeatures; @@ -52,6 +53,7 @@ // multi-display mode with Chrome not running in an adjacent window. @Restriction({DeviceFormFactor.TABLET_OR_DESKTOP, DeviceRestriction.RESTRICTION_TYPE_NON_AUTO}) @EnableFeatures({ChromeFeatureList.UMA_SESSION_CORRECTNESS_FIXES}) +@DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public class UmaActivityObserverTest { @Rule public FreshCtaTransitTestRule mCtaTestRule =
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31Test.java b/chrome/android/javatests/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31Test.java index 539cd6d..0547a5b 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31Test.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31Test.java
@@ -34,6 +34,7 @@ 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.DisableIf; import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.DoNotBatch; import org.chromium.base.test.util.MinAndroidSdkLevel; @@ -54,6 +55,7 @@ import org.chromium.chrome.test.transit.FreshCtaTransitTestRule; import org.chromium.chrome.test.util.ChromeTabUtils; import org.chromium.components.embedder_support.util.UrlConstants; +import org.chromium.ui.base.DeviceFormFactor; import org.chromium.ui.modaldialog.ModalDialogManager; import java.util.ArrayList; @@ -142,6 +144,7 @@ // Final state: max limit = 2, active tasks = 2, inactive tasks = 2. @Test @MediumTest + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void decreaseInstanceLimit_ExcessActive_ExcessTasksFinished() { // Set initial instance limit. MultiWindowUtils.setMaxInstancesForTesting(4);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/IncognitoNtpOmniboxAutofocusTrackerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/IncognitoNtpOmniboxAutofocusTrackerTest.java index 6b8f617..85cfcf4 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/IncognitoNtpOmniboxAutofocusTrackerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/IncognitoNtpOmniboxAutofocusTrackerTest.java
@@ -20,6 +20,7 @@ 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.DisableIf; import org.chromium.base.test.util.Features.EnableFeatures; import org.chromium.base.test.util.HistogramWatcher; import org.chromium.base.test.util.Restriction; @@ -38,6 +39,7 @@ @RunWith(ChromeJUnit4ClassRunner.class) @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) @Batch(Batch.PER_CLASS) +@DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public class IncognitoNtpOmniboxAutofocusTrackerTest { @Rule public FreshCtaTransitTestRule mActivityTestRule =
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageNavigationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageNavigationTest.java index 3838950..3576976 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageNavigationTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageNavigationTest.java
@@ -15,6 +15,7 @@ import org.junit.runner.RunWith; import org.chromium.base.test.util.CommandLineFlags; +import org.chromium.base.test.util.DisableIf; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.HistogramWatcher; import org.chromium.chrome.browser.flags.ChromeSwitches; @@ -28,6 +29,7 @@ import org.chromium.chrome.test.transit.ntp.RegularNewTabPageStation; import org.chromium.chrome.test.transit.page.WebPageStation; import org.chromium.net.test.EmbeddedTestServer; +import org.chromium.ui.base.DeviceFormFactor; /** Tests loading the NTP and navigating between it and other pages. */ @RunWith(ChromeJUnit4ClassRunner.class) @@ -90,6 +92,7 @@ /** Tests navigating to the tab switcher from the Incognito NTP. */ @Test @MediumTest + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testNavigateToTabSwitcherFromIncognitoNtp() { try (var histogram = HistogramWatcher.newBuilder()
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageAutoFetchTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageAutoFetchTest.java index 3490d666..986a28e 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageAutoFetchTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageAutoFetchTest.java
@@ -24,6 +24,7 @@ import org.chromium.base.test.util.CallbackHelper; import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.CriteriaHelper; +import org.chromium.base.test.util.DisableIf; import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.RequiresRestart; @@ -46,6 +47,7 @@ import org.chromium.net.NetworkChangeNotifier; import org.chromium.net.test.util.WebServer; import org.chromium.net.test.util.WebServer.HTTPRequest; +import org.chromium.ui.base.DeviceFormFactor; import org.chromium.ui.base.PageTransition; import java.io.IOException; @@ -372,6 +374,7 @@ @Test @MediumTest @Feature({"OfflineAutoFetch"}) + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testAutoFetchNotifyOnTabClose() throws Exception { final String testUrl = "http://www.offline.com"; // Make |testUrl| return an offline error and attempt to load the page.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoViewTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoViewTest.java index 3621983..78e1a41 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoViewTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoViewTest.java
@@ -66,6 +66,7 @@ import org.chromium.base.test.transit.ViewElement; import org.chromium.base.test.util.CallbackHelper; import org.chromium.base.test.util.CommandLineFlags; +import org.chromium.base.test.util.DisableIf; import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.Features; @@ -651,6 +652,7 @@ @MediumTest @Feature({"RenderTest"}) @Features.EnableFeatures(PermissionsAndroidFeatureList.APPROXIMATE_GEOLOCATION_PERMISSION) + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testShowPermissionsSubpage() throws IOException { addSomePermissions(mTestServerRule.getServer().getURL("/")); loadUrlAndOpenPageInfo(mTestServerRule.getServer().getURL(sSimpleHtml));
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestContactDetailsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestContactDetailsTest.java index 085e422..0ad7809 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestContactDetailsTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestContactDetailsTest.java
@@ -4,6 +4,9 @@ package org.chromium.chrome.browser.payments; +import org.chromium.base.test.util.DisableIf; +import org.chromium.ui.base.DeviceFormFactor; + import androidx.test.filters.MediumTest; import org.junit.Assert; @@ -35,6 +38,7 @@ /** A payment integration test for a merchant that requests contact details. */ @RunWith(ChromeJUnit4ClassRunner.class) @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) +@DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public class PaymentRequestContactDetailsTest { @Rule public PaymentRequestTestRule mPaymentRequestTestRule =
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sensitive_content/SensitiveContentTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sensitive_content/SensitiveContentTest.java index bebacf3..5c9e7d1 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/sensitive_content/SensitiveContentTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sensitive_content/SensitiveContentTest.java
@@ -35,6 +35,7 @@ import org.chromium.base.ThreadUtils; import org.chromium.base.test.util.CommandLineFlags; +import org.chromium.base.test.util.DisableIf; import org.chromium.base.test.util.DoNotBatch; import org.chromium.base.test.util.Features.EnableFeatures; import org.chromium.base.test.util.HistogramWatcher; @@ -119,6 +120,7 @@ @Test @MediumTest + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testTabHasSensitiveContentWhileSensitiveFieldsArePresent() { assertNotSensitive(mPage); @@ -131,6 +133,7 @@ @Test @MediumTest + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testSensitiveContentClientObserver() { assertNotSensitive(mPage); @@ -192,6 +195,7 @@ @Test @MediumTest @EnableFeatures(SensitiveContentFeatures.SENSITIVE_CONTENT_WHILE_SWITCHING_TABS) + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testTabHasSensitiveContentAttributeIsUpdated() { final Tab tab = mCtaTestRule.getActivityTab(); assertFalse(tab.getTabHasSensitiveContent()); @@ -248,6 +252,7 @@ @Test @LargeTest @EnableFeatures(SensitiveContentFeatures.SENSITIVE_CONTENT_WHILE_SWITCHING_TABS) + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testIncognitoTabSwitcherBecomesSensitive() { final String histogram = "SensitiveContent.TabSwitching.IncognitoTabSwitcherPane.Sensitivity"; @@ -314,6 +319,7 @@ @Test @LargeTest @EnableFeatures(SensitiveContentFeatures.SENSITIVE_CONTENT_WHILE_SWITCHING_TABS) + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testIncognitoTabSwitcherBecomesSensitiveWithTabGroups() { // Open the first incognito tab. CtaPageStation page = mPage.openNewIncognitoTabOrWindowFast();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/FullscreenSigninAndHistorySyncIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/FullscreenSigninAndHistorySyncIntegrationTest.java index 0f7909b5..92474fdd 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/FullscreenSigninAndHistorySyncIntegrationTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/FullscreenSigninAndHistorySyncIntegrationTest.java
@@ -452,6 +452,7 @@ @Test @MediumTest + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testUserAlreadySignedIn_refuseHistorySync_historySyncRequired() { HistogramWatcher historySyncHistogramWatcher = HistogramWatcher.newBuilder() @@ -597,6 +598,7 @@ @Test @MediumTest @DisableFeatures(SigninFeatures.SUPPORT_FORCED_SIGNIN_POLICY) + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testBackPress() { mBlankUiActivityTestRule.launchActivity(null); when(mHistorySyncHelperMock.shouldDisplayHistorySync()).thenReturn(true);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninFirstRunFragmentRenderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninFirstRunFragmentRenderTest.java index a01eb5a..9283d03 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninFirstRunFragmentRenderTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninFirstRunFragmentRenderTest.java
@@ -42,6 +42,7 @@ import org.chromium.base.test.util.ApplicationTestUtils; import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.CriteriaHelper; +import org.chromium.base.test.util.DisableIf; import org.chromium.base.test.util.DoNotBatch; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.Features.EnableFeatures; @@ -69,6 +70,7 @@ import org.chromium.components.user_prefs.UserPrefs; import org.chromium.components.user_prefs.UserPrefsJni; import org.chromium.content_public.browser.test.NativeLibraryTestUtils; +import org.chromium.ui.base.DeviceFormFactor; import org.chromium.ui.test.util.BlankUiTestActivity; import org.chromium.ui.test.util.DeviceRestriction; import org.chromium.ui.test.util.RenderTestRule; @@ -84,6 +86,7 @@ @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) @Restriction(DeviceRestriction.RESTRICTION_TYPE_NON_AUTO) @DoNotBatch(reason = "Relies on global state") +@DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public class SigninFirstRunFragmentRenderTest { /** Parameter provider for night mode state and device orientation. */ public static class NightModeAndOrientationParameterProvider implements ParameterProvider {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninFirstRunFragmentTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninFirstRunFragmentTest.java index 8e0eab89..8a55edd 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninFirstRunFragmentTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninFirstRunFragmentTest.java
@@ -124,6 +124,7 @@ import org.chromium.components.user_prefs.UserPrefs; import org.chromium.content_public.browser.test.NativeLibraryTestUtils; import org.chromium.ui.UiUtils; +import org.chromium.ui.base.DeviceFormFactor; import org.chromium.ui.test.util.BlankUiTestActivity; import org.chromium.ui.test.util.DeviceRestriction; import org.chromium.ui.test.util.NightModeTestUtils; @@ -328,6 +329,7 @@ @Test @MediumTest @Restriction({DeviceRestriction.RESTRICTION_TYPE_NON_AUTO}) + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testRemovingAllAccountsDismissesAccountPickerDialog() { mSigninTestRule.addAccount(TestAccounts.ACCOUNT1); launchActivityWithFragment(); @@ -991,6 +993,7 @@ @Test @MediumTest + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testFragmentWhenClickingOnTosLink() { launchActivityWithFragment(); @@ -1017,6 +1020,7 @@ @Test @MediumTest @Restriction({DeviceRestriction.RESTRICTION_TYPE_NON_AUTO}) + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testUIStateChangeOnContinueButtonPress_XplatSyncedSetup() { mSigninTestRule.addAccount(TestAccounts.ACCOUNT1); launchActivityWithFragment(); @@ -1048,6 +1052,7 @@ @Test @MediumTest @Restriction({DeviceRestriction.RESTRICTION_TYPE_NON_AUTO}) + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testSuccessfulSignInFlow_XplatSyncedSetup() { mSigninTestRule.addAccount(TestAccounts.ACCOUNT1); launchActivityWithFragment(); @@ -1133,6 +1138,7 @@ @Test @MediumTest @Restriction({DeviceRestriction.RESTRICTION_TYPE_NON_AUTO}) + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testStatePreservationOnRotation_XplatSyncedSetup() { mSigninTestRule.addAccount(TestAccounts.ACCOUNT1); launchActivityWithFragment(); @@ -1254,6 +1260,7 @@ @Test @MediumTest @Restriction({DeviceRestriction.RESTRICTION_TYPE_NON_AUTO}) + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testContinueButtonWhenAllowCrashUploadTurnedOff() { mSigninTestRule.addAccount(TestAccounts.ACCOUNT1); launchActivityWithFragment();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/tile/MostVisitedTilesLayoutTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/tile/MostVisitedTilesLayoutTest.java index f99f483..e6dfa573 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/tile/MostVisitedTilesLayoutTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/tile/MostVisitedTilesLayoutTest.java
@@ -4,6 +4,9 @@ package org.chromium.chrome.browser.suggestions.tile; +import org.chromium.base.test.util.DisableIf; +import org.chromium.ui.base.DeviceFormFactor; + import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; @@ -149,6 +152,7 @@ @Feature({"NewTabPage", "RenderTest"}) @ParameterAnnotations.UseMethodParameter(NightModeTestUtils.NightModeParams.class) @DisableFeatures({ChromeFeatureList.MOST_VISITED_TILES_CUSTOMIZATION}) + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testTilesLayoutAppearance_DisableMvtCustomization(boolean nightModeEnabled) throws Exception { doTilesLayoutAppearanceTest(nightModeEnabled, ""); @@ -159,6 +163,7 @@ @Feature({"NewTabPage", "RenderTest"}) @ParameterAnnotations.UseMethodParameter(NightModeTestUtils.NightModeParams.class) @EnableFeatures({ChromeFeatureList.MOST_VISITED_TILES_CUSTOMIZATION}) + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testTilesLayoutAppearance_EnableMvtCustomization(boolean nightModeEnabled) throws Exception { doTilesLayoutAppearanceTest(nightModeEnabled, "_with_add_new_button"); @@ -177,6 +182,7 @@ @MediumTest @Feature({"NewTabPage", "RenderTest"}) @DisableFeatures({ChromeFeatureList.MOST_VISITED_TILES_CUSTOMIZATION}) + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testModernTilesLayoutAppearance_Full_DisableMvtCustomization() throws IOException, InterruptedException { doModernTilesLayoutAppearanceTest_Full(""); @@ -186,6 +192,7 @@ @MediumTest @Feature({"NewTabPage", "RenderTest"}) @EnableFeatures({ChromeFeatureList.MOST_VISITED_TILES_CUSTOMIZATION}) + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testModernTilesLayoutAppearance_Full_EnableMvtCustomization() throws IOException, InterruptedException { doModernTilesLayoutAppearanceTest_Full("_with_add_new_button"); @@ -222,6 +229,7 @@ @Test @MediumTest @Feature({"NewTabPage", "RenderTest"}) + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testModernTilesLayoutAppearance_Two() throws IOException, InterruptedException { ThreadUtils.runOnUiThreadBlocking( () ->
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncTest.java index d98ecd6..d27f802c 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncTest.java
@@ -16,6 +16,7 @@ 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.DisableIf; import org.chromium.base.test.util.DoNotBatch; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.Matchers; @@ -28,6 +29,7 @@ import org.chromium.components.sync.PassphraseType; import org.chromium.components.sync.TransportState; import org.chromium.components.sync.UserSelectableType; +import org.chromium.ui.base.DeviceFormFactor; import java.util.Set; @@ -53,6 +55,7 @@ @Test @LargeTest @Feature({"Sync"}) + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testStopAndClear() { mSyncTestRule.getFakeServerHelper().setTrustedVaultNigori(new byte[] {1, 2, 3, 4}); mSyncTestRule.setUpAccountAndSignInForTesting();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tabbed_mode/KeyboardFocusRowManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tabbed_mode/KeyboardFocusRowManagerTest.java index 53c9aa6..0ec921b3 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/tabbed_mode/KeyboardFocusRowManagerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tabbed_mode/KeyboardFocusRowManagerTest.java
@@ -31,6 +31,7 @@ import org.chromium.base.test.util.Batch; import org.chromium.base.test.util.CallbackHelper; import org.chromium.base.test.util.CommandLineFlags; +import org.chromium.base.test.util.DisableIf; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.Features.DisableFeatures; import org.chromium.base.test.util.Features.EnableFeatures; @@ -109,6 +110,7 @@ @SmallTest @Restriction(DeviceFormFactor.TABLET_OR_DESKTOP) @Feature("KeyboardShortcuts") + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testSwitchKeyboardFocusRow_withTabletTabStrip() { // Put something in the content view so we can focus on it. ChromeTabUtils.newTabFromMenu( @@ -150,6 +152,7 @@ @Restriction(DeviceFormFactor.TABLET_OR_DESKTOP) @Feature("KeyboardShortcuts") @EnableFeatures(ChromeFeatureList.ANDROID_BOOKMARK_BAR) + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testSwitchKeyboardFocusRow_withBookmarksBar() { setBookmarkBarFeatureParam(true); setUserPrefsShowBookmarksBar(true); @@ -208,6 +211,7 @@ @SmallTest @Feature("KeyboardShortcuts") @Restriction(DeviceFormFactor.TABLET_OR_DESKTOP) + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testSkipStripIfHidden() { ThreadUtils.runOnUiThreadBlocking( () ->
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/adaptive/OptionalNewTabButtonControllerTabletTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/adaptive/OptionalNewTabButtonControllerTabletTest.java index 45838d8..1d9912f28 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/adaptive/OptionalNewTabButtonControllerTabletTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/adaptive/OptionalNewTabButtonControllerTabletTest.java
@@ -84,6 +84,7 @@ @Test @MediumTest + @Restriction(DeviceFormFactor.ONLY_TABLET) public void testButton_hiddenOnTablet_portrait() { ActivityTestUtils.rotateActivityToOrientation( mActivityTestRule.getActivity(), Configuration.ORIENTATION_PORTRAIT);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/TabSwitcherActionMenuPTTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/TabSwitcherActionMenuPTTest.java index 0c48c33..6fa9cd6 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/TabSwitcherActionMenuPTTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/TabSwitcherActionMenuPTTest.java
@@ -17,6 +17,7 @@ import org.junit.runner.RunWith; import org.chromium.base.test.util.CommandLineFlags; +import org.chromium.base.test.util.DisableIf; import org.chromium.base.test.util.DoNotBatch; import org.chromium.base.test.util.Features.DisableFeatures; import org.chromium.chrome.browser.flags.ChromeFeatureList; @@ -32,6 +33,7 @@ import org.chromium.chrome.test.transit.ntp.RegularNewTabPageStation; import org.chromium.chrome.test.transit.page.TabSwitcherActionMenuFacility; import org.chromium.chrome.test.transit.page.WebPageStation; +import org.chromium.ui.base.DeviceFormFactor; /** * Instrumentation tests for tab switcher long-press menu popup. @@ -71,6 +73,7 @@ @Test @LargeTest + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testOpenNewTabFromIncognito() { IncognitoNewTabPageStation incognitoNtp = mCtaTestRule @@ -91,6 +94,7 @@ @Test @LargeTest + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testOpenNewIncognitoTabFromIncognito() { IncognitoNewTabPageStation incognitoNtp = mCtaTestRule
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/video/FullscreenVideoTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/video/FullscreenVideoTest.java index 3ed3474..8299391 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/video/FullscreenVideoTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/video/FullscreenVideoTest.java
@@ -23,6 +23,7 @@ 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.DisableIf; import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.Features; import org.chromium.base.test.util.Restriction; @@ -39,6 +40,7 @@ import org.chromium.content_public.browser.test.util.DOMUtils; import org.chromium.content_public.browser.test.util.TestTouchUtils; import org.chromium.media.MediaSwitches; +import org.chromium.ui.base.DeviceFormFactor; import org.chromium.ui.test.util.DeviceRestriction; import java.util.concurrent.TimeoutException; @@ -51,6 +53,7 @@ }) @Features.EnableFeatures(ChromeFeatureList.DISPLAY_EDGE_TO_EDGE_FULLSCREEN) @Batch(Batch.PER_CLASS) +@DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public class FullscreenVideoTest { @Rule public FreshCtaTransitTestRule mActivityTestRule =
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/video/VideoTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/video/VideoTest.java index 095c24d0..5804f7c 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/video/VideoTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/video/VideoTest.java
@@ -28,6 +28,7 @@ import org.chromium.chrome.test.util.browser.TabTitleObserver; import org.chromium.content_public.browser.test.util.DOMUtils; import org.chromium.content_public.common.ContentFeatures; +import org.chromium.ui.base.DeviceFormFactor; import java.util.concurrent.TimeoutException; @@ -53,6 +54,7 @@ @DisableIf.Build( sdk_equals = Build.VERSION_CODES.Q, message = "crbug.com/447426928, crashing emulator with --disable-field-trial-config") + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testLoadMediaUrl() throws TimeoutException { Tab tab = mPage.getTab(); TabTitleObserver titleObserver = new TabTitleObserver(tab, "ready_to_play");
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webid/DigitalCredentialProviderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webid/DigitalCredentialProviderTest.java index 88db5ba..e7e9d299 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/webid/DigitalCredentialProviderTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webid/DigitalCredentialProviderTest.java
@@ -4,6 +4,9 @@ package org.chromium.chrome.browser.webid; +import org.chromium.base.test.util.DisableIf; +import org.chromium.ui.base.DeviceFormFactor; + import static org.hamcrest.Matchers.is; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; @@ -45,6 +48,7 @@ @RunWith(ChromeJUnit4ClassRunner.class) @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) @Batch(Batch.PER_CLASS) +@DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public class DigitalCredentialProviderTest { private static final String TEST_PAGE = "/chrome/test/data/android/dc_mdocs.html"; private static final String EXPECTED_MDOC = "test-mdoc";
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutTrailingButtonsCoordinatorTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutTrailingButtonsCoordinatorTest.java index 2821f89..387e3ab 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutTrailingButtonsCoordinatorTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutTrailingButtonsCoordinatorTest.java
@@ -98,7 +98,7 @@ mActivity.setTheme(R.style.Theme_BrowserUI_DayNight); when(mTaskTracker.get(anyInt())).thenReturn(mTask); - when(mTask.getOrCreateNativeBrowserWindowPtr(any())).thenReturn(mBwiPtr); + when(mTask.getNativeBrowserWindowPtr(any(), any())).thenReturn(mBwiPtr); UserPrefsJni.setInstanceForTesting(mUserPrefsJniMock); when(mUserPrefsJniMock.get(mProfile)).thenReturn(mPrefService); @@ -240,6 +240,27 @@ } @Test + public void testGlicHighlightedState_WindowPtrZero() { + assertNotNull("Glic button should be created.", mGlicButton); + + ArgumentCaptor<GlobalShowHideObserver> observerCaptor = + ArgumentCaptor.forClass(GlobalShowHideObserver.class); + Mockito.verify(mGlicKeyedService).addGlobalShowHideObserver(observerCaptor.capture()); + + // Simulate getNativeBrowserWindowPtr returning 0 + when(mTask.getNativeBrowserWindowPtr(any(), any())).thenReturn(0L); + + // Simulate Glic UI opening event. + when(mGlicKeyedService.isPanelShowingForBrowser(mBwiPtr)).thenReturn(true); + observerCaptor.getValue().onGlobalShowHide(); + + // Verify button is NOT highlighted because ptr was 0. + assertFalse( + "Glic button should not be highlighted when window ptr is 0.", + mGlicButton.isHighlighted()); + } + + @Test public void testGlicDismissNudgeButton() { mCoordinator.setGlicButtonText("Glic Nudge Text", /* isActor= */ false); mCoordinator.setGlicDismissNudgeButtonVisible(true);
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/gesturenav/GestureUserEducationIphControllerUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/gesturenav/GestureUserEducationIphControllerUnitTest.java index 7267fec..449c75a 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/gesturenav/GestureUserEducationIphControllerUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/gesturenav/GestureUserEducationIphControllerUnitTest.java
@@ -98,6 +98,7 @@ when(mWindowAndroid.getWindow()).thenReturn(mWindow); when(mTab.getWebContents()).thenReturn(mWebContents); when(mWebContents.getNavigationController()).thenReturn(mNavigationController); + mController.setDisableAnimationsForTesting(true); } @Test
diff --git a/chrome/android/modules/xr/BUILD.gn b/chrome/android/modules/xr/BUILD.gn index bcbfda4b..36e8149 100644 --- a/chrome/android/modules/xr/BUILD.gn +++ b/chrome/android/modules/xr/BUILD.gn
@@ -5,11 +5,16 @@ import("//build/config/android/rules.gni") import("//chrome/common/features.gni") import("//third_party/grpc-java/grpc_java_library.gni") +import("//third_party/jni_zero/jni_zero.gni") import("//tools/grit/grit_rule.gni") # Main Android library for the module android_library("java") { sources = [ + "internal/java/src/org/chromium/chrome/browser/media/immersive_playback/ImmersiveVideoControlDelegate.java", + "internal/java/src/org/chromium/chrome/browser/media/immersive_playback/ImmersiveVideoControlPanel.java", + "internal/java/src/org/chromium/chrome/browser/media/immersive_playback/ImmersiveVideoPlaybackActivity.java", + "internal/java/src/org/chromium/chrome/browser/media/immersive_playback/ImmersiveVideoPlaybackCoordinator.java", "internal/java/src/org/chromium/chrome/browser/xr/scenecore/XrEntityHolderFactory.java", "internal/java/src/org/chromium/chrome/browser/xr/scenecore/XrEntityHolderImpl.java", "internal/java/src/org/chromium/chrome/browser/xr/scenecore/XrModuleProviderImpl.java", @@ -24,12 +29,19 @@ "//base:build_info_java", "//base:bundle_utils_java", "//base:log_java", + "//base:resetters_java", "//base:supplier_java", "//base:task_executor_java", "//base:tasks_java", + "//base:token_java", "//build/android:build_java", + "//chrome/android:chrome_java", "//chrome/android:xr_java", "//chrome/browser/android/lifecycle:java", + "//chrome/browser/tab:java", + "//components/thin_webview:factory_java", + "//components/thin_webview:java", + "//content/public/android:content_java", "//third_party/android_deps:guava_java", "//third_party/androidx:androidx_annotation_annotation_java", "//third_party/androidx:androidx_xr_arcore_arcore_java", @@ -37,6 +49,7 @@ "//third_party/androidx:androidx_xr_runtime_runtime_java", "//third_party/androidx:androidx_xr_runtime_runtime_openxr_java", "//third_party/androidx:androidx_xr_scenecore_scenecore_java", + "//third_party/jni_zero:jni_zero_java", "//ui/android:ui_java", ] } @@ -72,3 +85,26 @@ "//ui/android:ui_no_recycler_view_java", ] } + +java_group("javatests_manifest_java") { + testonly = true + mergeable_android_manifests = [ "internal/java/AndroidManifest.xml" ] +} + +android_library("javatests") { + testonly = true + resources_package = "org.chromium.chrome" + + sources = [ + "internal/javatests/src/org/chromium/chrome/browser/media/immersive_playback/ImmersiveVideoPlaybackActivityTest.java", + "internal/javatests/src/org/chromium/chrome/browser/media/immersive_playback/ImmersiveVideoPlaybackCoordinatorTest.java", + ] + + deps = [ + ":java", + ":javatests_manifest_java", + "//base:flagged_apis_java", + "//chrome/android/javatests:chrome_test_java_helper", + "//components/thin_webview:java", + ] +}
diff --git a/chrome/android/modules/xr/DEPS b/chrome/android/modules/xr/DEPS new file mode 100644 index 0000000..711ddc1 --- /dev/null +++ b/chrome/android/modules/xr/DEPS
@@ -0,0 +1,3 @@ +include_rules = [ + "+components/thin_webview/java/src/org/chromium/components/thinwebview", +]
diff --git a/chrome/android/modules/xr/internal/java/AndroidManifest.xml b/chrome/android/modules/xr/internal/java/AndroidManifest.xml index bd9d1f2c..2dcd32ac 100644 --- a/chrome/android/modules/xr/internal/java/AndroidManifest.xml +++ b/chrome/android/modules/xr/internal/java/AndroidManifest.xml
@@ -1,6 +1,7 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:dist="http://schemas.android.com/apk/distribution" - featureSplit="xr"> + featureSplit="xr" + package="org.chromium.chrome"> <dist:module dist:title="@string/xr_module_title"> @@ -17,6 +18,18 @@ <dist:fusing dist:include="false"/> </dist:module> - <application /> + <application> + <activity android:name="org.chromium.chrome.browser.media.immersive_playback.ImmersiveVideoPlaybackActivity" + android:exported="false" + android:noHistory="true" + android:theme="@style/Theme.Chromium.Activity" + android:excludeFromRecents="true" + android:configChanges= + "screenSize|smallestScreenSize|screenLayout|orientation"> + <property + android:name="android.window.PROPERTY_XR_ACTIVITY_START_MODE" + android:value="XR_ACTIVITY_START_MODE_FULL_SPACE_MANAGED" /> + </activity> + </application> -</manifest> \ No newline at end of file +</manifest>
diff --git a/chrome/android/modules/xr/internal/java/src/org/chromium/chrome/browser/media/immersive_playback/ImmersiveVideoControlDelegate.java b/chrome/android/modules/xr/internal/java/src/org/chromium/chrome/browser/media/immersive_playback/ImmersiveVideoControlDelegate.java new file mode 100644 index 0000000..73abba8f --- /dev/null +++ b/chrome/android/modules/xr/internal/java/src/org/chromium/chrome/browser/media/immersive_playback/ImmersiveVideoControlDelegate.java
@@ -0,0 +1,25 @@ +// 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.media.immersive_playback; + +import org.chromium.build.annotations.NullMarked; + +/** Delegate for controlling media playback. */ +@NullMarked +public interface ImmersiveVideoControlDelegate { + /** + * Toggles the playback state between playing and paused. + * + * @param isPlaying True if the media is currently playing, false otherwise. + */ + void togglePlayPause(boolean isPlaying); + + /** + * Seeks to the specified position. + * + * @param positionMs The position to seek to, in milliseconds. + */ + void seekTo(long positionMs); +}
diff --git a/chrome/android/modules/xr/internal/java/src/org/chromium/chrome/browser/media/immersive_playback/ImmersiveVideoControlPanel.java b/chrome/android/modules/xr/internal/java/src/org/chromium/chrome/browser/media/immersive_playback/ImmersiveVideoControlPanel.java new file mode 100644 index 0000000..92ebb15 --- /dev/null +++ b/chrome/android/modules/xr/internal/java/src/org/chromium/chrome/browser/media/immersive_playback/ImmersiveVideoControlPanel.java
@@ -0,0 +1,190 @@ +// 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.media.immersive_playback; + +import android.content.Context; +import android.graphics.Color; +import android.os.Handler; +import android.os.Looper; +import android.os.SystemClock; +import android.view.Gravity; +import android.view.ViewGroup; +import android.widget.ImageButton; +import android.widget.LinearLayout; +import android.widget.SeekBar; +import android.widget.TextView; + +import org.chromium.build.annotations.NullMarked; +import org.chromium.chrome.R; + +import java.util.Locale; + +/** Manages the media control panel for Picture-in-Picture in an XR environment. */ +@NullMarked +public class ImmersiveVideoControlPanel extends LinearLayout { + private final ImmersiveVideoControlDelegate mVideoControlDelegate; + private final SeekBar mSeekBar; + private final TextView mPositionLabel; + private final ImageButton mPlayPauseButton; + private final Handler mHandler = new Handler(Looper.getMainLooper()); + private int mDuration; + private int mStartingPosition; + private long mLastUpdatedTime; + private double mPlaybackRate = 1f; + private boolean mIsPlaying; + private boolean mIsSeeking; + + private final Runnable mUpdateSeekbarTask = + new Runnable() { + @Override + public void run() { + if (mPlaybackRate <= 0) return; + long timeDiff = SystemClock.elapsedRealtime() - mLastUpdatedTime; + int offset = (int) (timeDiff * mPlaybackRate / 1000); + mSeekBar.setProgress(mStartingPosition + offset); + mHandler.postDelayed(this, 500); + } + }; + + /** + * @param context The context to create views in. + * @param videoControlDelegate The manager for media actions. + */ + public ImmersiveVideoControlPanel( + Context context, ImmersiveVideoControlDelegate videoControlDelegate) { + super(context); + mVideoControlDelegate = videoControlDelegate; + + setLayoutParams( + new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + setBackgroundColor(Color.BLACK); + setOrientation(LinearLayout.HORIZONTAL); + setGravity(Gravity.CENTER_VERTICAL); + setPadding(10, 10, 10, 10); + + mPlayPauseButton = createPlayPauseButton(); + mSeekBar = createSeekBarView(); + mPositionLabel = createPositionLabel(); + + addView(mPlayPauseButton); + addView(mSeekBar); + addView(mPositionLabel); + } + + /** + * Updates the seek bar with the current media position. + * + * @param durationMs The total duration of the media in milliseconds. + * @param positionMs The current position of the media in milliseconds. + * @param playbackRate The current playback rate of the media. + */ + public void updateMediaPosition(long durationMs, long positionMs, double playbackRate) { + if (mIsSeeking) return; + + mDuration = (int) (durationMs / 1000); + mStartingPosition = (int) (positionMs / 1000); + mPlaybackRate = playbackRate; + mLastUpdatedTime = SystemClock.elapsedRealtime(); + + mSeekBar.setMax(mDuration); + mHandler.removeCallbacks(mUpdateSeekbarTask); + + if (mPlaybackRate > 0) { + mHandler.postDelayed(mUpdateSeekbarTask, 500); + } else { + mSeekBar.setProgress(mStartingPosition); + } + } + + /** + * Updates the playback state of the control panel. + * + * @param isPlaying Whether the media is currently playing. + */ + public void updatePlaybackState(boolean isPlaying) { + mIsPlaying = isPlaying; + updatePlayPauseButtonState(isPlaying); + if (!isPlaying) { + mHandler.removeCallbacks(mUpdateSeekbarTask); + } + } + + public boolean isPlayingForTesting() { + return mIsPlaying; + } + + public SeekBar getSeekBarForTesting() { + return mSeekBar; + } + + private ImageButton createPlayPauseButton() { + ImageButton playPauseBtn = new ImageButton(getContext()); + playPauseBtn.setPadding(8, 8, 8, 8); + playPauseBtn.setBackgroundColor(Color.TRANSPARENT); + playPauseBtn.setOnClickListener(v -> mVideoControlDelegate.togglePlayPause(mIsPlaying)); + return playPauseBtn; + } + + private void updatePlayPauseButtonState(boolean isPlaying) { + mPlayPauseButton.setImageResource( + isPlaying ? R.drawable.ic_pause_white_24dp : R.drawable.ic_play_arrow_white_24dp); + mPlayPauseButton.setContentDescription( + getResources() + .getString( + isPlaying + ? R.string.accessibility_pause + : R.string.accessibility_play)); + } + + private SeekBar createSeekBarView() { + SeekBar seekBar = new SeekBar(getContext()); + LinearLayout.LayoutParams seekParams = + new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 1.0f); + seekBar.setLayoutParams(seekParams); + seekBar.setMax(0); + seekBar.setProgress(0); + seekBar.setOnSeekBarChangeListener( + new SeekBar.OnSeekBarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + if (fromUser) { + mVideoControlDelegate.seekTo(progress * 1000L); + } + mPositionLabel.setText(formatTime(progress, mDuration)); + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + mIsSeeking = true; + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + mIsSeeking = false; + } + }); + + return seekBar; + } + + private TextView createPositionLabel() { + TextView positionLabel = new TextView(getContext()); + positionLabel.setPadding(10, 0, 10, 0); + positionLabel.setTextAppearance(R.style.TextAppearance_TextSmall); + positionLabel.setText(formatTime(0, 0)); + return positionLabel; + } + + private String formatTime(int currentSec, int totalSec) { + return String.format( + Locale.US, + "%02d:%02d / %02d:%02d", + currentSec / 60, + currentSec % 60, + totalSec / 60, + totalSec % 60); + } +}
diff --git a/chrome/android/modules/xr/internal/java/src/org/chromium/chrome/browser/media/immersive_playback/ImmersiveVideoPlaybackActivity.java b/chrome/android/modules/xr/internal/java/src/org/chromium/chrome/browser/media/immersive_playback/ImmersiveVideoPlaybackActivity.java new file mode 100644 index 0000000..52c06fdc3 --- /dev/null +++ b/chrome/android/modules/xr/internal/java/src/org/chromium/chrome/browser/media/immersive_playback/ImmersiveVideoPlaybackActivity.java
@@ -0,0 +1,233 @@ +// 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.media.immersive_playback; + +import static org.chromium.build.NullUtil.assumeNonNull; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.view.ViewGroup; + +import androidx.annotation.VisibleForTesting; + +import org.chromium.base.ContextUtils; +import org.chromium.base.DeviceInfo; +import org.chromium.base.ResettersForTesting; +import org.chromium.base.UnguessableToken; +import org.chromium.build.annotations.Initializer; +import org.chromium.build.annotations.NullMarked; +import org.chromium.build.annotations.Nullable; +import org.chromium.chrome.browser.media.VideoOverlayActivity; +import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.browser.tab.TabUtils; +import org.chromium.components.thinwebview.CompositorView; +import org.chromium.content_public.browser.overlay_window.PlaybackState; +import org.chromium.ui.xr.scenecore.XrSurfaceEntityShape; +import org.chromium.ui.xr.scenecore.XrSurfaceEntityStereoMode; + +/** + * An immersive video playback activity which get created when requesting fullscreen from web API on + * XR devices. The activity will connect to web API through ImmersiveVideoPlaybackWindowAndroid. + */ +@NullMarked +public class ImmersiveVideoPlaybackActivity extends VideoOverlayActivity { + private static final String TAG = "ImmersiveVideoPlaybackActivity"; + + private @Nullable ImmersiveVideoPlaybackCoordinator mPlaybackCoordinator; + + @SuppressWarnings("StaticFieldLeak") + private static @Nullable ImmersiveVideoPlaybackCoordinator sPlaybackCoordinatorForTesting; + + /** Stores state that arrives before the UI is ready. This is only used on startup. */ + @VisibleForTesting + /* package */ static class PendingState { + public @Nullable Integer mVideoWidth; + public @Nullable Integer mVideoHeight; + public @Nullable @PlaybackState Integer mPlaybackState; + public @Nullable Long mDurationMs; + public @Nullable Long mPositionMs; + public @Nullable Double mPlaybackRate; + public @Nullable @XrSurfaceEntityStereoMode Integer mStereoMode; + public @Nullable @XrSurfaceEntityShape Integer mShape; + + void apply(ImmersiveVideoPlaybackActivity activity) { + if (mStereoMode != null || mShape != null) { + int stereo = mStereoMode != null ? mStereoMode : XrSurfaceEntityStereoMode.MONO; + int shape = mShape != null ? mShape : XrSurfaceEntityShape.QUAD; + activity.setImmersiveVideoOptions(stereo, shape); + } + if (mVideoWidth != null && mVideoHeight != null) { + activity.updateVideoSize(mVideoWidth, mVideoHeight); + } + if (mPlaybackState != null) { + activity.setPlaybackState(mPlaybackState); + } + if (mDurationMs != null && mPositionMs != null && mPlaybackRate != null) { + activity.setMediaPosition(mDurationMs, mPositionMs, mPlaybackRate); + } + reset(); + } + + void reset() { + mVideoWidth = null; + mVideoHeight = null; + mPlaybackState = null; + mDurationMs = null; + mPositionMs = null; + mPlaybackRate = null; + mStereoMode = null; + mShape = null; + } + } + + private final PendingState mPendingState = new PendingState(); + + /** Delegate for media control events. */ + private final ImmersiveVideoControlDelegate mVideoControlDelegate = + new ImmersiveVideoControlDelegate() { + @Override + public void togglePlayPause(boolean isPlaying) { + ImmersiveVideoPlaybackActivity.this.togglePlayPause(!isPlaying); + } + + @Override + public void seekTo(long positionMs) { + ImmersiveVideoPlaybackActivity.this.seekTo(positionMs); + } + }; + + @Override + @Initializer + public void onStart() { + super.onStart(); + + if (isInitiatorTabDestroyed()) { + return; + } + + if (!DeviceInfo.isXr()) { + finishOverlay(/* closeByNative= */ false); + return; + } + + finishInitialize(); + } + + @Initializer + private void finishInitialize() { + onActivityStart(); + + if (!isNativeHandleInitialized()) { + finishOverlay(/* closeByNative= */ true); + return; + } + } + + @Override + public void finishNativeInitialization() { + super.finishNativeInitialization(); + + if (sPlaybackCoordinatorForTesting != null) { + mPlaybackCoordinator = sPlaybackCoordinatorForTesting; + } else { + mPlaybackCoordinator = + new ImmersiveVideoPlaybackCoordinator( + this, assumeNonNull(getWindowAndroid()), mVideoControlDelegate); + + CompositorView compositorView = + mPlaybackCoordinator.createXrCompositorView( + XrSurfaceEntityStereoMode.MONO, XrSurfaceEntityShape.QUAD); + addContentView(compositorView.getView(), new ViewGroup.LayoutParams(0, 0)); + setCompositorView(compositorView); + } + + mPendingState.apply(this); + } + + @Override + public void setImmersiveVideoOptions( + @XrSurfaceEntityStereoMode int stereoMode, @XrSurfaceEntityShape int shape) { + if (mPlaybackCoordinator != null) { + mPlaybackCoordinator.updateVideoLayout(stereoMode, shape); + } else { + mPendingState.mStereoMode = stereoMode; + mPendingState.mShape = shape; + } + } + + @Override + protected void cleanup() { + if (mPlaybackCoordinator != null) { + mPlaybackCoordinator.destroy(); + mPlaybackCoordinator = null; + } + mPendingState.reset(); + } + + @Override + public void onStopWithNative() { + super.onStopWithNative(); + if (isNativeHandleInitialized()) { + onBackToTab(); + finishOverlay(/* closeByNative= */ false); + } + } + + @Override + public void updateVideoSize(int width, int height) { + if (mPlaybackCoordinator != null) { + mPlaybackCoordinator.updatePlayerSize(width, height); + } else { + mPendingState.mVideoWidth = width; + mPendingState.mVideoHeight = height; + } + } + + @Override + @VisibleForTesting + public void setPlaybackState(@PlaybackState int playbackState) { + if (mPlaybackCoordinator != null) { + mPlaybackCoordinator.updatePlaybackState(playbackState == PlaybackState.PLAYING); + } else { + mPendingState.mPlaybackState = playbackState; + } + } + + @Override + @VisibleForTesting + public void setMediaPosition(long durationMs, long positionMs, double playbackRate) { + if (mPlaybackCoordinator != null) { + mPlaybackCoordinator.updateMediaPosition(durationMs, positionMs, playbackRate); + } else { + mPendingState.mDurationMs = durationMs; + mPendingState.mPositionMs = positionMs; + mPendingState.mPlaybackRate = playbackRate; + } + } + + public PendingState getPendingStateForTesting() { + return mPendingState; + } + + public boolean isCoordinatorInitializedForTesting() { + return mPlaybackCoordinator != null; + } + + public static void setPlaybackCoordinatorForTesting( + ImmersiveVideoPlaybackCoordinator coordinator) { + sPlaybackCoordinatorForTesting = coordinator; + ResettersForTesting.register(() -> sPlaybackCoordinatorForTesting = null); + } + + public static void createActivity(UnguessableToken nativeToken, Object initiatorTab) { + Activity activity = TabUtils.getActivity((Tab) initiatorTab); + Context context = activity != null ? activity : ContextUtils.getApplicationContext(); + Intent intent = new Intent(context, ImmersiveVideoPlaybackActivity.class); + intent.putExtra(NATIVE_TOKEN_KEY, nativeToken); + intent.putExtra(WEB_CONTENTS_KEY, ((Tab) initiatorTab).getWebContents()); + context.startActivity(intent); + } +}
diff --git a/chrome/android/modules/xr/internal/java/src/org/chromium/chrome/browser/media/immersive_playback/ImmersiveVideoPlaybackCoordinator.java b/chrome/android/modules/xr/internal/java/src/org/chromium/chrome/browser/media/immersive_playback/ImmersiveVideoPlaybackCoordinator.java new file mode 100644 index 0000000..3428de5 --- /dev/null +++ b/chrome/android/modules/xr/internal/java/src/org/chromium/chrome/browser/media/immersive_playback/ImmersiveVideoPlaybackCoordinator.java
@@ -0,0 +1,337 @@ +// 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.media.immersive_playback; + +import static org.chromium.build.NullUtil.assumeNonNull; + +import android.app.Activity; +import android.os.Build; +import android.util.Rational; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.VisibleForTesting; + +import org.chromium.base.DeviceInfo; +import org.chromium.base.supplier.LazyOneshotSupplier; +import org.chromium.build.annotations.NullMarked; +import org.chromium.build.annotations.Nullable; +import org.chromium.chrome.browser.xr.scenecore.XrModule; +import org.chromium.components.thinwebview.CompositorView; +import org.chromium.components.thinwebview.CompositorViewFactory; +import org.chromium.components.thinwebview.ThinWebViewConstraints; +import org.chromium.ui.base.WindowAndroid; +import org.chromium.ui.xr.scenecore.XrCurvedSurfaceEntityHolder; +import org.chromium.ui.xr.scenecore.XrMovableComponent; +import org.chromium.ui.xr.scenecore.XrMovableComponent.OnMoveListener; +import org.chromium.ui.xr.scenecore.XrPanelEntityHolder; +import org.chromium.ui.xr.scenecore.XrQuadSurfaceEntityHolder; +import org.chromium.ui.xr.scenecore.XrResizableComponent; +import org.chromium.ui.xr.scenecore.XrResizableComponent.OnResizeListener; +import org.chromium.ui.xr.scenecore.XrResizableEntityHolder; +import org.chromium.ui.xr.scenecore.XrSceneCoreSessionManager; +import org.chromium.ui.xr.scenecore.XrSurfaceEntityHolder; +import org.chromium.ui.xr.scenecore.XrSurfaceEntityShape; +import org.chromium.ui.xr.scenecore.XrSurfaceEntityStereoMode; +import org.chromium.ui.xr.scenecore.XrSurfaceEntityView; + +/** A coordinator for XR specific Picture-in-Picture functionality. */ +@NullMarked +public class ImmersiveVideoPlaybackCoordinator { + private static final float PLAYER_PANEL_MIN_WIDTH_METERS = 0.5f; + private static final float PLAYER_PANEL_MAX_WIDTH_METERS = 3.0f; + private static final float PLAYER_PANEL_INITIAL_WIDTH_METERS = 2.0f; + private static final float PLAYER_PANEL_INITIAL_CURVE_RADIUS_METERS = 10.0f; + private static final float[] PLAYER_PANEL_INITIAL_TRANSLATION = {0.0f, 0.0f, -1.75f}; + private static final float[] PLAYER_PANEL_INITIAL_ROTATION = {0.0f, 0.0f, 0.0f, 1.0f}; + + private static final float[] MEDIA_CONTROL_PANEL_INITIAL_TRANSLATION = {0.0f, -1f, -1.75f}; + private static final float[] MEDIA_CONTROL_PANEL_INITIAL_ROTATION = {0.0f, 0.0f, 0.0f, 1.0f}; + private static final float MEDIA_CONTROL_PANEL_WIDTH_METERS = 1.0f; + private static final float MEDIA_CONTROL_PANEL_HEIGHT_METERS = 0.25f; + private static final float MEDIA_CONTROL_PANEL_VERTICAL_SPACING_METERS = 0.25f; + private static final float MEDIA_CONTROL_PANEL_Z_OFFSET_METERS = 0.01f; + + private final Activity mActivity; + private final WindowAndroid mWindowAndroid; + private final LazyOneshotSupplier<XrSceneCoreSessionManager> mXrSceneCoreSessionManagerSupplier; + private final ImmersiveVideoControlPanel mControlPanel; + + private @Nullable CompositorView mCompositorView; + private @Nullable XrSurfaceEntityHolder mSurfaceHolder; + private @Nullable XrPanelEntityHolder mControlPanelHolder; + private @Nullable OnMoveListener mPlayerPanelMoveListener; + private @Nullable OnResizeListener mPlayerPanelResizeListener; + private Rational mAspectRatio = new Rational(16, 9); + + /** + * @param activity The activity that will contain the XR compositor view. + * @param windowAndroid The window android for the activity. + * @param videoControlDelegate The delegate for media controls. + */ + public ImmersiveVideoPlaybackCoordinator( + Activity activity, + WindowAndroid windowAndroid, + ImmersiveVideoControlDelegate videoControlDelegate) { + mActivity = activity; + mWindowAndroid = windowAndroid; + mXrSceneCoreSessionManagerSupplier = + LazyOneshotSupplier.fromSupplier(this::createXrSceneCoreSessionManager); + mControlPanel = new ImmersiveVideoControlPanel(activity, videoControlDelegate); + } + + @VisibleForTesting + protected XrSceneCoreSessionManager createXrSceneCoreSessionManager() { + assert DeviceInfo.isXr(); + assert Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE; + assert XrModule.isInstalled() : "XR module must be installed on XR devices."; + return assumeNonNull(XrModule.getImpl().getXrSceneCoreSessionManager(mActivity)); + } + + /** + * Creates an XR compositor view and adds it to the activity. + * + * @param layout The video layout to use. + * @return The created compositor view. + */ + public CompositorView createXrCompositorView( + @XrSurfaceEntityStereoMode int stereoMode, @XrSurfaceEntityShape int shape) { + assumeNonNull(mXrSceneCoreSessionManagerSupplier.get()) + .getMainPanelEntity() + .setEntityEnabled(false); + + mControlPanelHolder = + mXrSceneCoreSessionManagerSupplier + .get() + .createPanelEntity(mControlPanel, "MediaControlPanel"); + + mPlayerPanelMoveListener = + new XrMovableComponent.OnMoveListener() { + @Override + public void onMoveUpdate(float[] translation, float[] rotation, float scale) { + if (mSurfaceHolder != null + && mSurfaceHolder.getSurfaceShape() == XrSurfaceEntityShape.QUAD) { + float height = + ((XrResizableEntityHolder) mSurfaceHolder) + .getEntitySize() + .getHeight(); + updateMediaControlPanelPose(translation, rotation, height); + } + } + }; + + mPlayerPanelResizeListener = + new XrResizableComponent.OnResizeListener() { + @Override + public void onResizeUpdate(float width, float height, float depth) { + if (mSurfaceHolder != null) { + float[] translation = mSurfaceHolder.getEntityTranslation(); + float[] rotation = mSurfaceHolder.getEntityRotation(); + updateMediaControlPanelPose(translation, rotation, height); + } + } + }; + + mCompositorView = createCompositorView(shape); + + if (mCompositorView.getView() instanceof XrSurfaceEntityView view) { + mSurfaceHolder = view.getHolder(); + updateVideoLayout(stereoMode, shape); + } + + return mCompositorView; + } + + @VisibleForTesting + protected CompositorView createCompositorView(int shape) { + return CompositorViewFactory.create( + mActivity, + mWindowAndroid, + new ThinWebViewConstraints(), + assumeNonNull(mXrSceneCoreSessionManagerSupplier.get()), + shape); + } + + /** + * Updates the video layout. + * + * @param layout The video layout to use. + */ + public void updateVideoLayout( + @XrSurfaceEntityStereoMode int stereoMode, @XrSurfaceEntityShape int shape) { + assumeNonNull(mSurfaceHolder); + updateShapeIfNeeded(shape); + updateStereoModeIfNeeded(stereoMode); + } + + private void updateStereoModeIfNeeded(@XrSurfaceEntityStereoMode int stereoMode) { + XrSurfaceEntityHolder surfaceHolder = assumeNonNull(mSurfaceHolder); + if (stereoMode != surfaceHolder.getSurfaceStereoMode()) { + surfaceHolder.setSurfaceStereoMode(stereoMode); + } + } + + private void updateShapeIfNeeded(@XrSurfaceEntityShape int shape) { + XrSurfaceEntityHolder surfaceHolder = assumeNonNull(mSurfaceHolder); + + if (surfaceHolder instanceof XrQuadSurfaceEntityHolder) { + resetQuadSurface((XrQuadSurfaceEntityHolder) surfaceHolder); + } + + surfaceHolder.setSurfaceShape(shape); + surfaceHolder.setEntityPose( + PLAYER_PANEL_INITIAL_TRANSLATION, PLAYER_PANEL_INITIAL_ROTATION); + + switch (shape) { + case XrSurfaceEntityShape.QUAD: + configureMediaControlPanel(false); + if (surfaceHolder instanceof XrQuadSurfaceEntityHolder) { + configureQuadSurface((XrQuadSurfaceEntityHolder) surfaceHolder); + } + break; + case XrSurfaceEntityShape.SPHERE: + case XrSurfaceEntityShape.HEMISPHERE: + configureMediaControlPanel(true); + if (surfaceHolder instanceof XrCurvedSurfaceEntityHolder) { + configureCurvedSurface((XrCurvedSurfaceEntityHolder) surfaceHolder); + } + break; + } + } + + private void configureMediaControlPanel(boolean isMovable) { + if (mControlPanelHolder == null) { + return; + } + + mControlPanelHolder.setEntitySize( + MEDIA_CONTROL_PANEL_WIDTH_METERS, MEDIA_CONTROL_PANEL_HEIGHT_METERS); + mControlPanelHolder.getMovableComponent().setMovable(isMovable, false); + } + + private void configureQuadSurface(XrQuadSurfaceEntityHolder quadHolder) { + float initialWidth = PLAYER_PANEL_INITIAL_WIDTH_METERS; + float initialHeight = calculateHeight(initialWidth); + float minWidth = PLAYER_PANEL_MIN_WIDTH_METERS; + float minHeight = calculateHeight(minWidth); + float maxWidth = PLAYER_PANEL_MAX_WIDTH_METERS; + float maxHeight = calculateHeight(maxWidth); + + XrResizableComponent resizable = quadHolder.getResizableComponent(); + XrMovableComponent movable = quadHolder.getMovableComponent(); + + quadHolder.setEntitySize(initialWidth, initialHeight); + resizable.setMinSize(minWidth, minHeight); + resizable.setMaxSize(maxWidth, maxHeight); + resizable.setResizable(true, true); + movable.setMovable(true, false); + movable.addMoveListener(assumeNonNull(mPlayerPanelMoveListener)); + resizable.addResizeListener(assumeNonNull(mPlayerPanelResizeListener)); + + updateMediaControlPanelPose( + PLAYER_PANEL_INITIAL_TRANSLATION, PLAYER_PANEL_INITIAL_ROTATION, initialHeight); + } + + private void resetQuadSurface(XrQuadSurfaceEntityHolder quadHolder) { + XrResizableComponent resizable = quadHolder.getResizableComponent(); + XrMovableComponent movable = quadHolder.getMovableComponent(); + + quadHolder.setEntitySize(1f, 1f); + resizable.setMinSize(1f, 1f); + resizable.setMaxSize(1f, 1f); + resizable.setResizable(false, false); + movable.setMovable(false, false); + movable.removeMoveListener(assumeNonNull(mPlayerPanelMoveListener)); + resizable.removeResizeListener(assumeNonNull(mPlayerPanelResizeListener)); + } + + private void configureCurvedSurface(XrCurvedSurfaceEntityHolder curvedHolder) { + curvedHolder.setEntityRadius(PLAYER_PANEL_INITIAL_CURVE_RADIUS_METERS); + if (mControlPanelHolder != null) { + mControlPanelHolder.setEntityPose( + MEDIA_CONTROL_PANEL_INITIAL_TRANSLATION, MEDIA_CONTROL_PANEL_INITIAL_ROTATION); + } + } + + private float calculateHeight(float width) { + Rational aspect = mAspectRatio; + if (aspect.floatValue() == 0) { + return width * 9f / 16f; + } + return width / aspect.floatValue(); + } + + private void updateMediaControlPanelPose(float[] translation, float[] rotation, float height) { + if (mControlPanelHolder != null) { + float[] newTranslation = translation.clone(); + // Move the media control panel under the player panel. + newTranslation[1] -= height / 2 + MEDIA_CONTROL_PANEL_VERTICAL_SPACING_METERS; + // Keep the media control panel slightly above the player panel. + newTranslation[2] += MEDIA_CONTROL_PANEL_Z_OFFSET_METERS; + mControlPanelHolder.setEntityPose(newTranslation, rotation); + } + } + + /** + * Updates the seek bar with the current media position. + * + * @param durationMs The total duration of the media in milliseconds. + * @param positionMs The current position of the media in milliseconds. + * @param playbackRate The current playback rate of the media. + */ + public void updateMediaPosition(long durationMs, long positionMs, double playbackRate) { + mControlPanel.updateMediaPosition(durationMs, positionMs, playbackRate); + } + + /** + * Updates the playback state of the control panel. + * + * @param isPlaying Whether the media is currently playing. + */ + public void updatePlaybackState(boolean isPlaying) { + mControlPanel.updatePlaybackState(isPlaying); + } + + /** + * Updates XR specific Picture-in-Picture parameters. + * + * @param width The current width. + * @param height The current height. + */ + public void updatePlayerSize(int width, int height) { + mAspectRatio = new Rational(width, height); + if (mSurfaceHolder != null) { + mSurfaceHolder.setSurfacePixelDimensions(width, height); + } + } + + public ImmersiveVideoControlPanel getControlPanelForTesting() { + return mControlPanel; + } + + /** Cleans up the coordinator and the compositor view. */ + public void destroy() { + if (mCompositorView != null) { + View view = mCompositorView.getView(); + if (view.getParent() instanceof ViewGroup parent) { + parent.removeView(view); + } + mCompositorView.destroy(); + mCompositorView = null; + } + if (mControlPanel.getParent() instanceof ViewGroup parent) { + parent.removeView(mControlPanel); + } + if (mControlPanelHolder != null) { + mControlPanelHolder.dispose(); + mControlPanelHolder = null; + } + // Listeners are cleaned up automatically during mCompositorView.destroy(), which + // disposes the surface holder and its components. + mPlayerPanelMoveListener = null; + mPlayerPanelResizeListener = null; + mSurfaceHolder = null; + } +}
diff --git a/chrome/android/modules/xr/internal/java/src/org/chromium/chrome/browser/xr/scenecore/XrModuleProviderImpl.java b/chrome/android/modules/xr/internal/java/src/org/chromium/chrome/browser/xr/scenecore/XrModuleProviderImpl.java index ff1e4d9..c2ed90d 100644 --- a/chrome/android/modules/xr/internal/java/src/org/chromium/chrome/browser/xr/scenecore/XrModuleProviderImpl.java +++ b/chrome/android/modules/xr/internal/java/src/org/chromium/chrome/browser/xr/scenecore/XrModuleProviderImpl.java
@@ -9,8 +9,10 @@ import androidx.annotation.RequiresApi; +import org.chromium.base.UnguessableToken; import org.chromium.build.annotations.NullMarked; import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; +import org.chromium.chrome.browser.media.immersive_playback.ImmersiveVideoPlaybackActivity; import org.chromium.ui.xr.scenecore.XrSceneCoreSessionInitializer; import org.chromium.ui.xr.scenecore.XrSceneCoreSessionManager; @@ -32,4 +34,10 @@ ActivityLifecycleDispatcher dispatcher, XrSceneCoreSessionManager manager) { return new XrSceneCoreSessionInitializerImpl(dispatcher, manager); } + + @Override + public void createImmersiveVideoPlaybackActivity( + UnguessableToken nativeToken, Object initiatorTab) { + ImmersiveVideoPlaybackActivity.createActivity(nativeToken, initiatorTab); + } }
diff --git a/chrome/android/modules/xr/internal/javatests/src/org/chromium/chrome/browser/media/immersive_playback/ImmersiveVideoPlaybackActivityTest.java b/chrome/android/modules/xr/internal/javatests/src/org/chromium/chrome/browser/media/immersive_playback/ImmersiveVideoPlaybackActivityTest.java new file mode 100644 index 0000000..ef0bb4d --- /dev/null +++ b/chrome/android/modules/xr/internal/javatests/src/org/chromium/chrome/browser/media/immersive_playback/ImmersiveVideoPlaybackActivityTest.java
@@ -0,0 +1,291 @@ +// 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.media.immersive_playback; + +import static org.junit.Assume.assumeTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; + +import androidx.test.filters.MediumTest; +import androidx.test.platform.app.InstrumentationRegistry; + +import org.hamcrest.Matchers; +import org.junit.Assert; +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.ContextUtils; +import org.chromium.base.DeviceInfo; +import org.chromium.base.ThreadUtils; +import org.chromium.base.UnguessableToken; +import org.chromium.base.test.util.Batch; +import org.chromium.base.test.util.CommandLineFlags; +import org.chromium.base.test.util.Criteria; +import org.chromium.base.test.util.CriteriaHelper; +import org.chromium.chrome.browser.flags.ChromeSwitches; +import org.chromium.chrome.browser.media.VideoOverlayActivity; +import org.chromium.chrome.browser.media.VideoOverlayActivityJni; +import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; +import org.chromium.chrome.test.transit.ChromeTransitTestRules; +import org.chromium.chrome.test.transit.FreshCtaTransitTestRule; +import org.chromium.chrome.test.util.ActivityTestUtils; +import org.chromium.content_public.browser.overlay_window.PlaybackState; +import org.chromium.ui.xr.scenecore.XrSurfaceEntityShape; +import org.chromium.ui.xr.scenecore.XrSurfaceEntityStereoMode; + +import java.util.concurrent.Callable; +import java.util.concurrent.TimeoutException; + +/** Tests for ImmersiveVideoPlaybackActivity. */ +@RunWith(ChromeJUnit4ClassRunner.class) +@Batch(Batch.PER_CLASS) +@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) +public class ImmersiveVideoPlaybackActivityTest { + @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule(); + + private static final String NATIVE_TOKEN_KEY = + "org.chromium.chrome.browser.media.VideoOverlayActivity.NativeToken"; + private static final String WEB_CONTENTS_KEY = + "org.chromium.chrome.browser.media.VideoOverlayActivity.WebContents"; + + @Rule + public FreshCtaTransitTestRule mActivityTestRule = + ChromeTransitTestRules.freshChromeTabbedActivityRule(); + + private static final long NATIVE_OVERLAY = 100L; + private static final long TIMEOUT_MILLISECONDS = 10000L; + private static final long DURATION_MS = 1000L; + private static final long POSITION_MS = 500L; + private static final float PLAYBACK_RATE = 1.0f; + private static final int VIDEO_WIDTH = 640; + private static final int VIDEO_HEIGHT = 360; + private static final @XrSurfaceEntityStereoMode int STEREO_MODE = + XrSurfaceEntityStereoMode.MONO; + private static final @XrSurfaceEntityShape int SURFACE_ENTITY_SHAPE = XrSurfaceEntityShape.QUAD; + + private final UnguessableToken mNativeWindowToken = UnguessableToken.createForTesting(); + + @Mock private VideoOverlayActivity.Natives mNativeMock; + @Mock private ImmersiveVideoPlaybackCoordinator mCoordinatorMock; + + private Tab mTab; + private boolean mIsRealXr; + + @Before + public void setUp() { + mIsRealXr = DeviceInfo.isXr(); + mActivityTestRule.startOnBlankPage(); + mTab = mActivityTestRule.getActivityTab(); + VideoOverlayActivityJni.setInstanceForTesting(mNativeMock); + when(mNativeMock.onActivityStart(eq(mNativeWindowToken), any(), any())) + .thenReturn(NATIVE_OVERLAY); + DeviceInfo.setIsXrForTesting(true); + + ImmersiveVideoPlaybackActivity.setPlaybackCoordinatorForTesting(mCoordinatorMock); + } + + /** Tests that the real activity starts successfully on a device with actual XR capabilities. */ + @Test + @MediumTest + public void testStartActivityReal() throws Throwable { + assumeTrue(mIsRealXr); + ImmersiveVideoPlaybackActivity.setPlaybackCoordinatorForTesting(null); + ImmersiveVideoPlaybackActivity activity = startImmersiveVideoPlaybackActivity(); + Assert.assertNotNull(activity); + testExitOn(activity, () -> activity.close()); + } + + /** Tests that the activity starts successfully when using the mocked coordinator. */ + @Test + @MediumTest + public void testStartActivityMock() throws Throwable { + ImmersiveVideoPlaybackActivity activity = startImmersiveVideoPlaybackActivity(); + Assert.assertNotNull(activity); + testExitOn(activity, () -> activity.close()); + } + + /** + * Tests that the activity handles non-XR devices correctly by bypassing initialization and + * self-terminating. + */ + @Test + @MediumTest + public void testStartActivityNonXr() throws Throwable { + DeviceInfo.setIsXrForTesting(false); + ImmersiveVideoPlaybackActivity activity = launchImmersiveVideoPlaybackActivity(); + verify(mNativeMock, never()).onActivityStart(any(), any(), any()); + CriteriaHelper.pollUiThread( + () -> Criteria.checkThat(activity.isDestroyed(), Matchers.is(true))); + } + + @Test + @MediumTest + public void testPendingStateDoesNotCrash() throws Throwable { + ThreadUtils.runOnUiThreadBlocking( + () -> { + ImmersiveVideoPlaybackActivity activity = new ImmersiveVideoPlaybackActivity(); + activity.setPlaybackState(PlaybackState.PLAYING); + activity.updateVideoSize(VIDEO_WIDTH, VIDEO_HEIGHT); + activity.setImmersiveVideoOptions(STEREO_MODE, SURFACE_ENTITY_SHAPE); + activity.setMediaPosition(DURATION_MS, POSITION_MS, PLAYBACK_RATE); + + ImmersiveVideoPlaybackActivity.PendingState pendingState = + activity.getPendingStateForTesting(); + Assert.assertEquals( + "Playback state mismatch", + PlaybackState.PLAYING, + pendingState.mPlaybackState.intValue()); + Assert.assertEquals( + "Video width mismatch", + VIDEO_WIDTH, + pendingState.mVideoWidth.intValue()); + Assert.assertEquals( + "Video height mismatch", + VIDEO_HEIGHT, + pendingState.mVideoHeight.intValue()); + Assert.assertEquals( + "Stereo mode mismatch", + STEREO_MODE, + pendingState.mStereoMode.intValue()); + Assert.assertEquals( + "Surface entity shape mismatch", + SURFACE_ENTITY_SHAPE, + pendingState.mShape.intValue()); + Assert.assertEquals( + "Duration mismatch", DURATION_MS, pendingState.mDurationMs.longValue()); + Assert.assertEquals( + "Position mismatch", POSITION_MS, pendingState.mPositionMs.longValue()); + Assert.assertEquals( + "Playback rate mismatch", + PLAYBACK_RATE, + pendingState.mPlaybackRate.floatValue(), + 0.0f); + }); + } + + /** Tests that setImmersiveVideoOptions correctly forwards calls to the mocked coordinator. */ + @Test + @MediumTest + public void testSetImmersiveVideoOptionsForwardsToCoordinatorMock() throws Throwable { + ImmersiveVideoPlaybackActivity activity = startImmersiveVideoPlaybackActivity(); + + activity.setImmersiveVideoOptions(STEREO_MODE, SURFACE_ENTITY_SHAPE); + verify(mCoordinatorMock).updateVideoLayout(STEREO_MODE, SURFACE_ENTITY_SHAPE); + + testExitOn(activity, () -> activity.close()); + } + + /** Tests that setMediaPosition correctly forwards calls to the mocked coordinator. */ + @Test + @MediumTest + public void testSetMediaPositionForwardsToCoordinatorMock() throws Throwable { + ImmersiveVideoPlaybackActivity activity = startImmersiveVideoPlaybackActivity(); + + activity.setMediaPosition(DURATION_MS, POSITION_MS, PLAYBACK_RATE); + verify(mCoordinatorMock).updateMediaPosition(DURATION_MS, POSITION_MS, PLAYBACK_RATE); + + testExitOn(activity, () -> activity.close()); + } + + /** Tests that setPlaybackState correctly forwards calls to the mocked coordinator. */ + @Test + @MediumTest + public void testSetPlaybackStateForwardsToCoordinatorMock() throws Throwable { + ImmersiveVideoPlaybackActivity activity = startImmersiveVideoPlaybackActivity(); + + activity.setPlaybackState(PlaybackState.PLAYING); + verify(mCoordinatorMock).updatePlaybackState(true); + + activity.setPlaybackState(PlaybackState.PAUSED); + verify(mCoordinatorMock).updatePlaybackState(false); + + testExitOn(activity, () -> activity.close()); + } + + /** Tests that updateVideoSize correctly forwards calls to the mocked coordinator. */ + @Test + @MediumTest + public void testUpdateVideoSizeForwardsToCoordinatorMock() throws Throwable { + ImmersiveVideoPlaybackActivity activity = startImmersiveVideoPlaybackActivity(); + + activity.updateVideoSize(VIDEO_WIDTH, VIDEO_HEIGHT); + verify(mCoordinatorMock).updatePlayerSize(VIDEO_WIDTH, VIDEO_HEIGHT); + + testExitOn(activity, () -> activity.close()); + } + + private ImmersiveVideoPlaybackActivity launchImmersiveVideoPlaybackActivity() throws Exception { + ImmersiveVideoPlaybackActivity activity = + ActivityTestUtils.launchActivityWithTimeout( + InstrumentationRegistry.getInstrumentation(), + ImmersiveVideoPlaybackActivity.class, + new Callable<>() { + @Override + public Void call() throws TimeoutException { + ThreadUtils.runOnUiThreadBlocking( + () -> { + Context context = ContextUtils.getApplicationContext(); + var window = mTab.getWindowAndroid(); + if (window != null) { + context = window.getActivity().get(); + } + Intent intent = + new Intent( + context, + ImmersiveVideoPlaybackActivity.class); + intent.putExtra(NATIVE_TOKEN_KEY, mNativeWindowToken); + intent.putExtra( + WEB_CONTENTS_KEY, mTab.getWebContents()); + context.startActivity(intent); + }); + return null; + } + }, + TIMEOUT_MILLISECONDS); + + return activity; + } + + private ImmersiveVideoPlaybackActivity startImmersiveVideoPlaybackActivity() throws Exception { + ImmersiveVideoPlaybackActivity activity = launchImmersiveVideoPlaybackActivity(); + ActivityTestUtils.waitForFirstLayout(activity); + + CriteriaHelper.pollUiThread( + () -> { + Criteria.checkThat(activity.isNativeHandleInitialized(), Matchers.is(true)); + Criteria.checkThat( + activity.isCoordinatorInitializedForTesting(), Matchers.is(true)); + }, + TIMEOUT_MILLISECONDS, + CriteriaHelper.DEFAULT_POLLING_INTERVAL); + + return activity; + } + + private void testExitOn(Activity activity, Runnable runnable) throws Throwable { + ThreadUtils.runOnUiThreadBlocking(() -> runnable.run()); + + CriteriaHelper.pollUiThread( + () -> { + Criteria.checkThat( + activity == null || activity.isDestroyed(), Matchers.is(true)); + }, + TIMEOUT_MILLISECONDS, + CriteriaHelper.DEFAULT_POLLING_INTERVAL); + } +}
diff --git a/chrome/android/modules/xr/internal/javatests/src/org/chromium/chrome/browser/media/immersive_playback/ImmersiveVideoPlaybackCoordinatorTest.java b/chrome/android/modules/xr/internal/javatests/src/org/chromium/chrome/browser/media/immersive_playback/ImmersiveVideoPlaybackCoordinatorTest.java new file mode 100644 index 0000000..67085325 --- /dev/null +++ b/chrome/android/modules/xr/internal/javatests/src/org/chromium/chrome/browser/media/immersive_playback/ImmersiveVideoPlaybackCoordinatorTest.java
@@ -0,0 +1,459 @@ +// 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.media.immersive_playback; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.Activity; +import android.util.Size; +import android.util.SizeF; +import android.view.Surface; +import android.widget.SeekBar; + +import androidx.test.annotation.UiThreadTest; +import androidx.test.filters.SmallTest; + +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.ClassRule; +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.ThreadUtils; +import org.chromium.base.test.BaseActivityTestRule; +import org.chromium.base.test.util.Batch; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; +import org.chromium.components.thinwebview.CompositorView; +import org.chromium.ui.base.WindowAndroid; +import org.chromium.ui.test.util.BlankUiTestActivity; +import org.chromium.ui.xr.scenecore.XrCurvedSurfaceEntityHolder; +import org.chromium.ui.xr.scenecore.XrMovableComponent; +import org.chromium.ui.xr.scenecore.XrPanelEntityHolder; +import org.chromium.ui.xr.scenecore.XrQuadSurfaceEntityHolder; +import org.chromium.ui.xr.scenecore.XrResizableComponent; +import org.chromium.ui.xr.scenecore.XrSceneCoreSessionManager; +import org.chromium.ui.xr.scenecore.XrSurfaceEntityShape; +import org.chromium.ui.xr.scenecore.XrSurfaceEntityStereoMode; +import org.chromium.ui.xr.scenecore.XrSurfaceEntityView; + +/** Tests for {@link ImmersiveVideoPlaybackCoordinator}. */ +@RunWith(ChromeJUnit4ClassRunner.class) +@Batch(Batch.UNIT_TESTS) +public class ImmersiveVideoPlaybackCoordinatorTest { + @ClassRule + public static final BaseActivityTestRule<BlankUiTestActivity> sActivityTestRule = + new BaseActivityTestRule<>(BlankUiTestActivity.class); + + @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule(); + + @Mock private ImmersiveVideoControlDelegate mVideoControlDelegate; + @Mock private WindowAndroid mWindowAndroid; + @Mock private XrSceneCoreSessionManager mXrSceneCoreSessionManager; + @Mock private CompositorView mCompositorView; + @Mock private XrMovableComponent mControlPanelMovableComponent; + @Mock private XrSurfaceEntityView mSurfaceEntityView; + @Mock private XrResizableComponent mResizableComponent; + @Mock private XrMovableComponent mSurfaceMovableComponent; + private FakeSurfaceHolder mSurfaceEntityHolder; + private FakePanelEntityHolder mMainPanelEntity; + private FakePanelEntityHolder mControlPanelHolder; + private ImmersiveVideoPlaybackCoordinator mCoordinator; + private static Activity sActivity; + + @BeforeClass + public static void setupSuite() { + sActivity = sActivityTestRule.launchActivity(null); + } + + @Before + public void setUp() throws Exception { + mSurfaceEntityHolder = new FakeSurfaceHolder(mSurfaceMovableComponent, mResizableComponent); + mMainPanelEntity = new FakePanelEntityHolder(null); + mControlPanelHolder = new FakePanelEntityHolder(mControlPanelMovableComponent); + + when(mXrSceneCoreSessionManager.getMainPanelEntity()).thenReturn(mMainPanelEntity); + when(mXrSceneCoreSessionManager.createPanelEntity(any(), any())) + .thenReturn(mControlPanelHolder); + when(mCompositorView.getView()).thenReturn(mSurfaceEntityView); + when(mSurfaceEntityView.getHolder()).thenReturn(mSurfaceEntityHolder); + + ThreadUtils.runOnUiThreadBlocking( + () -> { + mCoordinator = + new TestImmersiveVideoPlaybackCoordinator( + sActivity, + mWindowAndroid, + mVideoControlDelegate, + mXrSceneCoreSessionManager, + mCompositorView); + + mCoordinator.createXrCompositorView( + XrSurfaceEntityStereoMode.MONO, XrSurfaceEntityShape.QUAD); + }); + } + + /** Tests that updateMediaPosition correctly updates the seek bar. */ + @Test + @SmallTest + @UiThreadTest + public void testUpdateMediaPosition() { + // When playback is paused, updateMediaPosition should update the seek bar + // immediately, otherwise it should update the seek bar asynchronously every + // 500ms. + + int durationSeconds = 10; + int positionSeconds = 5; + + mCoordinator.updateMediaPosition( + /* durationMs= */ durationSeconds * 1000, + /* positionMs= */ positionSeconds * 1000, + /* playbackRate= */ 0.0f); + + ImmersiveVideoControlPanel panel = mCoordinator.getControlPanelForTesting(); + SeekBar seekBar = panel.getSeekBarForTesting(); + assertEquals(durationSeconds, seekBar.getMax()); + assertEquals(positionSeconds, seekBar.getProgress()); + } + + /** Tests that updatePlaybackState correctly updates the playback state in the panel. */ + @Test + @SmallTest + @UiThreadTest + public void testUpdatePlaybackState() { + ImmersiveVideoControlPanel panel = mCoordinator.getControlPanelForTesting(); + + mCoordinator.updatePlaybackState(true); + assertTrue(panel.isPlayingForTesting()); + + mCoordinator.updatePlaybackState(false); + assertFalse(panel.isPlayingForTesting()); + } + + /** Tests that updatePlayerSize forwards the call to the surface holder. */ + @Test + @SmallTest + @UiThreadTest + public void testUpdatePlayerSize() { + int width = 1920; + int height = 1080; + + mCoordinator.updatePlayerSize(width, height); + + assertEquals(width, mSurfaceEntityHolder.lastWidth); + assertEquals(height, mSurfaceEntityHolder.lastHeight); + } + + /** Tests that updateVideoLayout updates shape and stereo mode. */ + @Test + @SmallTest + @UiThreadTest + public void testUpdateVideoLayout() { + clearInvocations(mSurfaceMovableComponent); + clearInvocations(mControlPanelHolder.getMovableComponent()); + + // Switch to HEMISPHERE and SIDE_BY_SIDE. + mCoordinator.updateVideoLayout( + XrSurfaceEntityStereoMode.SIDE_BY_SIDE, XrSurfaceEntityShape.HEMISPHERE); + + assertEquals(XrSurfaceEntityShape.HEMISPHERE, mSurfaceEntityHolder.lastShape); + assertEquals(XrSurfaceEntityStereoMode.SIDE_BY_SIDE, mSurfaceEntityHolder.lastStereoMode); + + verify(mSurfaceMovableComponent).setMovable(false, false); + verify(mControlPanelHolder.getMovableComponent()).setMovable(true, false); + + clearInvocations(mSurfaceMovableComponent); + clearInvocations(mControlPanelHolder.getMovableComponent()); + + // Switch to SPHERE and TOP_BOTTOM. + mCoordinator.updateVideoLayout( + XrSurfaceEntityStereoMode.TOP_BOTTOM, XrSurfaceEntityShape.SPHERE); + + assertEquals(XrSurfaceEntityShape.SPHERE, mSurfaceEntityHolder.lastShape); + assertEquals(XrSurfaceEntityStereoMode.TOP_BOTTOM, mSurfaceEntityHolder.lastStereoMode); + + verify(mSurfaceMovableComponent).setMovable(false, false); + verify(mControlPanelHolder.getMovableComponent()).setMovable(true, false); + + clearInvocations(mSurfaceMovableComponent); + clearInvocations(mControlPanelHolder.getMovableComponent()); + + // Switch to QUAD and MONO (default state). + mCoordinator.updateVideoLayout(XrSurfaceEntityStereoMode.MONO, XrSurfaceEntityShape.QUAD); + + assertEquals(XrSurfaceEntityShape.QUAD, mSurfaceEntityHolder.lastShape); + assertEquals(XrSurfaceEntityStereoMode.MONO, mSurfaceEntityHolder.lastStereoMode); + + verify(mSurfaceMovableComponent).setMovable(true, false); + verify(mControlPanelHolder.getMovableComponent()).setMovable(false, false); + } + + /** Test subclass that allows injecting mocked dependencies by overriding protected methods. */ + private static class TestImmersiveVideoPlaybackCoordinator + extends ImmersiveVideoPlaybackCoordinator { + private final XrSceneCoreSessionManager mMockManager; + private final CompositorView mMockCompositorView; + + public TestImmersiveVideoPlaybackCoordinator( + Activity activity, + WindowAndroid windowAndroid, + ImmersiveVideoControlDelegate videoControlDelegate, + XrSceneCoreSessionManager mockManager, + CompositorView mockCompositorView) { + super(activity, windowAndroid, videoControlDelegate); + mMockManager = mockManager; + mMockCompositorView = mockCompositorView; + } + + @Override + protected XrSceneCoreSessionManager createXrSceneCoreSessionManager() { + return mMockManager; + } + + @Override + protected CompositorView createCompositorView(int shape) { + return mMockCompositorView; + } + } + + /** + * Fake implementation of XrQuadSurfaceEntityHolder and XrCurvedSurfaceEntityHolder that wraps + * an XrSurfaceEntityHolder and provides fake implementations for the additional methods + * required by these interfaces. + */ + private static class FakeSurfaceHolder + implements XrQuadSurfaceEntityHolder, XrCurvedSurfaceEntityHolder { + private final XrMovableComponent mMovableComponent; + private final XrResizableComponent mResizableComponent; + + // State variables for verification + public int lastShape = -1; + public int lastStereoMode = -1; + public int lastWidth = -1; + public int lastHeight = -1; + public float lastRadius = -1f; + + public FakeSurfaceHolder( + XrMovableComponent movableComponent, XrResizableComponent resizableComponent) { + mMovableComponent = movableComponent; + mResizableComponent = resizableComponent; + } + + @Override + public void setEntityRadius(float radius) { + lastRadius = radius; + } + + @Override + public float getEntityRadius() { + return lastRadius; + } + + @Override + public XrMovableComponent getMovableComponent() { + return mMovableComponent; + } + + @Override + public XrResizableComponent getResizableComponent() { + return mResizableComponent; + } + + @Override + public SizeF getEntitySize() { + return new SizeF(1f, 1f); + } + + @Override + public void setEntitySize(float width, float height) {} + + @Override + public void addCallback(Callback callback) {} + + @Override + public void removeCallback(Callback callback) {} + + @Override + public Surface getSurface() { + return null; + } + + @Override + public int getSurfaceStereoMode() { + return lastStereoMode; + } + + @Override + public void setSurfaceStereoMode(int stereoMode) { + lastStereoMode = stereoMode; + } + + @Override + public int getSurfaceShape() { + return lastShape; + } + + @Override + public void setSurfaceShape(int shape) { + lastShape = shape; + } + + @Override + public void setSurfacePixelDimensions(int width, int height) { + lastWidth = width; + lastHeight = height; + } + + @Override + public Object getEntity() { + return null; + } + + @Override + public void setEntityPose(float[] translation) {} + + @Override + public void setEntityPose(float[] translation, float[] rotation) {} + + @Override + public float[] getEntityTranslation() { + return null; + } + + @Override + public float[] getEntityRotation() { + return null; + } + + @Override + public void setEntityScale(float scale) {} + + @Override + public float getEntityScale() { + return 1f; + } + + @Override + public void setEntityAlpha(float alpha) {} + + @Override + public float getEntityAlpha() { + return 1f; + } + + @Override + public void setEntityEnabled(boolean enabled) {} + + @Override + public boolean isEntityEnabled() { + return true; + } + + @Override + public void dispose() {} + } + + private static class FakePanelEntityHolder implements XrPanelEntityHolder { + private final XrMovableComponent mMovableComponent; + public boolean isEnabled = true; + + public FakePanelEntityHolder(XrMovableComponent movableComponent) { + mMovableComponent = movableComponent; + } + + @Override + public void setEntityEnabled(boolean enabled) { + isEnabled = enabled; + } + + @Override + public boolean isEntityEnabled() { + return isEnabled; + } + + @Override + public XrMovableComponent getMovableComponent() { + return mMovableComponent; + } + + @Override + public void setEntitySizeInPixels(int w, int h) {} + + @Override + public Size getEntitySizeInPixels() { + return null; + } + + @Override + public void setEntityCornerRadius(float r) {} + + @Override + public float getEntityCornerRadius() { + return 0f; + } + + @Override + public Object getEntity() { + return null; + } + + @Override + public void setEntityPose(float[] t) {} + + @Override + public void setEntityPose(float[] t, float[] r) {} + + @Override + public float[] getEntityTranslation() { + return null; + } + + @Override + public float[] getEntityRotation() { + return null; + } + + @Override + public void setEntityScale(float scale) {} + + @Override + public float getEntityScale() { + return 1f; + } + + @Override + public void setEntityAlpha(float alpha) {} + + @Override + public float getEntityAlpha() { + return 1f; + } + + @Override + public void dispose() {} + + @Override + public XrResizableComponent getResizableComponent() { + return null; + } + + @Override + public SizeF getEntitySize() { + return null; + } + + @Override + public void setEntitySize(float w, float h) {} + } +}
diff --git a/chrome/app/chromium_strings.grd b/chrome/app/chromium_strings.grd index d881687..7f04bc0 100644 --- a/chrome/app/chromium_strings.grd +++ b/chrome/app/chromium_strings.grd
@@ -3274,7 +3274,7 @@ <!-- JS optimizations bubble --> <message name="IDS_JS_OPTIMIZATION_BUBBLE_BODY_NON_POLICY_BODY" desc="Body text for the JavaScript optimization bubble when disabled for other reasons."> - Chromium turns off JavaScript optimization when you visit a site for the first time.
 + For security, Chromium turns off JavaScript optimization when you visit a site for the first time.
 If this page isn’t working as expected, try allowing optimization. </message> </messages>
diff --git a/chrome/app/chromium_strings_grd/IDS_JS_OPTIMIZATION_BUBBLE_BODY_NON_POLICY_BODY.png.sha1 b/chrome/app/chromium_strings_grd/IDS_JS_OPTIMIZATION_BUBBLE_BODY_NON_POLICY_BODY.png.sha1 index 03ad2d3..991b43da 100644 --- a/chrome/app/chromium_strings_grd/IDS_JS_OPTIMIZATION_BUBBLE_BODY_NON_POLICY_BODY.png.sha1 +++ b/chrome/app/chromium_strings_grd/IDS_JS_OPTIMIZATION_BUBBLE_BODY_NON_POLICY_BODY.png.sha1
@@ -1 +1 @@ -25314d11521db9457db006659879b4ca4fd3150f \ No newline at end of file +d392960c12ae63472aa5b6c2f52450b2983ea089 \ No newline at end of file
diff --git a/chrome/app/google_chrome_strings.grd b/chrome/app/google_chrome_strings.grd index ed7a863..24d9ca57e 100644 --- a/chrome/app/google_chrome_strings.grd +++ b/chrome/app/google_chrome_strings.grd
@@ -3291,7 +3291,7 @@ <!-- JS optimizations bubble --> <message name="IDS_JS_OPTIMIZATION_BUBBLE_BODY_NON_POLICY_BODY" desc="Body text for the JavaScript optimization bubble when disabled for other reasons."> - Chrome turns off JavaScript optimization when you visit a site for the first time.
 + For security, Chrome turns off JavaScript optimization when you visit a site for the first time.
 If this page isn’t working as expected, try allowing optimization. </message> </messages>
diff --git a/chrome/app/google_chrome_strings_grd/IDS_JS_OPTIMIZATION_BUBBLE_BODY_NON_POLICY_BODY.png.sha1 b/chrome/app/google_chrome_strings_grd/IDS_JS_OPTIMIZATION_BUBBLE_BODY_NON_POLICY_BODY.png.sha1 index 3f022ef..18a5c76 100644 --- a/chrome/app/google_chrome_strings_grd/IDS_JS_OPTIMIZATION_BUBBLE_BODY_NON_POLICY_BODY.png.sha1 +++ b/chrome/app/google_chrome_strings_grd/IDS_JS_OPTIMIZATION_BUBBLE_BODY_NON_POLICY_BODY.png.sha1
@@ -1 +1 @@ -1f617b35cae2e82d7ceb7e7287f33c63f6e700ba \ No newline at end of file +e57517bcea9f65d08d9239593277e8ac2087d38d \ No newline at end of file
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 7bd6f23..699168e 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -11205,12 +11205,6 @@ FEATURE_VALUE_TYPE(chrome::android::kScheduleWindowCleaning)}, #endif // BUILDFLAG(IS_ANDROID) -#if !BUILDFLAG(IS_ANDROID) - {"open-dragged-links-same-tab", - flag_descriptions::kOpenDraggedLinksSameTabName, - flag_descriptions::kOpenDraggedLinksSameTabDescription, kOsDesktop, - FEATURE_VALUE_TYPE(blink::features::kSupportOpeningDraggedLinksInSameTab)}, -#endif #if BUILDFLAG(IS_ANDROID) {"android-use-display-topology", @@ -11728,13 +11722,6 @@ "LensOverlayTextSelectionContextMenuEntrypoint")}, #endif // !BUILDFLAG(IS_ANDROID), -#if BUILDFLAG(IS_ANDROID) - {"web-serial-wired-devices-android", - flag_descriptions::kWebSerialWiredDevicesAndroidName, - flag_descriptions::kWebSerialWiredDevicesAndroidDescription, kOsAndroid, - FEATURE_VALUE_TYPE(device::features::kWebSerialWiredDevicesAndroid)}, -#endif // BUILDFLAG(IS_ANDROID) - #if !BUILDFLAG(IS_ANDROID) {"tab-group-more-entry-points", flag_descriptions::kTabGroupMenuMoreEntryPointsName,
diff --git a/chrome/browser/actor/ui/actor_ui_tab_controller_unittest.cc b/chrome/browser/actor/ui/actor_ui_tab_controller_unittest.cc index 5f99d2d0..4e0d6b021 100644 --- a/chrome/browser/actor/ui/actor_ui_tab_controller_unittest.cc +++ b/chrome/browser/actor/ui/actor_ui_tab_controller_unittest.cc
@@ -505,7 +505,14 @@ ActorUiTabControllerError::kRequestedForNonExistentTab, 1); } -TEST_F(ActorUiTabControllerTest, RegisterNullCallbackDeathTest) { +// TODO(crbug.com/489697430): Test times out flakily under Asan and UBSan. +#if defined(ADDRESS_SANITIZER) || defined(UNDEFINED_SANITIZER) +#define MAYBE_RegisterNullCallbackDeathTest \ + DISABLED_RegisterNullCallbackDeathTest +#else +#define MAYBE_RegisterNullCallbackDeathTest RegisterNullCallbackDeathTest +#endif +TEST_F(ActorUiTabControllerTest, MAYBE_RegisterNullCallbackDeathTest) { EXPECT_DEATH_IF_SUPPORTED( (void)tab_controller()->RegisterActorOverlayStateChange( ActorUiTabControllerInterface::ActorOverlayStateChangeCallback()), @@ -522,7 +529,16 @@ ""); } -TEST_F(ActorUiTabControllerTest, RegisterCallbackWhileRegisteredDeathTest) { +// TODO(crbug.com/489701578): Test times out flakily under Asan and UBSan. +#if defined(ADDRESS_SANITIZER) || defined(UNDEFINED_SANITIZER) +#define MAYBE_RegisterCallbackWhileRegisteredDeathTest \ + DISABLED_RegisterCallbackWhileRegisteredDeathTest +#else +#define MAYBE_RegisterCallbackWhileRegisteredDeathTest \ + RegisterCallbackWhileRegisteredDeathTest +#endif +TEST_F(ActorUiTabControllerTest, + MAYBE_RegisterCallbackWhileRegisteredDeathTest) { auto valid_overlay_state_cb = base::BindRepeating([](bool, ActorOverlayState, base::OnceClosure) {}); auto valid_overlay_bg_cb = base::BindRepeating([](bool) {});
diff --git a/chrome/browser/ai/ai_manager.cc b/chrome/browser/ai/ai_manager.cc index 0cbb1b2..e6e5b6c4 100644 --- a/chrome/browser/ai/ai_manager.cc +++ b/chrome/browser/ai/ai_manager.cc
@@ -108,6 +108,9 @@ const char kExperimentalLanguageWarning[] = "The specified languages are experimental in %s API and output quality " "cannot be guaranteed. The supported language codes are: [%s]"; +const char kSpeedPreferenceMarkdownWarning[] = + "The 'speed' performance preference utilizes a model with limited support " + "for 'markdown' format."; constexpr char kModelVersionParam[] = "model_version"; // Feature flag for enabling foundational models in the AI API, requires the @@ -472,9 +475,9 @@ // Checks if the provided options satisfy the requirements for the 'speed' // performance preference: -// 1. Languages must be supported for speed preference. 2. Format must be plain -// text. 3. Type must be TLDR or KeyPoints. 4. Length must be short or medium. -// 5. `shared_context` must not be specified. +// 1. Languages must be supported for speed preference. +// 2. Type must be TLDR or KeyPoints. 3. Length must be short or medium. +// 4. `shared_context` must not be specified. // TODO(crbug.com/508631503): In the long term, model configs should express // the subset of supported options, and this matching code should be more // generalized. @@ -483,7 +486,6 @@ kInputLanguageNotSupported, kContextLanguageNotSupported, kSharedContextNotSupported, - kFormatNotSupported, kTypeNotSupported, kLengthNotSupported, kManifestBrokerDisabled, @@ -528,11 +530,6 @@ SpeedPreferenceIncompatibilityReason::kSharedContextNotSupported); } - if (options->format != blink::mojom::AISummarizerFormat::kPlainText) { - return base::unexpected( - SpeedPreferenceIncompatibilityReason::kFormatNotSupported); - } - if (options->type != blink::mojom::AISummarizerType::kTLDR && options->type != blink::mojom::AISummarizerType::kKeyPoints) { return base::unexpected( @@ -880,6 +877,9 @@ kUnavailableIncompatiblePreferenceOptions); return; } + if (options->format == blink::mojom::AISummarizerFormat::kMarkDown) { + MaybeLogSpeedPreferenceMarkdownWarning(); + } } if (base::FeatureList::IsEnabled( @@ -935,6 +935,9 @@ kIncompatiblePreferenceOptions); return; } + if (options->format == blink::mojom::AISummarizerFormat::kMarkDown) { + MaybeLogSpeedPreferenceMarkdownWarning(); + } } if (!model_broker_client_) { @@ -1722,3 +1725,13 @@ blink::mojom::ConsoleMessageLevel::kWarning, base::StringPrintf(kExperimentalLanguageWarning, api_name, list)); } + +void AIManager::MaybeLogSpeedPreferenceMarkdownWarning() { + auto* rfh = rfh_.AsRenderFrameHostIfValid(); + if (!rfh || did_log_speed_preference_markdown_warning_) { + return; + } + did_log_speed_preference_markdown_warning_ = true; + rfh->AddMessageToConsole(blink::mojom::ConsoleMessageLevel::kWarning, + kSpeedPreferenceMarkdownWarning); +}
diff --git a/chrome/browser/ai/ai_manager.h b/chrome/browser/ai/ai_manager.h index f7df3f3c..02be00b3 100644 --- a/chrome/browser/ai/ai_manager.h +++ b/chrome/browser/ai/ai_manager.h
@@ -234,6 +234,7 @@ void MaybeLogExperimentalLanguageWarning( const std::string_view api_name, const base::flat_set<std::string>& default_supported_languages); + void MaybeLogSpeedPreferenceMarkdownWarning(); // |model_broker_client_| is keeping |CanCreateLanguageModel| callbacks alive // until it is destroyed, so we need to ensure those callbacks are safely @@ -255,6 +256,7 @@ bool did_log_missing_output_language_warning_ = false; bool did_log_unsupported_language_error_ = false; bool did_log_experimental_language_warning_ = false; + bool did_log_speed_preference_markdown_warning_ = false; // Features that have attempted initialization in this session. base::flat_set<optimization_guide::mojom::OnDeviceFeature> tried_init_;
diff --git a/chrome/browser/ai/ai_summarizer_unittest.cc b/chrome/browser/ai/ai_summarizer_unittest.cc index e2890ec..b0afc37 100644 --- a/chrome/browser/ai/ai_summarizer_unittest.cc +++ b/chrome/browser/ai/ai_summarizer_unittest.cc
@@ -98,9 +98,9 @@ blink::mojom::AISummarizerCreateOptionsPtr GetDefaultOptions() { return blink::mojom::AISummarizerCreateOptions::New( - kSharedContextString, blink::mojom::AISummarizerType::kTLDR, - blink::mojom::AISummarizerFormat::kPlainText, - blink::mojom::AISummarizerLength::kMedium, + /*shared_context=*/"", blink::mojom::AISummarizerType::kKeyPoints, + blink::mojom::AISummarizerFormat::kMarkDown, + blink::mojom::AISummarizerLength::kShort, blink::mojom::PerformancePreference::kAuto, /*expected_input_languages=*/std::vector<AILanguageCodePtr>(), /*expected_context_languages=*/std::vector<AILanguageCodePtr>(), @@ -176,7 +176,7 @@ fake_broker_->settings().set_execute_result({"Result text"}); const auto options = blink::mojom::AISummarizerCreateOptions::New( - kSharedContextString, type, format, length, + /*shared_context=*/"", type, format, length, blink::mojom::PerformancePreference::kAuto, /*expected_input_languages=*/std::vector<AILanguageCodePtr>(), /*expected_context_languages=*/std::vector<AILanguageCodePtr>(), @@ -407,8 +407,10 @@ fake_broker_->UpdateModelAdaptation(fake_asset); TestCreateSummarizerClient create_summarizer_client; + auto options = GetDefaultOptions(); + options->shared_context = kSharedContextString; GetAIManagerRemote()->CreateSummarizer( - create_summarizer_client.BindNewPipeAndPassRemote(), GetDefaultOptions()); + create_summarizer_client.BindNewPipeAndPassRemote(), std::move(options)); CreateSummarizerResult result = create_summarizer_client.result().Take(); EXPECT_FALSE(result.has_value()); @@ -422,8 +424,10 @@ blink::mojom::kWritingAssistanceMaxInputTokenSize + 1); TestCreateSummarizerClient create_summarizer_client; + auto options = GetDefaultOptions(); + options->shared_context = kSharedContextString; GetAIManagerRemote()->CreateSummarizer( - create_summarizer_client.BindNewPipeAndPassRemote(), GetDefaultOptions()); + create_summarizer_client.BindNewPipeAndPassRemote(), std::move(options)); CreateSummarizerResult result = create_summarizer_client.result().Take(); EXPECT_FALSE(result.has_value()); @@ -510,7 +514,9 @@ } TEST_F(AISummarizerTest, MeasureUsage) { - auto summarizer_remote = GetAISummarizerRemote(); + auto options = GetDefaultOptions(); + options->shared_context = kSharedContextString; + auto summarizer_remote = GetAISummarizerRemote(std::move(options)); base::test::TestFuture<std::optional<uint32_t>> measure_future; summarizer_remote->MeasureUsage(kInputString, kContextString, @@ -674,7 +680,9 @@ } TEST_F(AISummarizerTest, CrashRecoveryMeasureInputUsage) { - auto summarizer_remote = GetAISummarizerRemote(); + auto options = GetDefaultOptions(); + options->shared_context = kSharedContextString; + auto summarizer_remote = GetAISummarizerRemote(std::move(options)); fake_broker_->CrashService(); base::test::TestFuture<std::optional<uint32_t>> measure_future; @@ -770,8 +778,10 @@ fake_broker_->settings().set_execute_result({"TLDR: Result text"}); + auto options = GetDefaultOptions(); + options->type = blink::mojom::AISummarizerType::kTLDR; mojo::Remote<blink::mojom::AISummarizer> summarizer_remote = - GetAISummarizerRemote(GetDefaultOptions()); + GetAISummarizerRemote(std::move(options)); EXPECT_THAT( Summarize(*summarizer_remote, kInputString, kContextString), @@ -896,7 +906,6 @@ CanCreateAndCreateWithManifestSpeedPreference) { auto options = GetDefaultOptions(); options->preference = blink::mojom::PerformancePreference::kSpeed; - options->shared_context = ""; options->output_language = blink::mojom::AILanguageCode::New("en"); fake_manifest_broker_->client().RequestAssetsFor( @@ -920,7 +929,6 @@ CanCreateSummarizerWithSpeedPreferenceDownloadable) { auto options = GetDefaultOptions(); options->preference = blink::mojom::PerformancePreference::kSpeed; - options->shared_context = ""; options->output_language = blink::mojom::AILanguageCode::New("en"); base::test::TestFuture<blink::mojom::ModelAvailabilityCheckResult> future; @@ -934,7 +942,6 @@ fake_manifest_broker_->client().RequestAssetsFor("summarizer_api"); auto options = GetDefaultOptions(); - options->shared_context = ""; options->output_language = blink::mojom::AILanguageCode::New("en"); base::test::TestFuture<blink::mojom::ModelAvailabilityCheckResult> future; @@ -957,7 +964,6 @@ auto options = GetDefaultOptions(); options->preference = blink::mojom::PerformancePreference::kCapability; - options->shared_context = ""; options->output_language = blink::mojom::AILanguageCode::New("en"); base::test::TestFuture<blink::mojom::ModelAvailabilityCheckResult> future; @@ -981,7 +987,6 @@ auto options = GetDefaultOptions(); options->preference = blink::mojom::PerformancePreference::kSpeed; options->length = blink::mojom::AISummarizerLength::kLong; - options->shared_context = ""; base::MockCallback<AIManager::CanCreateSummarizerCallback> callback; EXPECT_CALL(callback, Run(blink::mojom::ModelAvailabilityCheckResult:: @@ -996,7 +1001,6 @@ auto options = GetDefaultOptions(); options->preference = blink::mojom::PerformancePreference::kSpeed; options->format = blink::mojom::AISummarizerFormat::kMarkDown; - options->shared_context = ""; base::MockCallback<AIManager::CanCreateSummarizerCallback> callback; EXPECT_CALL(callback, Run(blink::mojom::ModelAvailabilityCheckResult:: @@ -1010,7 +1014,6 @@ auto options = GetDefaultOptions(); options->preference = blink::mojom::PerformancePreference::kSpeed; options->type = blink::mojom::AISummarizerType::kTeaser; - options->shared_context = ""; base::MockCallback<AIManager::CanCreateSummarizerCallback> callback; EXPECT_CALL(callback, Run(blink::mojom::ModelAvailabilityCheckResult:: @@ -1025,7 +1028,6 @@ auto options = GetDefaultOptions(); options->preference = blink::mojom::PerformancePreference::kSpeed; options->output_language = blink::mojom::AILanguageCode::New("fr"); - options->shared_context = ""; base::MockCallback<AIManager::CanCreateSummarizerCallback> callback; EXPECT_CALL(callback, Run(blink::mojom::ModelAvailabilityCheckResult:: @@ -1040,7 +1042,6 @@ auto options = GetDefaultOptions(); options->preference = blink::mojom::PerformancePreference::kSpeed; options->expected_input_languages = AITestUtils::ToMojoLanguageCodes({"fr"}); - options->shared_context = ""; base::MockCallback<AIManager::CanCreateSummarizerCallback> callback; EXPECT_CALL(callback, Run(blink::mojom::ModelAvailabilityCheckResult:: @@ -1056,7 +1057,6 @@ options->preference = blink::mojom::PerformancePreference::kSpeed; options->expected_context_languages = AITestUtils::ToMojoLanguageCodes({"fr"}); - options->shared_context = ""; base::MockCallback<AIManager::CanCreateSummarizerCallback> callback; EXPECT_CALL(callback, Run(blink::mojom::ModelAvailabilityCheckResult:: @@ -1088,7 +1088,6 @@ auto options = GetDefaultOptions(); options->preference = blink::mojom::PerformancePreference::kSpeed; - options->shared_context = ""; mojo::test::BadMessageObserver observer; GetAIManagerRemote()->CanCreateSummarizer(std::move(options), @@ -1114,7 +1113,6 @@ auto options = GetDefaultOptions(); options->preference = blink::mojom::PerformancePreference::kSpeed; options->length = blink::mojom::AISummarizerLength::kLong; - options->shared_context = ""; TestCreateSummarizerClient create_summarizer_client; GetAIManagerRemote()->CreateSummarizer( @@ -1130,7 +1128,6 @@ TEST_F(AISummarizerManifestTest, SummarizeWithSpeedPreferenceAndContextFails) { auto options = GetDefaultOptions(); options->preference = blink::mojom::PerformancePreference::kSpeed; - options->shared_context = ""; options->output_language = blink::mojom::AILanguageCode::New("en"); fake_manifest_broker_->client().RequestAssetsFor(
diff --git a/chrome/browser/ash/main_parts/chrome_browser_main_parts_ash.cc b/chrome/browser/ash/main_parts/chrome_browser_main_parts_ash.cc index 750c12b..89cb59af 100644 --- a/chrome/browser/ash/main_parts/chrome_browser_main_parts_ash.cc +++ b/chrome/browser/ash/main_parts/chrome_browser_main_parts_ash.cc
@@ -175,6 +175,7 @@ #include "chrome/browser/global_features.h" #include "chrome/browser/lifetime/application_lifetime.h" #include "chrome/browser/lifetime/termination_notification.h" +#include "chrome/browser/memory/oom_kills_monitor.h" #include "chrome/browser/metrics/chrome_feature_list_creator.h" #include "chrome/browser/metrics/structured/chrome_structured_metrics_delegate.h" #include "chrome/browser/net/chrome_network_delegate.h" @@ -1803,6 +1804,11 @@ // chromeos::PowerManagerClient is destroyed). doze_mode_power_status_scheduler_.reset(); + // Shut down OOMKillsMonitor before local_state() is destroyed in + // ChromeBrowserMainPartsLinux::PostMainMessageLoopRun(). The singleton + // holds a raw_ptr to PrefService that would otherwise dangle. + memory::OOMKillsMonitor::GetInstance().Shutdown(); + // NOTE: Closes ash and destroys `Shell`. ChromeBrowserMainPartsLinux::PostMainMessageLoopRun();
diff --git a/chrome/browser/ash/preferences/preferences.cc b/chrome/browser/ash/preferences/preferences.cc index 6c2482a..e6efacc 100644 --- a/chrome/browser/ash/preferences/preferences.cc +++ b/chrome/browser/ash/preferences/preferences.cc
@@ -1047,8 +1047,6 @@ if (user_is_active) { mouse_settings.SetPrimaryButtonRight(right); } - ReportBooleanPrefApplication(reason, "Mouse.PrimaryButtonRight.Changed", - "Mouse.PrimaryButtonRight.Started", right); // Save owner preference in local state to use on login screen. if (user_is_owner) { if (local_state_->GetBoolean(prefs::kOwnerPrimaryMouseButtonRight) !=
diff --git a/chrome/browser/banners/android/java/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java b/chrome/browser/banners/android/java/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java index cb88def..5d8f2600 100644 --- a/chrome/browser/banners/android/java/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java +++ b/chrome/browser/banners/android/java/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java
@@ -42,6 +42,7 @@ 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.DisableIf; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.Features.DisableFeatures; import org.chromium.chrome.browser.ShortcutHelper; @@ -71,6 +72,7 @@ import org.chromium.content_public.browser.test.util.TouchCommon; import org.chromium.content_public.common.ContentUrlConstants; import org.chromium.net.test.EmbeddedTestServer; +import org.chromium.ui.base.DeviceFormFactor; import org.chromium.ui.modaldialog.ModalDialogProperties; import org.chromium.ui.modaldialog.ModalDialogProperties.ButtonType; import org.chromium.ui.modelutil.PropertyModel; @@ -862,6 +864,7 @@ @Test @MediumTest @Feature({"AppBanners"}) + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testAppBannerDismissedAfterNavigation() throws Exception { String url = WebappTestPage.getTestUrlWithAction(mTestServer, "call_stashed_prompt_on_click");
diff --git a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/bar/BookmarkBarCoordinator.java b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/bar/BookmarkBarCoordinator.java index 79f8668..4527145 100644 --- a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/bar/BookmarkBarCoordinator.java +++ b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/bar/BookmarkBarCoordinator.java
@@ -39,11 +39,11 @@ import org.chromium.chrome.browser.browser_controls.BrowserControlsOffsetTagsInfo; import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider; import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider.ControlsPosition; +import org.chromium.chrome.browser.browser_controls.BrowserControlsUtils; import org.chromium.chrome.browser.browser_controls.TopControlLayer; import org.chromium.chrome.browser.browser_controls.TopControlsStacker; import org.chromium.chrome.browser.browser_controls.TopControlsStacker.TopControlType; import org.chromium.chrome.browser.browser_controls.TopControlsStacker.TopControlVisibility; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.fullscreen.FullscreenManager; import org.chromium.chrome.browser.fullscreen.FullscreenOptions; import org.chromium.chrome.browser.layouts.CompositorModelChangeProcessor; @@ -592,8 +592,9 @@ public void onEnterFullscreen(Tab tab, FullscreenOptions options) { // When fullscreen mode is entered, we need to hide the scene layer and Android widgets. // However, if LockTopControls is enabled, we never remove the bookmark bar. - if (!ChromeFeatureList.sLockTopControlsOnLargeTablets.isEnabled() - && !ChromeFeatureList.sLockTopControlsOnLargeTabletsV2.isEnabled()) { + + boolean isLockTopControlsEnabled = BrowserControlsUtils.doSyncMinHeightWithTotalHeightV2(mContext); + if (!isLockTopControlsEnabled) { mIsInFullscreenMode = true; updateSceneLayerVisibility(); updateAndroidWidgetVisibility(); @@ -607,9 +608,12 @@ // don't force this to true, but use the current state instead. Same for Android widgets. // We should never get into the fullscreen mode state while LockTopControls is enabled. - if (ChromeFeatureList.sLockTopControlsOnLargeTablets.isEnabled() - || ChromeFeatureList.sLockTopControlsOnLargeTabletsV2.isEnabled()) { - assert !mIsInFullscreenMode : "Should not be in fullscreen mode with LockTopControls"; + boolean isLockTopControlsEnabled = + BrowserControlsUtils.doSyncMinHeightWithTotalHeightV2(mContext); + if (isLockTopControlsEnabled) { + assert !mIsInFullscreenMode + : "Should not be in fullscreen mode on large tablets where top controls lock is" + + " enabled."; } mIsInFullscreenMode = false;
diff --git a/chrome/browser/bookmarks/android/javatests/src/org/chromium/chrome/browser/bookmarks/bar/BookmarkBarTest.java b/chrome/browser/bookmarks/android/javatests/src/org/chromium/chrome/browser/bookmarks/bar/BookmarkBarTest.java index 5574bc23..0a2b053 100644 --- a/chrome/browser/bookmarks/android/javatests/src/org/chromium/chrome/browser/bookmarks/bar/BookmarkBarTest.java +++ b/chrome/browser/bookmarks/android/javatests/src/org/chromium/chrome/browser/bookmarks/bar/BookmarkBarTest.java
@@ -59,6 +59,7 @@ 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.DisableIf; import org.chromium.base.test.util.Features.EnableFeatures; import org.chromium.base.test.util.Restriction; import org.chromium.chrome.R; @@ -89,6 +90,7 @@ @EnableFeatures(ChromeFeatureList.ANDROID_BOOKMARK_BAR) @Restriction({DeviceFormFactor.TABLET_OR_DESKTOP, DeviceRestriction.RESTRICTION_TYPE_NON_AUTO}) @RunWith(ChromeJUnit4ClassRunner.class) +@DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public class BookmarkBarTest { @Rule
diff --git a/chrome/browser/component_updater/indigo_component_installer.cc b/chrome/browser/component_updater/indigo_component_installer.cc index 7531f55..7f9b13a 100644 --- a/chrome/browser/component_updater/indigo_component_installer.cc +++ b/chrome/browser/component_updater/indigo_component_installer.cc
@@ -10,6 +10,7 @@ #include <utility> #include <vector> +#include "base/callback_list.h" #include "base/feature_list.h" #include "base/files/file_path.h" #include "base/files/file_util.h" @@ -45,6 +46,19 @@ namespace component_updater { +namespace { +base::RepeatingCallbackList<void()>& GetCallbackList() { + static base::NoDestructor<base::RepeatingCallbackList<void()>> callbacks; + return *callbacks; +} +} // namespace + +base::CallbackListSubscription RegisterIndigoComponentReadyCallback( + base::RepeatingClosure callback) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + return GetCallbackList().Add(std::move(callback)); +} + IndigoComponentInstallerPolicy::IndigoComponentInstallerPolicy() = default; IndigoComponentInstallerPolicy::~IndigoComponentInstallerPolicy() = default; @@ -75,6 +89,8 @@ VLOG(1) << "Component ready, version " << version.GetString() << " in " << install_dir; GetInstallDirStorage() = install_dir; + + GetCallbackList().Notify(); } // Called during startup and installation before ComponentReady().
diff --git a/chrome/browser/component_updater/indigo_component_installer.h b/chrome/browser/component_updater/indigo_component_installer.h index c90b7c8..92dede5 100644 --- a/chrome/browser/component_updater/indigo_component_installer.h +++ b/chrome/browser/component_updater/indigo_component_installer.h
@@ -12,7 +12,9 @@ #include <string> #include <vector> +#include "base/callback_list.h" #include "base/files/file_path.h" +#include "base/functional/callback.h" #include "base/values.h" #include "base/version.h" #include "components/component_updater/component_installer.h" @@ -52,6 +54,13 @@ std::string GetName() const override; }; +// Registers a callback to be notified when the Indigo component becomes ready +// (i.e. installed or updated). +// Must be called on the Browser UI thread, and the callback will in turn +// be invoked on the Browser UI thread. +base::CallbackListSubscription RegisterIndigoComponentReadyCallback( + base::RepeatingClosure callback); + // Call once during startup to make the component update service aware of // the Indigo component. void RegisterIndigoComponent(ComponentUpdateService* cus);
diff --git a/chrome/browser/context_sharing/tab_bottom_sheet/android/java/src/org/chromium/chrome/browser/tab_bottom_sheet/CoBrowseViews.java b/chrome/browser/context_sharing/tab_bottom_sheet/android/java/src/org/chromium/chrome/browser/tab_bottom_sheet/CoBrowseViews.java index c7bb939..ba05c54 100644 --- a/chrome/browser/context_sharing/tab_bottom_sheet/android/java/src/org/chromium/chrome/browser/tab_bottom_sheet/CoBrowseViews.java +++ b/chrome/browser/context_sharing/tab_bottom_sheet/android/java/src/org/chromium/chrome/browser/tab_bottom_sheet/CoBrowseViews.java
@@ -107,8 +107,8 @@ */ public void attachPeekView(View peekView) { ViewGroup peekContainer = mContainerView.findViewById(R.id.actor_control_container); + peekContainer.removeAllViews(); detachFromParent(peekView); - assert peekContainer.getChildCount() == 0; mPeekView = peekView; peekContainer.addView(mPeekView); } @@ -141,6 +141,10 @@ webUiContainer.addView(newView); } } + if (webContents != null) { + webContents.getEventForwarder().setCurrentTouchOffsetX(0.0f); + webContents.getEventForwarder().setCurrentTouchOffsetY(0.0f); + } } @TabBottomSheetClientType
diff --git a/chrome/browser/context_sharing/tab_bottom_sheet/android/java/src/org/chromium/chrome/browser/tab_bottom_sheet/CoBrowseViewsTest.java b/chrome/browser/context_sharing/tab_bottom_sheet/android/java/src/org/chromium/chrome/browser/tab_bottom_sheet/CoBrowseViewsTest.java index 331181a..dd024d8 100644 --- a/chrome/browser/context_sharing/tab_bottom_sheet/android/java/src/org/chromium/chrome/browser/tab_bottom_sheet/CoBrowseViewsTest.java +++ b/chrome/browser/context_sharing/tab_bottom_sheet/android/java/src/org/chromium/chrome/browser/tab_bottom_sheet/CoBrowseViewsTest.java
@@ -32,6 +32,7 @@ import org.chromium.chrome.browser.context_sharing.R; import org.chromium.chrome.browser.contextual_tasks.fusebox.ContextualTasksFusebox; import org.chromium.content_public.browser.WebContents; +import org.chromium.ui.base.EventForwarder; /** Unit tests for {@link CoBrowseViews}. */ @RunWith(BaseRobolectricTestRunner.class) @@ -45,6 +46,7 @@ @Mock private View mFuseboxView; @Mock private View mPeekView; @Mock private WebContents mWebContents; + @Mock private EventForwarder mEventForwarder; private Context mContext; private CoBrowseViews mCoBrowseViews; @@ -54,6 +56,7 @@ mContext = ApplicationProvider.getApplicationContext(); when(mWebUi.getWebUiView()).thenReturn(mWebUiView); when(mFusebox.getFuseboxView()).thenReturn(mFuseboxView); + when(mWebContents.getEventForwarder()).thenReturn(mEventForwarder); View rootView = LayoutInflater.from(mContext).inflate(R.layout.tab_bottom_sheet, null); mCoBrowseViews =
diff --git a/chrome/browser/context_sharing/tab_bottom_sheet/android/java/src/org/chromium/chrome/browser/tab_bottom_sheet/TabBottomSheetCoordinatorTest.java b/chrome/browser/context_sharing/tab_bottom_sheet/android/java/src/org/chromium/chrome/browser/tab_bottom_sheet/TabBottomSheetCoordinatorTest.java index b17c806..0d4aeac 100644 --- a/chrome/browser/context_sharing/tab_bottom_sheet/android/java/src/org/chromium/chrome/browser/tab_bottom_sheet/TabBottomSheetCoordinatorTest.java +++ b/chrome/browser/context_sharing/tab_bottom_sheet/android/java/src/org/chromium/chrome/browser/tab_bottom_sheet/TabBottomSheetCoordinatorTest.java
@@ -62,7 +62,9 @@ import org.chromium.components.browser_ui.bottomsheet.BottomSheetObserver; import org.chromium.components.browser_ui.widget.TouchEventObserver; import org.chromium.components.browser_ui.widget.TouchEventProvider; +import org.chromium.content_public.browser.WebContents; import org.chromium.ui.KeyboardVisibilityDelegate; +import org.chromium.ui.base.EventForwarder; import org.chromium.ui.base.TestActivity; import org.chromium.ui.base.ViewUtils; import org.chromium.ui.base.WindowAndroid; @@ -294,8 +296,8 @@ assertNotNull(peekContainer); // Simulate a stale view. - View placeholderView = new View(mContext); - peekContainer.addView(placeholderView); + View staleView = new View(mContext); + peekContainer.addView(staleView); assertEquals(1, peekContainer.getChildCount()); content.destroy(); @@ -667,4 +669,16 @@ verify(mMockBottomSheetController, never()).collapseSheet(anyBoolean()); } + + @Test + public void testSetWebContents_resetsTouchOffset() { + WebContents mockWebContents = mock(WebContents.class); + EventForwarder mockEventForwarder = mock(EventForwarder.class); + when(mockWebContents.getEventForwarder()).thenReturn(mockEventForwarder); + + mCoBrowseViews.setWebContents(mockWebContents); + + verify(mockEventForwarder).setCurrentTouchOffsetX(0.0f); + verify(mockEventForwarder).setCurrentTouchOffsetY(0.0f); + } }
diff --git a/chrome/browser/context_sharing/tab_bottom_sheet/android/java/src/org/chromium/chrome/browser/tab_bottom_sheet/TabBottomSheetNativeInterface.java b/chrome/browser/context_sharing/tab_bottom_sheet/android/java/src/org/chromium/chrome/browser/tab_bottom_sheet/TabBottomSheetNativeInterface.java index bb9f2db5..96f3e26 100644 --- a/chrome/browser/context_sharing/tab_bottom_sheet/android/java/src/org/chromium/chrome/browser/tab_bottom_sheet/TabBottomSheetNativeInterface.java +++ b/chrome/browser/context_sharing/tab_bottom_sheet/android/java/src/org/chromium/chrome/browser/tab_bottom_sheet/TabBottomSheetNativeInterface.java
@@ -7,14 +7,12 @@ import static org.chromium.build.NullUtil.assumeNonNull; import org.jni_zero.CalledByNative; -import org.jni_zero.JniType; import org.jni_zero.NativeMethods; import org.chromium.build.annotations.NullMarked; import org.chromium.build.annotations.Nullable; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab_bottom_sheet.TabBottomSheetManager.NativeInterfaceDelegate; -import org.chromium.content_public.browser.WebContents; /** Interface for native methods to interact with the tab bottom sheet. */ @NullMarked @@ -58,14 +56,6 @@ } } - @CalledByNative - public void resetTouchOffset( - @Nullable @JniType("content::WebContents*") WebContents webContents) { - if (webContents == null) return; - webContents.getEventForwarder().setCurrentTouchOffsetX(0.0f); - webContents.getEventForwarder().setCurrentTouchOffsetY(0.0f); - } - private @Nullable TabBottomSheetManagerImpl getTabBottomSheetManager(@Nullable Tab tab) { if (tab == null) { return null;
diff --git a/chrome/browser/context_sharing/tab_bottom_sheet/android/tab_bottom_sheet_bridge.cc b/chrome/browser/context_sharing/tab_bottom_sheet/android/tab_bottom_sheet_bridge.cc index c02f8e6..8e72e19b 100644 --- a/chrome/browser/context_sharing/tab_bottom_sheet/android/tab_bottom_sheet_bridge.cc +++ b/chrome/browser/context_sharing/tab_bottom_sheet/android/tab_bottom_sheet_bridge.cc
@@ -90,15 +90,6 @@ web_contents); } -void TabBottomSheetBridge::ResetTouchOffset( - content::WebContents* web_contents) { - if (!java_bridge_) { - return; - } - Java_TabBottomSheetNativeInterface_resetTouchOffset( - AttachCurrentThread(), java_bridge_, web_contents); -} - bool TabBottomSheetBridge::Show(bool animate, bool starts_expanded) { if (!co_browse_views_) { return false;
diff --git a/chrome/browser/context_sharing/tab_bottom_sheet/android/tab_bottom_sheet_bridge.h b/chrome/browser/context_sharing/tab_bottom_sheet/android/tab_bottom_sheet_bridge.h index bdf417a..0f9f6812d 100644 --- a/chrome/browser/context_sharing/tab_bottom_sheet/android/tab_bottom_sheet_bridge.h +++ b/chrome/browser/context_sharing/tab_bottom_sheet/android/tab_bottom_sheet_bridge.h
@@ -59,11 +59,6 @@ // Sets or updates the WebContents displayed in the bottom sheet. void SetWebContents(content::WebContents* web_contents); - // Resets the touch offset for the given WebContents. - // This way, when the WebContents are transferred from a tab to the bottom - // sheet, the touch events are correctly aligned sans the toolbar. - void ResetTouchOffset(content::WebContents* web_contents); - // Triggers the bottom sheet to display on screen. // Returns true if the bottom sheet was successfully shown. It returns early // if there is no CoBrowseViews, so the caller should make sure that the
diff --git a/chrome/browser/contextual_tasks/android/contextual_tasks_panel_host_android.cc b/chrome/browser/contextual_tasks/android/contextual_tasks_panel_host_android.cc index 0dac76e8..01e27e9 100644 --- a/chrome/browser/contextual_tasks/android/contextual_tasks_panel_host_android.cc +++ b/chrome/browser/contextual_tasks/android/contextual_tasks_panel_host_android.cc
@@ -91,7 +91,6 @@ web_contents_->SetDelegate(this); if (auto* bridge = GetOrCreateBridge()) { bridge->SetWebContents(web_contents); - bridge->ResetTouchOffset(web_contents); if (is_open_) { bridge->Show(/*animate=*/false, /*starts_expanded=*/true); }
diff --git a/chrome/browser/contextual_tasks/contextual_tasks_url_loader_factory_interceptor_browsertest.cc b/chrome/browser/contextual_tasks/contextual_tasks_url_loader_factory_interceptor_browsertest.cc index 566d18f0..8e7b8e85 100644 --- a/chrome/browser/contextual_tasks/contextual_tasks_url_loader_factory_interceptor_browsertest.cc +++ b/chrome/browser/contextual_tasks/contextual_tasks_url_loader_factory_interceptor_browsertest.cc
@@ -40,6 +40,34 @@ const char kTestSubHost[] = "sub.google.com"; const char kDenylistHost[] = "lh3.google.com"; +constexpr char kNavigateWebviewScript[] = R"( + (async () => { + const waitFor = (selector, scope = document) => { + return new Promise(resolve => { + if (scope.querySelector(selector)) { + return resolve(scope.querySelector(selector)); + } + const observer = new MutationObserver(() => { + if (scope.querySelector(selector)) { + observer.disconnect(); + resolve(scope.querySelector(selector)); + } + }); + observer.observe(scope, {childList: true, subtree: true}); + }); + }; + const app = await waitFor('contextual-tasks-app'); + await new Promise(resolve => { + app.setOnLoadStartFinishedCallbackForTesting(resolve); + }); + if (!app.shadowRoot) { + await customElements.whenDefined('contextual-tasks-app'); + } + const webview = await waitFor('#threadFrame', app.shadowRoot); + webview.src = $1; + })(); + )"; + } // namespace class ContextualTasksUrlLoaderFactoryInterceptorBrowserTest @@ -250,26 +278,7 @@ // Script to find the webview and navigate it. // Note: We access the shadowRoot of the app. std::string script = content::JsReplace( - R"( - (async () => { - let app = document.querySelector('contextual-tasks-app'); - while (!app) { - await new Promise(r => setTimeout(r, 100)); - app = document.querySelector('contextual-tasks-app'); - } - // Wait for shadow root - while (!app.shadowRoot) { - await new Promise(r => setTimeout(r, 100)); - } - // Wait for threadFrame - let webview = app.shadowRoot.querySelector('#threadFrame'); - while (!webview) { - await new Promise(r => setTimeout(r, 100)); - webview = app.shadowRoot.querySelector('#threadFrame'); - } - webview.src = $1; - })(); - )", + kNavigateWebviewScript, https_server_.GetURL(kTestHost, "/echoheader?Authorization").spec()); EXPECT_TRUE(content::ExecJs(web_ui_contents, script)); @@ -320,6 +329,9 @@ }; const app = await waitFor('contextual-tasks-app'); + await new Promise(resolve => { + app.setOnLoadStartFinishedCallbackForTesting(resolve); + }); if (!app.shadowRoot) { await customElements.whenDefined('contextual-tasks-app'); } @@ -403,24 +415,7 @@ TabListInterface::From(browser())->GetActiveTab()->GetContents(); std::string script = content::JsReplace( - R"( - (async () => { - let app = document.querySelector('contextual-tasks-app'); - while (!app) { - await new Promise(r => setTimeout(r, 100)); - app = document.querySelector('contextual-tasks-app'); - } - while (!app.shadowRoot) { - await new Promise(r => setTimeout(r, 100)); - } - let webview = app.shadowRoot.querySelector('#threadFrame'); - while (!webview) { - await new Promise(r => setTimeout(r, 100)); - webview = app.shadowRoot.querySelector('#threadFrame'); - } - webview.src = $1; - })(); - )", + kNavigateWebviewScript, https_server_.GetURL(kTestHost, "/echoheader?Authorization").spec()); EXPECT_TRUE(content::ExecJs(web_ui_contents, script)); @@ -444,24 +439,7 @@ TabListInterface::From(browser())->GetActiveTab()->GetContents(); std::string script = content::JsReplace( - R"( - (async () => { - let app = document.querySelector('contextual-tasks-app'); - while (!app) { - await new Promise(r => setTimeout(r, 100)); - app = document.querySelector('contextual-tasks-app'); - } - while (!app.shadowRoot) { - await new Promise(r => setTimeout(r, 100)); - } - let webview = app.shadowRoot.querySelector('#threadFrame'); - while (!webview) { - await new Promise(r => setTimeout(r, 100)); - webview = app.shadowRoot.querySelector('#threadFrame'); - } - webview.src = $1; - })(); - )", + kNavigateWebviewScript, https_server_.GetURL(kTestHost, "/echoheader?Authorization").spec()); EXPECT_TRUE(content::ExecJs(web_ui_contents, script)); @@ -509,6 +487,9 @@ }; const app = await waitFor('contextual-tasks-app'); + await new Promise(resolve => { + app.setOnLoadStartFinishedCallbackForTesting(resolve); + }); if (!app.shadowRoot) { await customElements.whenDefined('contextual-tasks-app'); } @@ -564,26 +545,7 @@ // Script to find the webview and navigate it. // Note: We access the shadowRoot of the app. std::string script = content::JsReplace( - R"( - (async () => { - let app = document.querySelector('contextual-tasks-app'); - while (!app) { - await new Promise(r => setTimeout(r, 100)); - app = document.querySelector('contextual-tasks-app'); - } - // Wait for shadow root - while (!app.shadowRoot) { - await new Promise(r => setTimeout(r, 100)); - } - // Wait for threadFrame - let webview = app.shadowRoot.querySelector('#threadFrame'); - while (!webview) { - await new Promise(r => setTimeout(r, 100)); - webview = app.shadowRoot.querySelector('#threadFrame'); - } - webview.src = $1; - })(); - )", + kNavigateWebviewScript, https_server_.GetURL(kTestHost, "/onegoogle/echoheader?Authorization") .spec()); @@ -608,24 +570,7 @@ TabListInterface::From(browser())->GetActiveTab()->GetContents(); std::string script = content::JsReplace( - R"( - (async () => { - let app = document.querySelector('contextual-tasks-app'); - while (!app) { - await new Promise(r => setTimeout(r, 100)); - app = document.querySelector('contextual-tasks-app'); - } - while (!app.shadowRoot) { - await new Promise(r => setTimeout(r, 100)); - } - let webview = app.shadowRoot.querySelector('#threadFrame'); - while (!webview) { - await new Promise(r => setTimeout(r, 100)); - webview = app.shadowRoot.querySelector('#threadFrame'); - } - webview.src = $1; - })(); - )", + kNavigateWebviewScript, https_server_.GetURL(kDenylistHost, "/denylist/echoheader?Authorization") .spec());
diff --git a/chrome/browser/dictation/BUILD.gn b/chrome/browser/dictation/BUILD.gn index 4422b6d..8d0d643c 100644 --- a/chrome/browser/dictation/BUILD.gn +++ b/chrome/browser/dictation/BUILD.gn
@@ -9,6 +9,7 @@ "session_controller.h", "session_controller_delegate.h", "session_ui.h", + "session_ui_delegate.h", "stream_provider.h", "target.h", ] @@ -25,11 +26,14 @@ "features.cc", "features.h", "session_controller.cc", + "session_ui_impl.cc", + "session_ui_impl.h", ] deps = [ ":dictation", "//base", + "//chrome/browser/ui/browser_window", "//content/public/browser", ] } @@ -60,6 +64,7 @@ ":impl", ":test_support", "//base/test:test_support", + "//chrome/browser/ui:test_support", ] }
diff --git a/chrome/browser/dictation/DEPS b/chrome/browser/dictation/DEPS index 690c171..e51af06a 100644 --- a/chrome/browser/dictation/DEPS +++ b/chrome/browser/dictation/DEPS
@@ -2,4 +2,5 @@ "+base", "+testing/gmock", "+testing/gtest", + "+chrome/browser/ui/browser_window/public", ]
diff --git a/chrome/browser/dictation/dictation_keyed_service.cc b/chrome/browser/dictation/dictation_keyed_service.cc index 0eda740..171e712 100644 --- a/chrome/browser/dictation/dictation_keyed_service.cc +++ b/chrome/browser/dictation/dictation_keyed_service.cc
@@ -8,8 +8,10 @@ #include "chrome/browser/dictation/dictation_keyed_service_factory.h" #include "chrome/browser/dictation/features.h" #include "chrome/browser/dictation/session_controller.h" +#include "chrome/browser/dictation/session_ui_impl.h" #include "chrome/browser/dictation/target.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/browser_window/public/browser_window_interface.h" namespace dictation { @@ -19,6 +21,13 @@ return DictationKeyedServiceFactory::GetDictationKeyedService(context); } +DictationKeyedService::SessionState::SessionState( + SessionControllerDelegate& delegate, + base::WeakPtr<BrowserWindowInterface> window) + : controller_(delegate), window_(window) {} + +DictationKeyedService::SessionState::~SessionState() = default; + DictationKeyedService::DictationKeyedService(Profile* profile) : profile_(profile) { CHECK(base::FeatureList::IsEnabled(kDictation)); @@ -37,21 +46,29 @@ std::unique_ptr<SessionUi> DictationKeyedService::CreateUi( SessionController& controller) const { - return nullptr; + CHECK(session_); + if (!session_->window_) { + return nullptr; + } + + return std::make_unique<SessionUiImpl>(*session_->window_, controller); } -void DictationKeyedService::StartSession(Target* target) { - CHECK(!session_controller_); +void DictationKeyedService::StartSession(BrowserWindowInterface& window, + Target* target) { + CHECK(!session_); - session_controller_ = std::make_unique<SessionController>(*this); + session_.emplace(*this, window.GetWeakPtr()); + + session_->controller_.Initialize(); if (target) { - session_controller_->StartDictationStream(*target); + session_->controller_.StartDictationStream(*target); } } void DictationKeyedService::EndSession() { - session_controller_.reset(); + session_.reset(); } } // namespace dictation
diff --git a/chrome/browser/dictation/dictation_keyed_service.h b/chrome/browser/dictation/dictation_keyed_service.h index 4671f620..a310b13 100644 --- a/chrome/browser/dictation/dictation_keyed_service.h +++ b/chrome/browser/dictation/dictation_keyed_service.h
@@ -8,9 +8,12 @@ #include <memory> #include "base/memory/raw_ptr.h" +#include "base/memory/weak_ptr.h" +#include "chrome/browser/dictation/session_controller.h" #include "chrome/browser/dictation/session_controller_delegate.h" #include "components/keyed_service/core/keyed_service.h" +class BrowserWindowInterface; class Profile; namespace content { @@ -19,7 +22,6 @@ namespace dictation { -class SessionController; class Target; // Created on a per-profile basis for any regular profile (i.e. excludes OTR, @@ -45,6 +47,7 @@ SessionController& controller) const override; std::unique_ptr<SessionUi> CreateUi( SessionController& controller) const override; + void EndSession() override; // Starts a new session from the given target. It's the caller's // responsibility to ensure this never called while an existing session in @@ -53,19 +56,28 @@ // If a target is provided, the new session will immediately start up a // stream. Otherwise, if nullptr is passed the session is created without a // stream. - void StartSession(Target* target); - - // Ends the current session. No-op if there is no existing session. - void EndSession(); + void StartSession(BrowserWindowInterface& window, Target* target); // Returns null when no session is in progress. - SessionController* session_controller() const { - return session_controller_.get(); + SessionController* session_controller() { + return session_ ? &session_->controller_ : nullptr; + } + const SessionController* session_controller() const { + return const_cast<DictationKeyedService*>(this)->session_controller(); } private: raw_ptr<Profile> profile_; - std::unique_ptr<SessionController> session_controller_; + + struct SessionState { + SessionState(SessionControllerDelegate& delegate, + base::WeakPtr<BrowserWindowInterface> window); + ~SessionState(); + + SessionController controller_; + base::WeakPtr<BrowserWindowInterface> window_; + }; + std::optional<SessionState> session_; }; } // namespace dictation
diff --git a/chrome/browser/dictation/dictation_keyed_service_unittest.cc b/chrome/browser/dictation/dictation_keyed_service_unittest.cc index 0031bd4..ef47027 100644 --- a/chrome/browser/dictation/dictation_keyed_service_unittest.cc +++ b/chrome/browser/dictation/dictation_keyed_service_unittest.cc
@@ -6,6 +6,7 @@ #include "base/test/scoped_feature_list.h" #include "chrome/browser/dictation/features.h" +#include "chrome/browser/ui/browser_window/test/mock_browser_window_interface.h" #include "testing/gtest/include/gtest/gtest.h" namespace dictation { @@ -21,6 +22,7 @@ protected: base::test::ScopedFeatureList scoped_feature_list_; + testing::NiceMock<MockBrowserWindowInterface> window_; std::unique_ptr<DictationKeyedService> service_; }; @@ -32,12 +34,12 @@ TEST_F(DictationKeyedServiceTest, StartSessionWithNullTarget) { ASSERT_EQ(service_->session_controller(), nullptr); - service_->StartSession(nullptr); + service_->StartSession(window_, nullptr); EXPECT_NE(service_->session_controller(), nullptr); } TEST_F(DictationKeyedServiceTest, EndSessionRemovesController) { - service_->StartSession(nullptr); + service_->StartSession(window_, nullptr); ASSERT_NE(service_->session_controller(), nullptr); service_->EndSession(); EXPECT_EQ(service_->session_controller(), nullptr);
diff --git a/chrome/browser/dictation/session_controller.cc b/chrome/browser/dictation/session_controller.cc index 7b2c5e7..b281e97 100644 --- a/chrome/browser/dictation/session_controller.cc +++ b/chrome/browser/dictation/session_controller.cc
@@ -13,8 +13,7 @@ namespace dictation { SessionController::SessionController(SessionControllerDelegate& delegate) - : delegate_(delegate), - ui_(delegate_->CreateUi(*this)) {} + : delegate_(delegate) {} SessionController::~SessionController() { CHECK(state_ != State::kInactive || !attached_stream_provider_); @@ -23,6 +22,10 @@ } } +void SessionController::Initialize() { + ui_ = delegate_->CreateUi(*this); +} + void SessionController::StartDictationStream(Target& target) { CHECK_EQ(state_, State::kInactive); @@ -31,7 +34,7 @@ stream_provider->BindToTarget(target); attached_stream_provider_ = std::move(stream_provider); - MoveToState(State::kInitializing); + MoveToState(State::kStreamInitializing); } void SessionController::EndDictationStream() { @@ -41,6 +44,12 @@ MoveToState(State::kInactive); } +void SessionController::RequestEndSession() { + delegate_->EndSession(); + + // DO NOT ADD CODE AFTER THIS: EndSession() destroys `this`. +} + void SessionController::MoveToState(State new_state) { // TODO(bokan): use base::StateTransitions state_ = new_state;
diff --git a/chrome/browser/dictation/session_controller.h b/chrome/browser/dictation/session_controller.h index 3f6ce74..8b991b1 100644 --- a/chrome/browser/dictation/session_controller.h +++ b/chrome/browser/dictation/session_controller.h
@@ -10,6 +10,7 @@ #include "base/callback_list.h" #include "base/functional/bind.h" #include "base/memory/raw_ref.h" +#include "chrome/browser/dictation/session_ui_delegate.h" namespace dictation { @@ -21,7 +22,7 @@ // The session_controller is a coordinating class between the StreamProvider and // the UI. It manages Profile-level state and transitions and synchronizes the // dictation system. -class SessionController { +class SessionController : public SessionUiDelegate { public: enum class State { // Dictation is currently not active, there is no stream provider attached. @@ -29,7 +30,7 @@ // A stream provider has just been attached but it is still starting up and // not yet active. - kInitializing, + kStreamInitializing, // A stream provider is attached and actively transcribing and sending // data. @@ -41,11 +42,16 @@ }; explicit SessionController(SessionControllerDelegate& delegate); - ~SessionController(); - + ~SessionController() override; SessionController(const SessionController&) = delete; SessionController& operator=(const SessionController&) = delete; + // Called by the service when it's ready for the session to start. + void Initialize(); + + // SessionUiDelegate + void RequestEndSession() override; + // Starts a new dictation stream by creating and attaching a new stream // provider. An existing stream must have been detached before calling this // method.
diff --git a/chrome/browser/dictation/session_controller_delegate.h b/chrome/browser/dictation/session_controller_delegate.h index 3fc135ad..e51dac4 100644 --- a/chrome/browser/dictation/session_controller_delegate.h +++ b/chrome/browser/dictation/session_controller_delegate.h
@@ -26,6 +26,10 @@ SessionController& controller) const = 0; virtual std::unique_ptr<SessionUi> CreateUi( SessionController& controller) const = 0; + + // Ends the current session. No-op if there is no existing session. Note: this + // may destroy the session controller synchronously. + virtual void EndSession() = 0; }; } // namespace dictation
diff --git a/chrome/browser/dictation/session_controller_unittest.cc b/chrome/browser/dictation/session_controller_unittest.cc index fc13cf3..a64a501 100644 --- a/chrome/browser/dictation/session_controller_unittest.cc +++ b/chrome/browser/dictation/session_controller_unittest.cc
@@ -40,7 +40,8 @@ TEST_F(DictationSessionControllerTest, StreamAffectsState) { MockTarget target; controller_->StartDictationStream(target); - EXPECT_EQ(controller_->state(), SessionController::State::kInitializing); + EXPECT_EQ(controller_->state(), + SessionController::State::kStreamInitializing); EXPECT_NE(controller_->attached_stream_provider(), nullptr); controller_->EndDictationStream();
diff --git a/chrome/browser/dictation/session_ui_delegate.h b/chrome/browser/dictation/session_ui_delegate.h new file mode 100644 index 0000000..f06344a --- /dev/null +++ b/chrome/browser/dictation/session_ui_delegate.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 CHROME_BROWSER_DICTATION_SESSION_UI_DELEGATE_H_ +#define CHROME_BROWSER_DICTATION_SESSION_UI_DELEGATE_H_ + +namespace dictation { + +// Interface for the UI to communicate back to the session controller. +class SessionUiDelegate { + public: + virtual ~SessionUiDelegate() = default; + + // Called when the session end has been requested via the UI. + virtual void RequestEndSession() = 0; +}; + +} // namespace dictation + +#endif // CHROME_BROWSER_DICTATION_SESSION_UI_DELEGATE_H_
diff --git a/chrome/browser/dictation/session_ui_impl.cc b/chrome/browser/dictation/session_ui_impl.cc new file mode 100644 index 0000000..9a44895a --- /dev/null +++ b/chrome/browser/dictation/session_ui_impl.cc
@@ -0,0 +1,20 @@ +// 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/dictation/session_ui_impl.h" + +#include "base/functional/bind.h" +#include "base/memory/ptr_util.h" +#include "chrome/browser/dictation/session_ui_delegate.h" +#include "chrome/browser/profiles/profile.h" + +namespace dictation { + +SessionUiImpl::SessionUiImpl(BrowserWindowInterface& window, + SessionUiDelegate& delegate) + : controller_(delegate) {} + +SessionUiImpl::~SessionUiImpl() = default; + +} // namespace dictation
diff --git a/chrome/browser/dictation/session_ui_impl.h b/chrome/browser/dictation/session_ui_impl.h new file mode 100644 index 0000000..a7306ee --- /dev/null +++ b/chrome/browser/dictation/session_ui_impl.h
@@ -0,0 +1,32 @@ +// 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_DICTATION_SESSION_UI_IMPL_H_ +#define CHROME_BROWSER_DICTATION_SESSION_UI_IMPL_H_ + +#include "base/memory/raw_ref.h" +#include "chrome/browser/dictation/session_ui.h" + +class BrowserWindowInterface; + +namespace dictation { + +class SessionUiDelegate; + +class SessionUiImpl : public SessionUi { + public: + explicit SessionUiImpl(BrowserWindowInterface& window, + SessionUiDelegate& delegate); + ~SessionUiImpl() override; + + SessionUiImpl(const SessionUiImpl&) = delete; + SessionUiImpl& operator=(const SessionUiImpl&) = delete; + + private: + const base::raw_ref<SessionUiDelegate> controller_; +}; + +} // namespace dictation + +#endif // CHROME_BROWSER_DICTATION_SESSION_UI_IMPL_H_
diff --git a/chrome/browser/dictation/test_util.h b/chrome/browser/dictation/test_util.h index ada2bd3..8bdf056 100644 --- a/chrome/browser/dictation/test_util.h +++ b/chrome/browser/dictation/test_util.h
@@ -44,6 +44,7 @@ CreateUi, (SessionController & controller), (const, override)); + MOCK_METHOD(void, EndSession, (), (override)); }; class MockTarget : public Target {
diff --git a/chrome/browser/educational_tip/BUILD.gn b/chrome/browser/educational_tip/BUILD.gn index 7e9e81e..134b4302 100644 --- a/chrome/browser/educational_tip/BUILD.gn +++ b/chrome/browser/educational_tip/BUILD.gn
@@ -32,7 +32,6 @@ "java/src/org/chromium/chrome/browser/educational_tip/cards/SignInPromoCoordinator.java", "java/src/org/chromium/chrome/browser/educational_tip/cards/TabGroupPromoCoordinator.java", "java/src/org/chromium/chrome/browser/educational_tip/cards/TabGroupSyncPromoCoordinator.java", - "java/src/org/chromium/chrome/browser/educational_tip/cards/TipsNotificationsPromoCoordinator.java", "java/src/org/chromium/chrome/browser/educational_tip/two_cell/EducationalTipModuleTwoCellBuilder.java", "java/src/org/chromium/chrome/browser/educational_tip/two_cell/EducationalTipModuleTwoCellCoordinator.java", "java/src/org/chromium/chrome/browser/educational_tip/two_cell/EducationalTipModuleTwoCellProperties.java", @@ -121,7 +120,6 @@ "java/res/drawable/sign_in_promo_logo.xml", "java/res/drawable/tab_group_promo_logo.xml", "java/res/drawable/tab_group_sync_promo_logo.xml", - "java/res/drawable/tips_notifications_promo_logo.xml", "java/res/layout/educational_tip_default_browser_bottom_sheet.xml", "java/res/layout/educational_tip_module_layout.xml", "java/res/layout/educational_tip_module_two_cell_layout.xml",
diff --git a/chrome/browser/educational_tip/java/res/drawable/tips_notifications_promo_logo.xml b/chrome/browser/educational_tip/java/res/drawable/tips_notifications_promo_logo.xml deleted file mode 100644 index 6248a323..0000000 --- a/chrome/browser/educational_tip/java/res/drawable/tips_notifications_promo_logo.xml +++ /dev/null
@@ -1,26 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -Copyright 2025 The Chromium Authors -Use of this source code is governed by a BSD-style license that can be -found in the LICENSE file. ---> - -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="62dp" - android:height="62dp" - android:viewportWidth="62" - android:viewportHeight="62"> - <path - android:pathData="M8.552,0L53.448,0A8.552,8.552 0,0 1,62 8.552L62,53.448A8.552,8.552 0,0 1,53.448 62L8.552,62A8.552,8.552 0,0 1,0 53.448L0,8.552A8.552,8.552 0,0 1,8.552 0z" - android:fillColor="@color/educational_tip_card_logo_color_10"/> - <path - android:pathData="M24.704,4.425C25.016,4.166 25.173,4.037 25.316,3.928C28.678,1.357 33.322,1.357 36.685,3.928C36.827,4.037 36.984,4.166 37.296,4.425C37.436,4.54 37.506,4.598 37.575,4.653C39.157,5.912 41.097,6.625 43.111,6.689C43.198,6.691 43.289,6.692 43.469,6.695C43.873,6.7 44.075,6.702 44.254,6.711C48.465,6.926 52.022,9.942 52.963,14.095C53.003,14.271 53.04,14.472 53.115,14.873C53.149,15.052 53.166,15.141 53.184,15.228C53.595,17.221 54.627,19.027 56.129,20.383C56.195,20.442 56.263,20.502 56.4,20.621C56.706,20.887 56.859,21.02 56.99,21.143C60.08,24.042 60.886,28.663 58.965,32.455C58.883,32.616 58.784,32.794 58.586,33.15C58.498,33.309 58.454,33.389 58.413,33.467C57.46,35.26 57.102,37.314 57.39,39.329C57.402,39.417 57.417,39.507 57.446,39.686C57.511,40.089 57.544,40.291 57.566,40.47C58.088,44.698 55.766,48.761 51.881,50.418C51.716,50.488 51.527,50.56 51.15,50.705C50.981,50.769 50.896,50.801 50.815,50.834C48.944,51.59 47.363,52.93 46.302,54.66C46.256,54.736 46.21,54.814 46.118,54.971C45.911,55.322 45.808,55.497 45.711,55.649C43.421,59.227 39.057,60.831 35.027,59.578C34.856,59.525 34.666,59.457 34.284,59.322C34.114,59.262 34.029,59.232 33.946,59.204C32.032,58.568 29.968,58.568 28.054,59.204C27.971,59.232 27.886,59.262 27.716,59.322C27.334,59.457 27.144,59.525 26.973,59.578C22.942,60.831 18.579,59.227 16.289,55.649C16.192,55.497 16.089,55.322 15.882,54.971C15.79,54.814 15.744,54.736 15.698,54.66C14.637,52.93 13.056,51.59 11.185,50.834C11.104,50.801 11.019,50.769 10.851,50.705C10.473,50.56 10.284,50.488 10.119,50.418C6.234,48.761 3.912,44.698 4.434,40.47C4.456,40.291 4.489,40.089 4.554,39.686C4.583,39.507 4.598,39.417 4.61,39.329C4.898,37.314 4.54,35.26 3.587,33.467C3.546,33.389 3.502,33.309 3.414,33.15C3.216,32.794 3.117,32.616 3.036,32.455C1.114,28.663 1.92,24.042 5.01,21.143C5.141,21.02 5.294,20.887 5.6,20.621C5.737,20.502 5.805,20.442 5.871,20.383C7.373,19.027 8.405,17.221 8.816,15.228C8.834,15.141 8.851,15.052 8.885,14.873C8.96,14.472 8.997,14.271 9.037,14.095C9.978,9.942 13.535,6.926 17.746,6.711C17.925,6.702 18.127,6.7 18.531,6.695C18.711,6.692 18.802,6.691 18.889,6.689C20.903,6.625 22.843,5.912 24.425,4.653C24.494,4.598 24.564,4.54 24.704,4.425Z" - android:fillColor="@color/educational_tip_card_logo_color_3"/> - <group> - <clip-path - android:pathData="M14,14h34v34h-34z"/> - <path - android:pathData="M25.333,31.106C25.333,32.665 25.888,33.999 26.998,35.108C28.108,36.218 29.442,36.773 31,36.773C32.558,36.773 33.892,36.218 35.002,35.108C36.112,33.999 36.667,32.665 36.667,31.106C36.667,29.548 36.112,28.214 35.002,27.104C33.892,25.994 32.558,25.44 31,25.44C29.442,25.44 28.108,25.994 26.998,27.104C25.888,28.214 25.333,29.548 25.333,31.106ZM31,39.606C31.307,39.606 31.602,39.594 31.885,39.571C32.169,39.547 32.452,39.5 32.735,39.429L29.406,45.167C25.841,44.765 22.854,43.242 20.446,40.598C18.038,37.93 16.833,34.766 16.833,31.106C16.833,30.115 16.928,29.158 17.117,28.237C17.306,27.293 17.589,26.396 17.967,25.546L23.633,35.356C24.365,36.631 25.381,37.658 26.679,38.438C27.978,39.217 29.418,39.606 31,39.606ZM31,22.606C29.111,22.606 27.435,23.161 25.971,24.271C24.507,25.357 23.492,26.75 22.925,28.45L19.596,22.712C20.894,20.965 22.524,19.572 24.483,18.533C26.467,17.471 28.639,16.94 31,16.94C33.338,16.94 35.486,17.459 37.446,18.498C39.406,19.513 41.035,20.883 42.333,22.606H31ZM43.963,25.44C44.364,26.313 44.659,27.222 44.848,28.167C45.06,29.111 45.167,30.091 45.167,31.106C45.167,34.766 43.963,37.918 41.554,40.563C39.169,43.207 36.218,44.742 32.7,45.167L38.367,35.356C38.721,34.742 38.992,34.081 39.181,33.373C39.394,32.641 39.5,31.885 39.5,31.106C39.5,29.997 39.299,28.969 38.898,28.025C38.52,27.057 37.989,26.195 37.304,25.44H43.963Z" - android:fillColor="@color/educational_tip_card_logo_color_6"/> - </group> -</vector>
diff --git a/chrome/browser/educational_tip/java/res/values-night/colors.xml b/chrome/browser/educational_tip/java/res/values-night/colors.xml index 4e66a6b..1552a5a 100644 --- a/chrome/browser/educational_tip/java/res/values-night/colors.xml +++ b/chrome/browser/educational_tip/java/res/values-night/colors.xml
@@ -15,7 +15,6 @@ <color name="educational_tip_card_logo_color_7">@color/material_primary_70</color> <color name="educational_tip_card_logo_color_8">@color/material_secondary_40</color> <color name="educational_tip_card_logo_color_9">@color/material_tertiary_40</color> - <color name="educational_tip_card_logo_color_10">?attr/colorSurfaceContainer</color> <!-- Setup List celebratory promo colors --> <color name="setup_list_celebratory_promo_gradient_blue_start">@color/baseline_primary_80</color>
diff --git a/chrome/browser/educational_tip/java/res/values/colors.xml b/chrome/browser/educational_tip/java/res/values/colors.xml index 59b7a7e..da45d40d 100644 --- a/chrome/browser/educational_tip/java/res/values/colors.xml +++ b/chrome/browser/educational_tip/java/res/values/colors.xml
@@ -15,7 +15,6 @@ <color name="educational_tip_card_logo_color_7">@color/material_primary_60</color> <color name="educational_tip_card_logo_color_8">@color/material_secondary_80</color> <color name="educational_tip_card_logo_color_9">@color/material_tertiary_80</color> - <color name="educational_tip_card_logo_color_10">?attr/colorSurface</color> <color name="educational_tip_card_logo_color_11">@color/baseline_primary_40</color> <!-- Setup List celebratory promo colors -->
diff --git a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationTipModuleActionDelegate.java b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationTipModuleActionDelegate.java index 8e40ca3..1d61650 100644 --- a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationTipModuleActionDelegate.java +++ b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationTipModuleActionDelegate.java
@@ -64,9 +64,6 @@ */ void showSignInLegacy(); - /** Opens the settings page for the Tips Notifications channel. */ - void showTipsNotificationsChannelSettings(); - /** Opens the Password Checkup UI. */ void showPasswordCheckup();
diff --git a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipCardProviderFactory.java b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipCardProviderFactory.java index b14ddb3..d36d9a10 100644 --- a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipCardProviderFactory.java +++ b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipCardProviderFactory.java
@@ -19,7 +19,6 @@ import org.chromium.chrome.browser.educational_tip.cards.SignInPromoCoordinator; import org.chromium.chrome.browser.educational_tip.cards.TabGroupPromoCoordinator; import org.chromium.chrome.browser.educational_tip.cards.TabGroupSyncPromoCoordinator; -import org.chromium.chrome.browser.educational_tip.cards.TipsNotificationsPromoCoordinator; import org.chromium.chrome.browser.magic_stack.ModuleDelegate.ModuleType; /** A factory interface for building a EducationalTipCardProvider instance. */ @@ -52,9 +51,6 @@ callbackController, actionDelegate, removeModuleCallback); - case ModuleType.TIPS_NOTIFICATIONS_PROMO: - return new TipsNotificationsPromoCoordinator( - onModuleClickedCallback, callbackController, actionDelegate); case ModuleType.ENHANCED_SAFE_BROWSING_PROMO: return new EnhancedSafeBrowsingPromoCoordinator( onModuleClickedCallback, actionDelegate);
diff --git a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipCardProviderSignalHandler.java b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipCardProviderSignalHandler.java index fb1eaeb..3494edd8 100644 --- a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipCardProviderSignalHandler.java +++ b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipCardProviderSignalHandler.java
@@ -71,8 +71,6 @@ "is_eligible_to_history_opt_in", ProcessedValue.fromFloat(isEligibleToHistoryOptIn(profile))); return inputContext; - case ModuleType.TIPS_NOTIFICATIONS_PROMO: - return inputContext; default: assert false : "Card type not supported: " + moduleType; return inputContext;
diff --git a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipModuleUtils.java b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipModuleUtils.java index 466f88e..faa91c6 100644 --- a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipModuleUtils.java +++ b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipModuleUtils.java
@@ -29,7 +29,6 @@ modules.add(ModuleType.TAB_GROUP_SYNC_PROMO); modules.add(ModuleType.QUICK_DELETE_PROMO); modules.add(ModuleType.HISTORY_SYNC_PROMO); - modules.add(ModuleType.TIPS_NOTIFICATIONS_PROMO); modules.add(ModuleType.NTP_THEME_PROMO); return modules; }
diff --git a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/cards/TipsNotificationsPromoCoordinator.java b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/cards/TipsNotificationsPromoCoordinator.java deleted file mode 100644 index 85bca37b..0000000 --- a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/cards/TipsNotificationsPromoCoordinator.java +++ /dev/null
@@ -1,72 +0,0 @@ -// Copyright 2025 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.educational_tip.cards; - -import androidx.annotation.DrawableRes; - -import org.chromium.base.CallbackController; -import org.chromium.build.annotations.NullMarked; -import org.chromium.chrome.browser.educational_tip.EducationTipModuleActionDelegate; -import org.chromium.chrome.browser.educational_tip.EducationalTipCardProvider; -import org.chromium.chrome.browser.educational_tip.R; - -/** Coordinator for the Tips Notifications promo card. */ -@NullMarked -public class TipsNotificationsPromoCoordinator implements EducationalTipCardProvider { - private final EducationTipModuleActionDelegate mActionDelegate; - private final Runnable mOnClickedRunnable; - - /** - * @param onModuleClickedCallback The callback to be called when the module is clicked. - * @param callbackController The instance of {@link CallbackController}. - * @param actionDelegate The instance of {@link EducationTipModuleActionDelegate}. - */ - public TipsNotificationsPromoCoordinator( - Runnable onModuleClickedCallback, - CallbackController callbackController, - EducationTipModuleActionDelegate actionDelegate) { - mActionDelegate = actionDelegate; - - mOnClickedRunnable = - callbackController.makeCancelable( - () -> { - mActionDelegate.showTipsNotificationsChannelSettings(); - onModuleClickedCallback.run(); - }); - } - - // EducationalTipCardProvider implementation. - - @Override - public String getCardTitle() { - return mActionDelegate - .getContext() - .getString(R.string.educational_tip_tips_notifications_title); - } - - @Override - public String getCardDescription() { - return mActionDelegate - .getContext() - .getString(R.string.educational_tip_tips_notifications_description); - } - - @Override - public String getCardButtonText() { - return mActionDelegate - .getContext() - .getString(R.string.educational_tip_tips_notifications_button); - } - - @Override - public @DrawableRes int getCardImage() { - return R.drawable.tips_notifications_promo_logo; - } - - @Override - public void onCardClicked() { - mOnClickedRunnable.run(); - } -}
diff --git a/chrome/browser/educational_tip/junit/src/org/chromium/chrome/browser/educational_tip/EducationalTipModuleMediatorUnitTest.java b/chrome/browser/educational_tip/junit/src/org/chromium/chrome/browser/educational_tip/EducationalTipModuleMediatorUnitTest.java index fd5e565..d371d33 100644 --- a/chrome/browser/educational_tip/junit/src/org/chromium/chrome/browser/educational_tip/EducationalTipModuleMediatorUnitTest.java +++ b/chrome/browser/educational_tip/junit/src/org/chromium/chrome/browser/educational_tip/EducationalTipModuleMediatorUnitTest.java
@@ -160,13 +160,6 @@ R.string.educational_tip_history_sync_description, R.drawable.history_sync_promo_logo); - // Test showing tips notifications promo card. - testShowModuleImpl( - ModuleType.TIPS_NOTIFICATIONS_PROMO, - R.string.educational_tip_tips_notifications_title, - R.string.educational_tip_tips_notifications_description, - R.drawable.tips_notifications_promo_logo); - // Test showing quick delete promo card. testShowModuleImpl( ModuleType.NTP_THEME_PROMO,
diff --git a/chrome/browser/extensions/api/web_request/web_request_apitest.cc b/chrome/browser/extensions/api/web_request/web_request_apitest.cc index 57acfb3..0b856003 100644 --- a/chrome/browser/extensions/api/web_request/web_request_apitest.cc +++ b/chrome/browser/extensions/api/web_request/web_request_apitest.cc
@@ -8604,11 +8604,15 @@ url_loader_factory_reset_runloop_.Run(); } + int reset_count() const { return reset_count_; } + private: void OnDidResetURLLoaderFactories() override { + ++reset_count_; url_loader_factory_reset_runloop_.Quit(); } + int reset_count_ = 0; base::RunLoop url_loader_factory_reset_runloop_; }; @@ -8708,6 +8712,62 @@ registration_observer.WaitForRegistrationStored(); } +// Tests that URLLoaderFactories are reset only on transitions of +// MayHaveProxies(): when the first relevant extension loads and when the last +// one unloads, but not on intermediate load/unload events. +IN_PROC_BROWSER_TEST_F(ManifestV3WebRequestApiTest, + ResetURLLoaderFactoriesOnMayHaveProxiesTransitions) { + // Skip if the proxy is forced since factories won't be reset in that case. + if (base::FeatureList::IsEnabled( + extensions_features::kForceWebRequestProxyForTest)) { + return; + } + + auto make_extension_dir = [](const char* name) { + static constexpr char kManifestTemplate[] = + R"({ + "name": "%s", + "manifest_version": 3, + "version": "0.1", + "permissions": ["webRequest"], + "background": {"service_worker": "background.js"} + })"; + auto dir = std::make_unique<TestExtensionDir>(); + dir->WriteManifest(base::StringPrintf(kManifestTemplate, name)); + dir->WriteFile(FILE_PATH_LITERAL("background.js"), ""); + return dir; + }; + + std::unique_ptr<TestExtensionDir> dir_a = make_extension_dir("ExtensionA"); + std::unique_ptr<TestExtensionDir> dir_b = make_extension_dir("ExtensionB"); + + URLLoaderFactoriesResetWaiter waiter; + + // Loading the first extension transitions MayHaveProxies() from false to + // true, triggering a reset. + const Extension* extension_a = LoadExtension(dir_a->UnpackedPath()); + ASSERT_TRUE(extension_a); + ExtensionId id_a = extension_a->id(); + EXPECT_EQ(1, waiter.reset_count()); + + // Loading a second extension keeps MayHaveProxies() true, so no reset. + const Extension* extension_b = LoadExtension(dir_b->UnpackedPath()); + ASSERT_TRUE(extension_b); + ExtensionId id_b = extension_b->id(); + EXPECT_EQ(1, waiter.reset_count()); + + // Unloading one of two relevant extensions keeps MayHaveProxies() true, so + // no reset. + UninstallExtension(id_a); + EXPECT_EQ(1, waiter.reset_count()); + + // Unloading the last relevant extension transitions MayHaveProxies() from + // true to false, which must also trigger a reset so stale proxying + // factories are torn down. + UninstallExtension(id_b); + EXPECT_EQ(2, waiter.reset_count()); +} + #if BUILDFLAG(ENABLE_EXTENSIONS) // TODO(crbug.com/478208019): Test is flaky.
diff --git a/chrome/browser/extensions/events_apitest.cc b/chrome/browser/extensions/events_apitest.cc index 41da5b5..79325c429 100644 --- a/chrome/browser/extensions/events_apitest.cc +++ b/chrome/browser/extensions/events_apitest.cc
@@ -281,7 +281,7 @@ // Tests that events broadcast right after a profile has started to be destroyed // do not cause a crash. Regression test for crbug.com/40847328. // TODO(crbug.com/505759503): Enable the test. -#if BUILDFLAG(IS_CHROMEOS) && defined(ADDRESS_SANITIZER) +#if BUILDFLAG(IS_CHROMEOS) #define MAYBE_DispatchEventDuringShutdown DISABLED_DispatchEventDuringShutdown #else #define MAYBE_DispatchEventDuringShutdown DispatchEventDuringShutdown
diff --git a/chrome/browser/extensions/service_worker_registration_apitest.cc b/chrome/browser/extensions/service_worker_registration_apitest.cc index 1ee4752..cd8962fad 100644 --- a/chrome/browser/extensions/service_worker_registration_apitest.cc +++ b/chrome/browser/extensions/service_worker_registration_apitest.cc
@@ -102,6 +102,8 @@ WaitForWorkerUnregistrationAttemptCompleted(); } + bool registration_delayed() const { return registration_delayed_; } + private: void WaitForWorkerUnregistrationAttemptCompleted() { SCOPED_TRACE("Waiting for worker unregistration attempt to complete"); @@ -120,9 +122,16 @@ } } + void OnWorkerRegistrationDelayed(const ExtensionId& extension_id) override { + if (extension_id == expected_extension_id_) { + registration_delayed_ = true; + } + } + const ExtensionId expected_extension_id_; base::RunLoop registration_attempt_runloop; base::RunLoop unregistration_attempt_runloop; + bool registration_delayed_ = false; }; } // namespace @@ -921,10 +930,7 @@ GetServiceWorkerRegistrationState(*reinstalled_extension)); } - CheckBooleanHistogramCounts( - "Extensions.ServiceWorkerBackground." - "WorkerRegistrationRetryForUnregistrationAttemptsResult", - /*true_count=*/1, /*false_count=*/0, histogram_tester); + EXPECT_TRUE(registration_waiter2.registration_delayed()); } #if BUILDFLAG(ENABLE_EXTENSIONS)
diff --git a/chrome/browser/finds/core/finds_features.cc b/chrome/browser/finds/core/finds_features.cc index ed757bc6..579e456 100644 --- a/chrome/browser/finds/core/finds_features.cc +++ b/chrome/browser/finds/core/finds_features.cc
@@ -50,4 +50,7 @@ &kChromeFinds, "enable_theme_url_visit_count_opt_in", /*default_value=*/true}; +constexpr base::FeatureParam<bool> kBlockModelExecution{ + &kChromeFinds, "block_model_execution", /*default_value=*/false}; + } // namespace finds::features
diff --git a/chrome/browser/finds/core/finds_features.h b/chrome/browser/finds/core/finds_features.h index c87b924..85af956 100644 --- a/chrome/browser/finds/core/finds_features.h +++ b/chrome/browser/finds/core/finds_features.h
@@ -65,6 +65,9 @@ // The feature flag param to enable the theme URL visit count opt-in flow. extern const base::FeatureParam<bool> kEnableThemeUrlVisitCountOptIn; +// The feature flag param to block model execution. +extern const base::FeatureParam<bool> kBlockModelExecution; + } // namespace finds::features #endif // CHROME_BROWSER_FINDS_CORE_FINDS_FEATURES_H_
diff --git a/chrome/browser/finds/core/finds_service.cc b/chrome/browser/finds/core/finds_service.cc index cf6d851..3621d7c 100644 --- a/chrome/browser/finds/core/finds_service.cc +++ b/chrome/browser/finds/core/finds_service.cc
@@ -242,6 +242,14 @@ return; } + if (finds::features::kBlockModelExecution.Get()) { + RecordFindsResultAndRunCallback( + std::move(callback), + {Result::Status::kModelExecutionDisabledByParam, + "Error: Model execution disabled by feature parameter."}); + return; + } + if (!IsModelExecutionCooldownPassed(pref_service_)) { RecordFindsResultAndRunCallback(std::move(callback), {Result::Status::kModelExecutionOnCooldown,
diff --git a/chrome/browser/finds/core/finds_service.h b/chrome/browser/finds/core/finds_service.h index 9014c8d3..33e4ff82 100644 --- a/chrome/browser/finds/core/finds_service.h +++ b/chrome/browser/finds/core/finds_service.h
@@ -78,8 +78,9 @@ kNoSuggestionsForTheme = 10, kFailedToScheduleNotification = 11, kDisabledByEnterprisePolicy = 12, + kModelExecutionDisabledByParam = 13, - kMaxValue = kDisabledByEnterprisePolicy, + kMaxValue = kModelExecutionDisabledByParam, }; // LINT.ThenChange(//tools/metrics/histograms/metadata/others/enums.xml:FindsResult) Status status;
diff --git a/chrome/browser/finds/core/finds_service_unittest.cc b/chrome/browser/finds/core/finds_service_unittest.cc index 6a802ed0..2ea2a3fa 100644 --- a/chrome/browser/finds/core/finds_service_unittest.cc +++ b/chrome/browser/finds/core/finds_service_unittest.cc
@@ -1035,4 +1035,28 @@ service_->RemoveObserver(&observer); } +TEST_F(FindsServiceTest, TestModelExecutionDisabledByParam) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeatureWithParameters( + finds::features::kChromeFinds, {{"block_model_execution", "true"}}); + + EXPECT_CALL(*history_service_, QueryHistory(_, _, _, _)).Times(0); + EXPECT_CALL(*opt_guide_service_, ExecuteModel(_, _, _, _)).Times(0); + + bool callback_called = false; + service_->ExecuteModelAndScheduleNotification( + base::BindLambdaForTesting([&](FindsService::Result result) { + EXPECT_EQ(FindsService::Result::Status::kModelExecutionDisabledByParam, + result.status); + EXPECT_EQ("Error: Model execution disabled by feature parameter.", + result.message); + callback_called = true; + })); + EXPECT_TRUE(callback_called); + + histogram_tester_.ExpectUniqueSample( + "Finds.Result", + FindsService::Result::Status::kModelExecutionDisabledByParam, 1); +} + } // namespace finds
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index 44a0a6a..3adee10 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -2252,7 +2252,7 @@ { "name": "default-site-instance-groups", "owners": [ "creis@chromium.org", "chrome-security-architecture@google.com" ], - "expiry_milestone": 150 + "expiry_milestone": 170 }, { "name": "defer-os-clipboard-read-call-to-get-type", @@ -2292,7 +2292,7 @@ { "name": "desktop-ua-on-connected-display", "owners": [ "skavuluru@google.com", "clank-large-form-factors@google.com" ], - "expiry_milestone": 150 + "expiry_milestone": 152 }, { "name": "device-posture", @@ -2433,8 +2433,8 @@ { "name": "disable-process-reuse", "owners": [ - "alexmos@google.com", "creis@google.com" ], - "expiry_milestone": 150 + "alexmos@google.com", "creis@google.com", "lbrady@google.com" ], + "expiry_milestone": 170 }, { "name": "disable-u18-feedback-desktop", @@ -3538,8 +3538,8 @@ }, { "name": "enable-isolated-sandboxed-iframes", - "owners": [ "wjmaclean@chromium.org", "alexmos@chromium.org", "creis@chromium.org" ], - "expiry_milestone": 145 + "owners": [ "lbrady@google.com", "alexmos@chromium.org", "creis@chromium.org" ], + "expiry_milestone": 170 }, { "name": "enable-isolated-web-app-allowlist", @@ -5171,7 +5171,7 @@ "slobodan@chromium.org", "//components/autofill/OWNERS" ], - "expiry_milestone": 150 + "expiry_milestone": 160 }, { "name": "glic-actor-cursor", @@ -6351,7 +6351,7 @@ "twellington@chromium.org", "skavuluru@google.com" ], - "expiry_milestone": 150 + "expiry_milestone": 152 }, { "name": "lock-controls-on-tablets-v2", @@ -6359,7 +6359,7 @@ "twellington@chromium.org", "skavuluru@google.com" ], - "expiry_milestone": 150 + "expiry_milestone": 152 }, { "name": "logo-view-refactor", @@ -7297,14 +7297,6 @@ "expiry_milestone": 150 }, { - "name": "open-dragged-links-same-tab", - "owners": [ - "agale@chromium.org", - "top-chrome-desktop-ui@google.com" - ], - "expiry_milestone": 150 - }, - { "name": "open-edit-group-view-by-tapping-title", "owners": [ "achara@google.com", "bling-meridian@google.com" ], "expiry_milestone": 153 @@ -7349,8 +7341,8 @@ }, { "name": "origin-keyed-processes-by-default", - "owners": [ "wjmaclean@chromium.org", "creis@chromium.org", "site-isolation-dev@chromium.org"], - "expiry_milestone": 150 + "owners": [ "lbrady@google.com", "creis@chromium.org", "site-isolation-dev@chromium.org"], + "expiry_milestone": 170 }, { "name": "overlay-scrollbars", @@ -8785,11 +8777,11 @@ "top-chrome-desktop-ui@google.com", "//chrome/browser/startup/OWNERS" ], - "expiry_milestone": 150 + "expiry_milestone": 154 }, { "name": "strict-origin-isolation", - "owners": [ "wjmaclean@chromium.org", "alexmos@chromium.org", "creis@chromium.org" ], + "owners": [ "lbrady@google.com", "alexmos@chromium.org", "creis@chromium.org" ], // This can be used to opt in to origin isolation which isolates full // origins rather than sites. Note that this breaks document.domain and is // therefore unlikely to ship anytime soon, but this allows experimenting @@ -9135,7 +9127,7 @@ { "name" : "toolbar-phone-animation-refactor", "owners": [ "skavuluru@google.com", "nemco@google.com", "clank-large-form-factors@google.com" ], - "expiry_milestone" : 150 + "expiry_milestone" : 160 }, { "name": "toolbar-snapshot-refactor", @@ -9774,11 +9766,6 @@ "expiry_milestone": 160 }, { - "name": "web-serial-wired-devices-android", - "owners": ["xutan@chromium.org", "ovn@google.com", "lt-web-apps-team@google.com"], - "expiry_milestone": 150 - }, - { "name": "webcrypto-pqc", "owners": [ "hchao@chromium.org", "chrome-secure-web-and-net@chromium.org" ], "expiry_milestone": 152
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 532883f..07d79ec 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -4229,11 +4229,6 @@ "allows assistive technologies to access only accessibility nodes that are " "on-screen"; -inline constexpr char kOpenDraggedLinksSameTabName[] = - "Open Dragged Links in the Same Tab"; -inline constexpr char kOpenDraggedLinksSameTabDescription[] = - "Allows users to drag a single link to a tab to open in that tab."; - inline constexpr char kDefaultSiteInstanceGroupsName[] = "Default SiteInstanceGroups"; inline constexpr char kDefaultSiteInstanceGroupsDescription[] = @@ -6131,11 +6126,6 @@ inline constexpr char kWebFeedOnboardingDescription[] = "Helps the user understand how to use the web feed."; -inline constexpr char kWebSerialWiredDevicesAndroidName[] = - "Web Serial API for Wired Devices"; -inline constexpr char kWebSerialWiredDevicesAndroidDescription[] = - "Provides a way for websites to interact with wired serial devices"; - inline constexpr char kXplatSyncedSetupName[] = "Cross-platform synced setup"; inline constexpr char kXplatSyncedSetupDescription[] = "Enables the Cross-platform synced setup feature.";
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 2d80ae66..e589593 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
@@ -1052,7 +1052,7 @@ public static final CachedFlag sLockTopControlsOnLargeTabletsV2 = newCachedFlag( LOCK_TOP_CONTROLS_ON_LARGE_TABLETS_V2, - /* defaultValue= */ false, + /* defaultValue= */ true, /* defaultValueInTests= */ true); public static final CachedFlag sLogoViewRefactor = newCachedFlag( @@ -1474,7 +1474,7 @@ public static final MutableFlagWithSafeDefault sInlinePdfV2 = newMutableFlagWithSafeDefault(INLINE_PDF_V2, false); public static final MutableFlagWithSafeDefault sLockTopControlsOnLargeTablets = - newMutableFlagWithSafeDefault(LOCK_TOP_CONTROLS_ON_LARGE_TABLETS, false); + newMutableFlagWithSafeDefault(LOCK_TOP_CONTROLS_ON_LARGE_TABLETS, true); public static final MutableFlagWithSafeDefault sMediaIndicatorsAndroid = newMutableFlagWithSafeDefault(MEDIA_INDICATORS_ANDROID, true); public static final MutableFlagWithSafeDefault sNoVisibleHintForDifferentTLD =
diff --git a/chrome/browser/glic/android/java/src/org/chromium/chrome/browser/glic/GlicToolbarButtonController.java b/chrome/browser/glic/android/java/src/org/chromium/chrome/browser/glic/GlicToolbarButtonController.java index 2594a7df..c1d38d8 100644 --- a/chrome/browser/glic/android/java/src/org/chromium/chrome/browser/glic/GlicToolbarButtonController.java +++ b/chrome/browser/glic/android/java/src/org/chromium/chrome/browser/glic/GlicToolbarButtonController.java
@@ -6,6 +6,7 @@ import static org.chromium.build.NullUtil.assumeNonNull; +import android.app.Activity; import android.content.Context; import android.content.res.ColorStateList; import android.graphics.Color; @@ -91,7 +92,7 @@ void onClick(boolean preventClose); } - private final Context mContext; + private final Activity mActivity; private final GlicButtonDelegate mToggleGlicCallback; private final Supplier<@Nullable Tracker> mTrackerSupplier; private final Supplier<@Nullable ChromeAndroidTask> mTaskSupplier; @@ -112,7 +113,7 @@ private @Nullable AnchoredPopupWindow mMenuWindow; /** - * @param context The Android context. + * @param activity The Android activity. * @param activeTabSupplier The currently active tab. * @param toggleGlicCallback Callback to run when the button is clicked to open Glic. * @param trackerSupplier Supplier for the current profile tracker. @@ -121,7 +122,7 @@ * @param tabModelSelectorSupplier Supplier for the TabModelSelector. */ public GlicToolbarButtonController( - Context context, + Activity activity, Supplier<@Nullable Tab> activeTabSupplier, GlicButtonDelegate toggleGlicCallback, Supplier<@Nullable Tracker> trackerSupplier, @@ -134,12 +135,13 @@ activeTabSupplier, /* modalDialogManager= */ null, new ButtonSpec.Builder( - AppCompatResources.getDrawable(context, R.drawable.ic_spark_24dp), - context.getString(R.string.glic_button_entrypoint_ask_gemini_label), + AppCompatResources.getDrawable(activity, R.drawable.ic_spark_24dp), + activity.getString( + R.string.glic_button_entrypoint_ask_gemini_label), /* supportsTinting= */ true) .setButtonVariant(AdaptiveToolbarButtonVariant.GLIC) .build()); - mContext = context; + mActivity = activity; mToggleGlicCallback = toggleGlicCallback; mTrackerSupplier = trackerSupplier; mTaskSupplier = taskSupplier; @@ -147,8 +149,8 @@ mTabModelSelectorSupplier = tabModelSelectorSupplier; mDefaultSpec = mButtonData.getButtonSpec(); Drawable collapsedDrawable = - AppCompatResources.getDrawable(context, R.drawable.glic_dirty_dot_spark); - mWorkingSpec = createWorkingSpec(context); + AppCompatResources.getDrawable(activity, R.drawable.glic_dirty_dot_spark); + mWorkingSpec = createWorkingSpec(activity); mReviewSpec = new ButtonSpec.Builder(createReviewSpec()) .setCollapsedDrawable(collapsedDrawable) @@ -340,8 +342,11 @@ ChromeAndroidTask task = mTaskSupplier.get(); if (task == null) return; - long browserWindowPtr = task.getOrCreateNativeBrowserWindowPtr(mCurrentProfile); - boolean isOpen = mCurrentGlicService.isPanelShowingForBrowser(browserWindowPtr); + long browserWindowPtr = task.getNativeBrowserWindowPtr(mCurrentProfile, mActivity); + boolean isOpen = false; + if (browserWindowPtr != 0) { + isOpen = mCurrentGlicService.isPanelShowingForBrowser(browserWindowPtr); + } if (mIsPanelOpen != isOpen) { mIsPanelOpen = isOpen; notifyObservers(true); @@ -534,7 +539,7 @@ @Override protected @Nullable IphCommandBuilder getIphCommandBuilder(Tab tab) { return new IphCommandBuilder( - mContext.getResources(), + mActivity.getResources(), FeatureConstants.GLIC_PROMO_ANDROID_FEATURE, R.string.iph_glic_promo_text, R.string.iph_glic_promo_accessibility_text);
diff --git a/chrome/browser/glic/android/java/src/org/chromium/chrome/browser/glic/GlicToolbarButtonControllerTest.java b/chrome/browser/glic/android/java/src/org/chromium/chrome/browser/glic/GlicToolbarButtonControllerTest.java index 75403d4..7b8fd29 100644 --- a/chrome/browser/glic/android/java/src/org/chromium/chrome/browser/glic/GlicToolbarButtonControllerTest.java +++ b/chrome/browser/glic/android/java/src/org/chromium/chrome/browser/glic/GlicToolbarButtonControllerTest.java
@@ -11,6 +11,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.app.Activity; import android.content.Context; import android.graphics.drawable.LayerDrawable; import android.view.View; @@ -25,6 +26,7 @@ import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; +import org.robolectric.Robolectric; import org.chromium.base.ContextUtils; import org.chromium.base.supplier.ObservableSuppliers; @@ -75,12 +77,15 @@ @Mock private GlicEnabling.Natives mGlicEnablingJniMock; @Captor private ArgumentCaptor<ActorKeyedService.Observer> mActorObserverCaptor; + private Activity mActivity; private Context mContext; private GlicToolbarButtonController mController; @Before public void setUp() { mContext = ContextUtils.getApplicationContext(); + mActivity = Robolectric.setupActivity(Activity.class); + when(mTab.getProfile()).thenReturn(mProfile); when(mTab.getUrl()).thenReturn(JUnitTestGURLs.EXAMPLE_URL); ActorKeyedServiceFactory.setForTesting(mActorService); @@ -95,7 +100,7 @@ when(mGlicEnablingJniMock.isEnabledForProfile(any())).thenReturn(true); mController = new GlicToolbarButtonController( - mContext, + mActivity, () -> mTab, mToggleGlicCallback, () -> mTracker, @@ -104,6 +109,7 @@ () -> mTabModelSelector); } + @Test public void testButtonData() { ButtonData buttonData = mController.get(mTab); @@ -326,12 +332,12 @@ @Test public void testIsPanelOpen_Initial() { ChromeAndroidTask task = mock(ChromeAndroidTask.class); - when(task.getOrCreateNativeBrowserWindowPtr(mProfile)).thenReturn(123L); + when(task.getNativeBrowserWindowPtr(mProfile, mActivity)).thenReturn(123L); when(mGlicKeyedService.isPanelShowingForBrowser(123L)).thenReturn(true); GlicToolbarButtonController controller = new GlicToolbarButtonController( - mContext, + mActivity, () -> mTab, mToggleGlicCallback, () -> mTracker, @@ -347,12 +353,12 @@ @Test public void testIsPanelOpen_GlobalShowHide() { ChromeAndroidTask task = mock(ChromeAndroidTask.class); - when(task.getOrCreateNativeBrowserWindowPtr(mProfile)).thenReturn(123L); + when(task.getNativeBrowserWindowPtr(mProfile, mActivity)).thenReturn(123L); when(mGlicKeyedService.isPanelShowingForBrowser(123L)).thenReturn(true); GlicToolbarButtonController controller = new GlicToolbarButtonController( - mContext, + mActivity, () -> mTab, mToggleGlicCallback, () -> mTracker,
diff --git a/chrome/browser/glic/experimental_opt_in/glic_experimental_opt_in_dialog_browsertest.cc b/chrome/browser/glic/experimental_opt_in/glic_experimental_opt_in_dialog_browsertest.cc index cac00d61..5374236 100644 --- a/chrome/browser/glic/experimental_opt_in/glic_experimental_opt_in_dialog_browsertest.cc +++ b/chrome/browser/glic/experimental_opt_in/glic_experimental_opt_in_dialog_browsertest.cc
@@ -22,6 +22,8 @@ class GlicExperimentalOptInTest : public GlicBrowserTest { public: + // These tests don't run on Android, so allow browser() use. + using PlatformBrowserTest::browser; GlicExperimentalOptInTest() { feature_list_.InitAndEnableFeature(features::kGlicExperimentalTriggering); }
diff --git a/chrome/browser/glic/glic_context_menu_browsertest.cc b/chrome/browser/glic/glic_context_menu_browsertest.cc index 9088b1d7..e4215d4 100644 --- a/chrome/browser/glic/glic_context_menu_browsertest.cc +++ b/chrome/browser/glic/glic_context_menu_browsertest.cc
@@ -19,6 +19,8 @@ class GlicContextMenuBrowserTestBase : public GlicBrowserTest { protected: + // These tests don't run on Android, so allow browser() use. + using PlatformBrowserTest::browser; std::unique_ptr<TestRenderViewContextMenu> CreateContextMenu() { content::WebContents* web_contents = browser()->tab_strip_model()->GetActiveWebContents();
diff --git a/chrome/browser/glic/host/glic_api_browsertest.cc b/chrome/browser/glic/host/glic_api_browsertest.cc index fa785e9..98172ce 100644 --- a/chrome/browser/glic/host/glic_api_browsertest.cc +++ b/chrome/browser/glic/host/glic_api_browsertest.cc
@@ -181,8 +181,6 @@ "GlicApiTestUserStatusCheckTest", "GlicApiTestWithOneTabMoreDebounceDelay", "GlicGetHostCapabilityApiTest", - "GlicApiTestWithDefaultTabContextDisabled", - "GlicApiTestWithDefaultTabContextEnabled", "GlicApiTestWithMqlsIdGetterEnabled", "GlicApiTestWithMqlsIdGetterDisabled", "GlicApiTestRuntimeFeatureOff", @@ -361,30 +359,6 @@ base::test::ScopedFeatureList scoped_feature_list_; }; -class GlicApiTestWithDefaultTabContextEnabled : public GlicApiTestWithOneTab { - public: - GlicApiTestWithDefaultTabContextEnabled() { - feature_list_.InitWithFeatures({features::kGlicDefaultTabContextSetting}, - {}); - } - - void SetUpOnMainThread() override { GlicApiTest::SetUpOnMainThread(); } - - private: - base::test::ScopedFeatureList feature_list_; -}; - -class GlicApiTestWithDefaultTabContextDisabled : public GlicApiTestWithOneTab { - public: - GlicApiTestWithDefaultTabContextDisabled() { - feature_list_.InitWithFeatures({}, - {features::kGlicDefaultTabContextSetting}); - } - - private: - base::test::ScopedFeatureList feature_list_; -}; - class GlicApiTestWithWebActuationSettingEnabled : public GlicApiTestWithOneTab { public: GlicApiTestWithWebActuationSettingEnabled() { @@ -751,35 +725,6 @@ AssertAllTestsRegistered(GetTestSuiteNames()); } -IN_PROC_BROWSER_TEST_P(GlicApiTestWithDefaultTabContextDisabled, - testDefaultTabContextApiIsUndefinedWhenFeatureDisabled) { - ExecuteJsTest(); -} - -IN_PROC_BROWSER_TEST_P(GlicApiTestWithDefaultTabContextEnabled, - testGetDefaultTabContextPermissionState) { - // Default kGlicDefaultTabContextEnabled value is true. - NavigateTabAndOpenGlic(); - ExecuteJsTest(); - browser()->profile()->GetPrefs()->SetBoolean( - prefs::kGlicDefaultTabContextEnabled, false); - ContinueJsTest(); -} - -IN_PROC_BROWSER_TEST_P(GlicApiTestWithDefaultTabContextEnabled, testPinOnBind) { - NavigateTabAndOpenGlic(); - ExecuteJsTest(); -} - -IN_PROC_BROWSER_TEST_P(GlicApiTestWithDefaultTabContextEnabled, - testNoPinOnBindWhenSettingOff) { - browser()->profile()->GetPrefs()->SetBoolean( - prefs::kGlicDefaultTabContextEnabled, false); - - NavigateTabAndOpenGlic(); - ExecuteJsTest(); -} - IN_PROC_BROWSER_TEST_P(GlicApiTestWithWebActuationSettingDisabled, testWebActuationSettingIsUndefinedWhenFeatureDisabled) { ExecuteJsTest(); @@ -3704,14 +3649,6 @@ DefaultTestParamSet(), &WithTestParams::PrintTestVariant); INSTANTIATE_TEST_SUITE_P(, - GlicApiTestWithDefaultTabContextEnabled, - DefaultTestParamSet(), - &WithTestParams::PrintTestVariant); -INSTANTIATE_TEST_SUITE_P(, - GlicApiTestWithDefaultTabContextDisabled, - DefaultTestParamSet(), - &WithTestParams::PrintTestVariant); -INSTANTIATE_TEST_SUITE_P(, GlicApiTestWithMqlsIdGetterEnabled, DefaultTestParamSet(), &WithTestParams::PrintTestVariant);
diff --git a/chrome/browser/glic/host/glic_internals.mojom b/chrome/browser/glic/host/glic_internals.mojom index 25136e8..ec7ac67 100644 --- a/chrome/browser/glic/host/glic_internals.mojom +++ b/chrome/browser/glic/host/glic_internals.mojom
@@ -33,6 +33,7 @@ FreOverride fre_override = kUnspecified; bool wait_for_panel_open; InvokeTargetSurface surface; + ActuationTarget actuation_target; }; // Page handler for the glic internals WebUI.
diff --git a/chrome/browser/glic/host/glic_internals_page_handler.cc b/chrome/browser/glic/host/glic_internals_page_handler.cc index cb042dd..9147b1e 100644 --- a/chrome/browser/glic/host/glic_internals_page_handler.cc +++ b/chrome/browser/glic/host/glic_internals_page_handler.cc
@@ -215,6 +215,7 @@ options.timeout = mojo_options->timeout; options.fre_override = mojo_options->fre_override; options.wait_for_panel_open = mojo_options->wait_for_panel_open; + options.target.actuation_target = mojo_options->actuation_target; switch (mojo_options->allowed_inflight_navigation) { case mojom::AllowedInflightNavigation::kSameDomain:
diff --git a/chrome/browser/glic/host/new_glic_api_browsertest.cc b/chrome/browser/glic/host/new_glic_api_browsertest.cc index c94b381..1fdf877 100644 --- a/chrome/browser/glic/host/new_glic_api_browsertest.cc +++ b/chrome/browser/glic/host/new_glic_api_browsertest.cc
@@ -131,6 +131,8 @@ "NewGlicApiTestWithPixelOutput", "NewGlicApiTestWithGeminiActOnWebPolicy", "NewGlicApiMultiProfileTest", + "NewGlicApiTestWithDefaultTabContextDisabled", + "NewGlicApiTestWithDefaultTabContextEnabled", #if !BUILDFLAG(IS_ANDROID) "NewGlicApiTestWithSkills", #endif @@ -241,8 +243,8 @@ #if !BUILDFLAG(IS_ANDROID) void CloseMainBrowserWithIncognitoKeepAlive() { - CreateIncognitoBrowser(); - CloseBrowserAsynchronously(browser()); + PlatformBrowserTest::CreateIncognitoBrowser(); + CloseBrowserAsynchronously(GetBrowserWindowInterface()); } #endif @@ -260,7 +262,7 @@ profile_manager->GenerateNextProfileDirectoryPath(); Profile& new_profile = profiles::testing::CreateProfileSync(profile_manager, new_path); - return CreateBrowser(&new_profile); + return PlatformBrowserTest::CreateBrowser(&new_profile); #else NOTREACHED(); #endif @@ -299,6 +301,58 @@ } }; +class NewGlicApiTestWithDefaultTabContextDisabled : public NewGlicApiTest { + public: + NewGlicApiTestWithDefaultTabContextDisabled() { + feature_list_.InitWithFeatures({}, + {features::kGlicDefaultTabContextSetting}); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +IN_PROC_BROWSER_TEST_P(NewGlicApiTestWithDefaultTabContextDisabled, + testDefaultTabContextApiIsUndefinedWhenFeatureDisabled) { + ASSERT_OK(OpenGlicForActiveTab()); + ExecuteJsTest(); +} + +class NewGlicApiTestWithDefaultTabContextEnabled : public NewGlicApiTest { + public: + NewGlicApiTestWithDefaultTabContextEnabled() { + feature_list_.InitWithFeatures({features::kGlicDefaultTabContextSetting}, + {}); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +IN_PROC_BROWSER_TEST_P(NewGlicApiTestWithDefaultTabContextEnabled, + testGetDefaultTabContextPermissionState) { + ASSERT_OK(OpenGlicForActiveTab()); + ExecuteJsTest(); + GetProfile()->GetPrefs()->SetBoolean(prefs::kGlicDefaultTabContextEnabled, + false); + ContinueJsTest(); +} + +IN_PROC_BROWSER_TEST_P(NewGlicApiTestWithDefaultTabContextEnabled, + testPinOnBind) { + ASSERT_OK(OpenGlicForActiveTab()); + ExecuteJsTest(); +} + +IN_PROC_BROWSER_TEST_P(NewGlicApiTestWithDefaultTabContextEnabled, + testNoPinOnBindWhenSettingOff) { + GetProfile()->GetPrefs()->SetBoolean(prefs::kGlicDefaultTabContextEnabled, + false); + + ASSERT_OK(OpenGlicForActiveTab()); + ExecuteJsTest(); +} + IN_PROC_BROWSER_TEST_P(NewGlicApiTestWithWebContentsWarming, testWebClientReadyOnPreload) { auto container = @@ -1120,7 +1174,7 @@ #if !BUILDFLAG(IS_ANDROID) // TODO(harringtond): Enable skills on Android. ASSERT_OK_AND_ASSIGN(auto* instance, OpenGlicForActiveTabAndDetach()); BrowserWindowInterface* browser_to_close = GetBrowserWindowInterface(); - CreateIncognitoBrowser(); + PlatformBrowserTest::CreateIncognitoBrowser(); CloseBrowserAsynchronously(browser_to_close); ui_test_utils::WaitForBrowserToClose(browser_to_close); @@ -1173,6 +1227,16 @@ DefaultTestParamSet(), &WithTestParams::PrintTestVariant); +INSTANTIATE_TEST_SUITE_P(, + NewGlicApiTestWithDefaultTabContextDisabled, + DefaultTestParamSet(), + &WithTestParams::PrintTestVariant); + +INSTANTIATE_TEST_SUITE_P(, + NewGlicApiTestWithDefaultTabContextEnabled, + DefaultTestParamSet(), + &WithTestParams::PrintTestVariant); + // Skills are not supported yet on Android. #if !BUILDFLAG(IS_ANDROID) INSTANTIATE_TEST_SUITE_P(, @@ -1188,6 +1252,10 @@ GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST( NewGlicApiTestWithGeminiActOnWebPolicy); GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(NewGlicApiMultiProfileTest); +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST( + NewGlicApiTestWithDefaultTabContextDisabled); +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST( + NewGlicApiTestWithDefaultTabContextEnabled); #if !BUILDFLAG(IS_ANDROID) GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(NewGlicApiTestWithSkills); #endif
diff --git a/chrome/browser/glic/public/glic_enabling.cc b/chrome/browser/glic/public/glic_enabling.cc index 43b6282..74e0a9b 100644 --- a/chrome/browser/glic/public/glic_enabling.cc +++ b/chrome/browser/glic/public/glic_enabling.cc
@@ -777,6 +777,10 @@ } prefs::FreStatus GlicEnabling::GetCompletedFre() const { + if (base::FeatureList::IsEnabled( + features::kGlicExperimentalTriggeringOptInBypass)) { + return prefs::FreStatus::kCompleted; + } return static_cast<prefs::FreStatus>( profile_->GetPrefs()->GetInteger(prefs::kGlicCompletedFre)); } @@ -787,6 +791,10 @@ } bool GlicEnabling::GetUserEnabledActuationOnWeb() const { + if (base::FeatureList::IsEnabled( + features::kGlicExperimentalTriggeringOptInBypass)) { + return true; + } return profile_->GetPrefs()->GetBoolean( prefs::kGlicUserEnabledActuationOnWeb); } @@ -803,6 +811,10 @@ } bool GlicEnabling::GetExperimentalTriggeringEnabled() const { + if (base::FeatureList::IsEnabled( + features::kGlicExperimentalTriggeringOptInBypass)) { + return true; + } return profile_->GetPrefs()->GetBoolean( prefs::kGlicExperimentalTriggeringEnabled); }
diff --git a/chrome/browser/glic/public/glic_enabling_unittest.cc b/chrome/browser/glic/public/glic_enabling_unittest.cc index 3124b92..1057ac0 100644 --- a/chrome/browser/glic/public/glic_enabling_unittest.cc +++ b/chrome/browser/glic/public/glic_enabling_unittest.cc
@@ -769,5 +769,91 @@ EXPECT_TRUE(callback_called); } +TEST_F(GlicEnablingProfileEligibilityTest, + GetExperimentalTriggeringState_AllDisabled) { + base::test::ScopedFeatureList feature_list; + feature_list.InitWithFeatures( + /*enabled_features=*/{}, + /*disabled_features=*/{features::kGlicExperimentalTriggering, + features::kGlicExperimentalTriggeringOptInBypass}); + + auto& enabling = glic::GlicKeyedService::Get(profile())->enabling(); + EXPECT_EQ(enabling.GetExperimentalTriggeringState(), + syncer::DeviceInfo::GlicExperimentalTriggeringState::kUnavailable); +} + +TEST_F(GlicEnablingProfileEligibilityTest, + GetExperimentalTriggeringState_BypassEnabled_MainDisabled) { + base::test::ScopedFeatureList feature_list; + feature_list.InitWithFeatures( + /*enabled_features=*/{features::kGlicExperimentalTriggeringOptInBypass}, + /*disabled_features=*/{features::kGlicExperimentalTriggering}); + + auto& enabling = glic::GlicKeyedService::Get(profile())->enabling(); + EXPECT_EQ(enabling.GetExperimentalTriggeringState(), + syncer::DeviceInfo::GlicExperimentalTriggeringState::kUnavailable); +} + +TEST_F(GlicEnablingProfileEligibilityTest, + GetExperimentalTriggeringState_MainEnabled_BypassDisabled_NeedsOptIn) { + base::test::ScopedFeatureList feature_list; + feature_list.InitWithFeatures( + /*enabled_features=*/{features::kGlicExperimentalTriggering}, + /*disabled_features=*/{features::kGlicExperimentalTriggeringOptInBypass}); + + auto& enabling = glic::GlicKeyedService::Get(profile())->enabling(); + + // Ensure we are not opted in. + enabling.SetCompletedFre(prefs::FreStatus::kIncomplete); + enabling.SetUserEnabledActuationOnWeb(false); + enabling.SetExperimentalTriggeringEnabled(false); + + EXPECT_EQ(enabling.GetExperimentalTriggeringState(), + syncer::DeviceInfo::GlicExperimentalTriggeringState::kNeedsOptIn); +} + +TEST_F(GlicEnablingProfileEligibilityTest, + GetExperimentalTriggeringState_MainEnabled_BypassDisabled_Ready) { + base::test::ScopedFeatureList feature_list; + feature_list.InitWithFeatures( + /*enabled_features=*/{features::kGlicExperimentalTriggering}, + /*disabled_features=*/{features::kGlicExperimentalTriggeringOptInBypass}); + + auto& enabling = glic::GlicKeyedService::Get(profile())->enabling(); + + // Opt-in manually. + enabling.SetCompletedFre(prefs::FreStatus::kCompleted); + enabling.SetUserEnabledActuationOnWeb(true); + enabling.SetExperimentalTriggeringEnabled(true); + + EXPECT_EQ(enabling.GetExperimentalTriggeringState(), + syncer::DeviceInfo::GlicExperimentalTriggeringState::kReady); +} + +TEST_F(GlicEnablingProfileEligibilityTest, + GetExperimentalTriggeringState_MainEnabled_BypassEnabled) { + base::test::ScopedFeatureList feature_list; + feature_list.InitWithFeatures( + /*enabled_features=*/{features::kGlicExperimentalTriggering, + features::kGlicExperimentalTriggeringOptInBypass}, + /*disabled_features=*/{}); + + auto& enabling = glic::GlicKeyedService::Get(profile())->enabling(); + + // Ensure prefs are NOT opted in. + enabling.SetCompletedFre(prefs::FreStatus::kIncomplete); + enabling.SetUserEnabledActuationOnWeb(false); + enabling.SetExperimentalTriggeringEnabled(false); + + // Bypass should make it ready. + EXPECT_EQ(enabling.GetExperimentalTriggeringState(), + syncer::DeviceInfo::GlicExperimentalTriggeringState::kReady); + + // Verify helper functions return true. + EXPECT_TRUE(enabling.HasConsented()); + EXPECT_TRUE(enabling.GetUserEnabledActuationOnWeb()); + EXPECT_TRUE(enabling.GetExperimentalTriggeringEnabled()); +} + } // namespace } // namespace glic
diff --git a/chrome/browser/glic/public/glic_invoke_options.h b/chrome/browser/glic/public/glic_invoke_options.h index 37fb9159..620c25c 100644 --- a/chrome/browser/glic/public/glic_invoke_options.h +++ b/chrome/browser/glic/public/glic_invoke_options.h
@@ -238,6 +238,10 @@ // Callback for when the conversation ID is known. base::OnceCallback<void(std::string)> on_conversation_id_ready; + + // Whether or not to show the panel on invocation. Doesn't prevent the panel + // from being shown later and has no impact if the panel is already showing. + bool show_panel = true; }; } // namespace glic
diff --git a/chrome/browser/glic/service/glic_instance_coordinator_browsertest.cc b/chrome/browser/glic/service/glic_instance_coordinator_browsertest.cc index 3dbf9d15..4d37a881 100644 --- a/chrome/browser/glic/service/glic_instance_coordinator_browsertest.cc +++ b/chrome/browser/glic/service/glic_instance_coordinator_browsertest.cc
@@ -252,7 +252,7 @@ TabRestoreServiceFactory::GetForProfile(GetProfile()); service->RestoreMostRecentEntry(live_tab_context); #else - chrome::RestoreTab(browser()); + chrome::RestoreTab(PlatformBrowserTest::browser()); #endif } TestResult<> CloseGlicForTabAndWait(tabs::TabInterface* tab) { @@ -1003,6 +1003,37 @@ EXPECT_TRUE(instance->IsActuating()); } +IN_PROC_BROWSER_TEST_F(GlicInstanceCoordinatorActorTaskTest, + OnTabAddedToTaskDoesNotShowPanelIfSuppressed) { + ASSERT_OK_AND_ASSIGN(GlicInstanceImpl * instance, OpenGlicForActiveTab()); + + tabs::TabInterface* tab = GetTabListInterface()->GetActiveTab(); + + PreventDeletionOnClose(instance); + instance->Close(EmbedderKey(tab), CloseOptions()); + ASSERT_OK( + WaitForSidePanelState(tab, GlicSidePanelCoordinator::State::kClosed)); + + EXPECT_FALSE(instance->IsShowing()); + + instance->SuppressShowOnNextTabAddedToTask(true); + + actor::TaskId task_id(123); + instance->OnTabAddedToTask(task_id, tab->GetHandle()); + + EXPECT_FALSE(instance->IsShowing()); + EXPECT_OK( + WaitForSidePanelState(tab, GlicSidePanelCoordinator::State::kClosed)); + + tabs::TabInterface* tab2 = CreateAndActivateTab(GURL("about:blank")); + + instance->OnTabAddedToTask(task_id, tab2->GetHandle()); + + EXPECT_TRUE(instance->IsShowing()); + EXPECT_OK( + WaitForSidePanelState(tab2, GlicSidePanelCoordinator::State::kShown)); +} + class GlicInstanceCoordinatorHibernationTest : public GlicInstanceCoordinatorBrowserTest { public: @@ -1382,7 +1413,7 @@ IN_PROC_BROWSER_TEST_F(GlicInstanceCoordinatorBrowserTest, ResolveTargetSurfaceCreatesNewWindow) { Profile* incognito_profile = - browser()->profile()->GetPrimaryOTRProfile(/*create_if_needed=*/true); + GetProfile()->GetPrimaryOTRProfile(/*create_if_needed=*/true); // Initially there should be no browsers for incognito profile. EXPECT_EQ(ProfileBrowserCollection::GetForProfile(incognito_profile) @@ -1766,9 +1797,7 @@ task->Start(done_future.GetCallback()); // Destroy the tab. - browser()->tab_strip_model()->CloseWebContentsAt( - browser()->tab_strip_model()->GetIndexOfWebContents(web_contents), - TabCloseTypes::CLOSE_USER_GESTURE); + GetTabListInterface()->CloseTab(tab->GetHandle()); // Wait for the task to complete. It should complete when the timer fires, // and it should not crash.
diff --git a/chrome/browser/glic/service/glic_instance_coordinator_impl.cc b/chrome/browser/glic/service/glic_instance_coordinator_impl.cc index 4338e75..cc26d63 100644 --- a/chrome/browser/glic/service/glic_instance_coordinator_impl.cc +++ b/chrome/browser/glic/service/glic_instance_coordinator_impl.cc
@@ -1041,7 +1041,8 @@ side_panel_options.prefer_peek = true; bound_instance->Show(ShowOptions{side_panel_options}); } else { - bound_instance->BindTabWithoutShowing(tab, /*pin_on_bind=*/false); + bound_instance->BindTabWithoutShowing(tab, GlicPinTrigger::kUnknown, + /*pin_on_bind=*/false); } }
diff --git a/chrome/browser/glic/service/glic_instance_impl.cc b/chrome/browser/glic/service/glic_instance_impl.cc index 67f7626..762f580 100644 --- a/chrome/browser/glic/service/glic_instance_impl.cc +++ b/chrome/browser/glic/service/glic_instance_impl.cc
@@ -1297,8 +1297,13 @@ } void GlicInstanceImpl::BindTabWithoutShowing(tabs::TabInterface* tab, + GlicPinTrigger pin_trigger, bool pin_on_bind) { - BindTab(tab, GlicPinTrigger::kUnknown, pin_on_bind); + BindTab(tab, pin_trigger, pin_on_bind); +} + +void GlicInstanceImpl::SuppressShowOnNextTabAddedToTask(bool suppress) { + suppress_show_on_tab_added_to_task_ = suppress; } void GlicInstanceImpl::MaybeInitializeHiddenClient( @@ -1614,6 +1619,9 @@ IsDetached()) { side_panel_options.pin_trigger = GlicPinTrigger::kActuation; ShowInactiveSidePanelEmbedderFor(side_panel_options); + } else if (suppress_show_on_tab_added_to_task_) { + BindTab(tab, GlicPinTrigger::kActuation, /*pin_on_bind=*/true); + suppress_show_on_tab_added_to_task_ = false; } else { Show(ShowOptions{side_panel_options}); }
diff --git a/chrome/browser/glic/service/glic_instance_impl.h b/chrome/browser/glic/service/glic_instance_impl.h index f36d459..e11cd62f 100644 --- a/chrome/browser/glic/service/glic_instance_impl.h +++ b/chrome/browser/glic/service/glic_instance_impl.h
@@ -133,7 +133,10 @@ void Hibernate(); void Shutdown(); void CloseInstanceAndShutdown(); - void BindTabWithoutShowing(tabs::TabInterface* tab, bool pin_on_bind); + void BindTabWithoutShowing(tabs::TabInterface* tab, + GlicPinTrigger pin_trigger, + bool pin_on_bind); + void SuppressShowOnNextTabAddedToTask(bool suppress); // Initializes the instance for a hidden client. No-op if the instance already // has webui contents. void MaybeInitializeHiddenClient(mojom::InvocationSource invocation_source, @@ -458,6 +461,9 @@ // when the user clicks a link inside the Glic panel. bool is_creating_tab_from_glic_panel_link_click_ = false; + // True if we should suppress showing the panel when a tab is added to a task. + bool suppress_show_on_tab_added_to_task_ = false; + base::WeakPtrFactory<GlicInstanceImpl> weak_ptr_factory_{this}; };
diff --git a/chrome/browser/glic/service/glic_invoke_handler.cc b/chrome/browser/glic/service/glic_invoke_handler.cc index 19603962..f0cff8df 100644 --- a/chrome/browser/glic/service/glic_invoke_handler.cc +++ b/chrome/browser/glic/service/glic_invoke_handler.cc
@@ -187,8 +187,12 @@ show_options.fre_override = options_.fre_override; } - tasks.push_back( - std::make_unique<ShowInstanceTask>(&*instance_, show_options)); + if (!auto_submit_passkey_.has_value() || auto_submit_options_.show_panel) { + tasks.push_back( + std::make_unique<ShowInstanceTask>(&*instance_, show_options)); + } else { + tasks.push_back(std::make_unique<SetupHiddenPanelTask>(&*instance_, tab_)); + } tasks.push_back(std::make_unique<MaybeInitializeHiddenClientTask>( &*instance_, options_.invocation_source, options_.fre_override)); tasks.push_back( @@ -276,6 +280,7 @@ void GlicInvokeHandler::OnError(GlicInvokeError error) { timeout_timer_.Stop(); + instance_->SuppressShowOnNextTabAddedToTask(false); if (main_task_) { main_task_->NotifySequenceCompleted(/*success=*/false); }
diff --git a/chrome/browser/glic/service/glic_invoke_task.cc b/chrome/browser/glic/service/glic_invoke_task.cc index 9e7ad7cf..dd684d9 100644 --- a/chrome/browser/glic/service/glic_invoke_task.cc +++ b/chrome/browser/glic/service/glic_invoke_task.cc
@@ -102,6 +102,19 @@ std::move(done_callback).Run(); } +SetupHiddenPanelTask::SetupHiddenPanelTask(GlicInstanceImpl* instance, + tabs::TabInterface* tab) + : instance_(instance), tab_(tab) {} + +SetupHiddenPanelTask::~SetupHiddenPanelTask() = default; + +void SetupHiddenPanelTask::Start(base::OnceClosure done_callback) { + instance_->SuppressShowOnNextTabAddedToTask(true); + instance_->BindTabWithoutShowing(tab_, GlicPinTrigger::kActuation, + /*pin_on_bind=*/true); + std::move(done_callback).Run(); +} + MaybeInitializeHiddenClientTask::MaybeInitializeHiddenClientTask( GlicInstanceImpl* instance, mojom::InvocationSource invocation_source,
diff --git a/chrome/browser/glic/service/glic_invoke_task.h b/chrome/browser/glic/service/glic_invoke_task.h index c249a5a..453807aa 100644 --- a/chrome/browser/glic/service/glic_invoke_task.h +++ b/chrome/browser/glic/service/glic_invoke_task.h
@@ -102,6 +102,18 @@ ShowOptions options_; }; +// Task that sets up the instance for a hidden panel. +class SetupHiddenPanelTask : public GlicInvokeTask { + public: + SetupHiddenPanelTask(GlicInstanceImpl* instance, tabs::TabInterface* tab); + ~SetupHiddenPanelTask() override; + void Start(base::OnceClosure done_callback) override; + + private: + raw_ptr<GlicInstanceImpl> instance_; + raw_ptr<tabs::TabInterface> tab_; +}; + class MaybeInitializeHiddenClientTask : public GlicInvokeTask { public: MaybeInitializeHiddenClientTask(GlicInstanceImpl* instance,
diff --git a/chrome/browser/glic/suggestions/contextual_cueing_helper.cc b/chrome/browser/glic/suggestions/contextual_cueing_helper.cc index c595347..2435a42 100644 --- a/chrome/browser/glic/suggestions/contextual_cueing_helper.cc +++ b/chrome/browser/glic/suggestions/contextual_cueing_helper.cc
@@ -282,6 +282,10 @@ } } +void ContextualCueingHelper::WebContentsDestroyed() { + weak_ptr_factory_.InvalidateWeakPtrs(); +} + void ContextualCueingHelper::OnOptimizationGuideCueingMetadata( base::TimeTicks document_available_time, optimization_guide::OptimizationGuideDecision decision,
diff --git a/chrome/browser/glic/suggestions/contextual_cueing_helper.h b/chrome/browser/glic/suggestions/contextual_cueing_helper.h index ef7d3f6..9f73e12 100644 --- a/chrome/browser/glic/suggestions/contextual_cueing_helper.h +++ b/chrome/browser/glic/suggestions/contextual_cueing_helper.h
@@ -47,6 +47,7 @@ void PrimaryMainDocumentElementAvailable() override; void OnFirstContentfulPaintInPrimaryMainFrame() override; void DocumentOnLoadCompletedInPrimaryMainFrame() override; + void WebContentsDestroyed() override; // Returns when the last primary main frame navigation was committed if the // navigation was a same document navigation.
diff --git a/chrome/browser/glic/test_support/glic_browser_test.h b/chrome/browser/glic/test_support/glic_browser_test.h index 3f300ac..414b1e4 100644 --- a/chrome/browser/glic/test_support/glic_browser_test.h +++ b/chrome/browser/glic/test_support/glic_browser_test.h
@@ -415,6 +415,22 @@ } private: + // Hide functionality not available on Android to discourage use. + // Callers can instead use, e.g. PlatformBrowserTest::browser(), or + // redeclare PlatformBrowserTest::browser as public on the test fixture. +#if !BUILDFLAG(IS_ANDROID) + // Alternative: CreateAndActivateTab(GURL("about:blank")) + using T::AddBlankTabAndShow; + // Alternative: GetBrowser() + using T::browser; + // Alternative: + // chrome/browser/ui/browser_window/public/create_browser_window.h. + using T::CreateBrowser; + using T::CreateBrowserForApp; + using T::CreateBrowserForPopup; + using T::CreateIncognitoBrowser; + using T::OpenURLOffTheRecord; +#endif GlicTestEnvironment glic_test_environment_; base::test::ScopedFeatureList scoped_feature_list_; #if defined(USE_MOCK_ACTIVATION_CONTROLLER)
diff --git a/chrome/browser/image_descriptions/BUILD.gn b/chrome/browser/image_descriptions/BUILD.gn index 9ce828ce..d0be306f 100644 --- a/chrome/browser/image_descriptions/BUILD.gn +++ b/chrome/browser/image_descriptions/BUILD.gn
@@ -122,6 +122,7 @@ "//components/user_prefs/android:java", "//content/public/android:content_java", "//content/public/test/android:content_java_test_support", + "//ui/android:ui_java", "//third_party/android_deps:espresso_java", "//third_party/androidx:androidx_fragment_fragment_java", "//third_party/androidx:androidx_preference_preference_java",
diff --git a/chrome/browser/image_descriptions/android/java/src/org/chromium/chrome/browser/image_descriptions/ImageDescriptionsSettingsTest.java b/chrome/browser/image_descriptions/android/java/src/org/chromium/chrome/browser/image_descriptions/ImageDescriptionsSettingsTest.java index f3c8852..4559788 100644 --- a/chrome/browser/image_descriptions/android/java/src/org/chromium/chrome/browser/image_descriptions/ImageDescriptionsSettingsTest.java +++ b/chrome/browser/image_descriptions/android/java/src/org/chromium/chrome/browser/image_descriptions/ImageDescriptionsSettingsTest.java
@@ -4,6 +4,9 @@ package org.chromium.chrome.browser.image_descriptions; +import org.chromium.base.test.util.DisableIf; +import org.chromium.ui.base.DeviceFormFactor; + import static androidx.test.espresso.Espresso.onView; import static androidx.test.espresso.action.ViewActions.click; import static androidx.test.espresso.matcher.ViewMatchers.withId; @@ -265,6 +268,7 @@ @Test @SmallTest + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testUserTogglesSwitch_Off() { // When we toggle switch to Off, it should disable radio buttons and descriptions ThreadUtils.runOnUiThreadBlocking(
diff --git a/chrome/browser/indigo/indigo_agent_host.cc b/chrome/browser/indigo/indigo_agent_host.cc index 55289a9..4e97f93 100644 --- a/chrome/browser/indigo/indigo_agent_host.cc +++ b/chrome/browser/indigo/indigo_agent_host.cc
@@ -6,7 +6,6 @@ #include <utility> -#include "base/command_line.h" #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/functional/bind.h" @@ -15,8 +14,8 @@ #include "base/logging.h" #include "base/task/task_traits.h" #include "base/task/thread_pool.h" -#include "chrome/browser/component_updater/indigo_component_installer.h" #include "chrome/browser/indigo/indigo_image_replacement_manager.h" +#include "chrome/browser/indigo/indigo_service.h" #include "chrome/browser/profiles/profile.h" #include "content/public/browser/page.h" #include "content/public/browser/render_frame_host.h" @@ -28,7 +27,6 @@ namespace indigo { namespace { -const char kIndigoScriptSwitch[] = "indigo-script"; std::optional<std::string> ReadFileToStringSync(const base::FilePath& path) { std::string content; @@ -55,28 +53,18 @@ return true; } - base::FilePath override_path = - base::CommandLine::ForCurrentProcess()->GetSwitchValuePath( - kIndigoScriptSwitch); - std::optional<base::FilePath> component_path = - component_updater::GetIndigoContentScriptPath(); - - base::FilePath target_path; - if (!override_path.empty()) { - target_path = override_path; - } else if (component_path.has_value()) { - target_path = *component_path; - } else { + std::optional<base::FilePath> script_path = IndigoService::GetScriptPath(); + if (!script_path.has_value()) { return false; } injection_state_ = InjectionState::kInjecting; pending_invoke_count_++; - GURL script_url = net::FilePathToFileURL(target_path); + GURL script_url = net::FilePathToFileURL(*script_path); base::ThreadPool::PostTaskAndReplyWithResult( FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_BLOCKING}, - base::BindOnce(&ReadFileToStringSync, target_path), + base::BindOnce(&ReadFileToStringSync, *script_path), base::BindOnce(&IndigoAgentHost::OnScriptLoaded, weak_factory_.GetWeakPtr(), std::move(script_url))); return true;
diff --git a/chrome/browser/indigo/indigo_page_action_controller_unittest.cc b/chrome/browser/indigo/indigo_page_action_controller_unittest.cc index b8db42fc..07fc78d 100644 --- a/chrome/browser/indigo/indigo_page_action_controller_unittest.cc +++ b/chrome/browser/indigo/indigo_page_action_controller_unittest.cc
@@ -6,8 +6,10 @@ #include <memory> +#include "base/command_line.h" #include "base/test/bind.h" #include "base/test/gmock_callback_support.h" +#include "base/test/scoped_command_line.h" #include "base/test/scoped_feature_list.h" #include "base/test/test_future.h" #include "build/build_config.h" @@ -58,6 +60,8 @@ protected: void SetUp() override { feature_list_.InitAndEnableFeature(features::kIndigo); + scoped_command_line_.GetProcessCommandLine()->AppendSwitchASCII( + "indigo-script", "/dummy/path"); } void TearDown() override { @@ -173,6 +177,7 @@ std::unique_ptr<page_actions::MockPageActionController> page_action_controller_; std::unique_ptr<IndigoPageActionController> controller_; + base::test::ScopedCommandLine scoped_command_line_; }; TEST_F(IndigoPageActionControllerTest, ShowsWhenOptimizationGuideReturnsTrue) {
diff --git a/chrome/browser/indigo/indigo_service.cc b/chrome/browser/indigo/indigo_service.cc index ff4ed41..aa5c1d05 100644 --- a/chrome/browser/indigo/indigo_service.cc +++ b/chrome/browser/indigo/indigo_service.cc
@@ -4,9 +4,11 @@ #include "chrome/browser/indigo/indigo_service.h" +#include "base/command_line.h" #include "base/files/file_path.h" #include "base/functional/bind.h" #include "base/task/sequenced_task_runner.h" +#include "chrome/browser/component_updater/indigo_component_installer.h" #include "chrome/browser/extensions/component_loader.h" #include "chrome/browser/indigo/api_client.h" #include "chrome/browser/indigo/indigo_extension_utils.h" @@ -46,6 +48,18 @@ return !remote_eligibility->has_user_image || !has_onboarded_pref; } +// static +std::optional<base::FilePath> IndigoService::GetScriptPath() { + static constexpr char kIndigoScriptSwitch[] = "indigo-script"; + base::FilePath override_path = + base::CommandLine::ForCurrentProcess()->GetSwitchValuePath( + kIndigoScriptSwitch); + if (!override_path.empty()) { + return override_path; + } + return component_updater::GetIndigoContentScriptPath(); +} + IndigoService::IndigoService(Profile* profile, signin::IdentityManager* identity_manager, PrefService* pref_service) @@ -75,6 +89,11 @@ extensions::ComponentLoader::Get(profile_)->Add( indigo_extension_utils::GetManifest(), base::FilePath(FILE_PATH_LITERAL("indigo"))); + + indigo_component_ready_subscription_ = + component_updater::RegisterIndigoComponentReadyCallback( + base::BindRepeating(&IndigoService::OnIndigoComponentReady, + base::Unretained(this))); } IndigoService::~IndigoService() = default; @@ -114,6 +133,10 @@ } LocalEligibility IndigoService::ComputeLocalEligibility() const { + if (!GetScriptPath().has_value()) { + return LocalEligibility::kMissingScript; + } + if (pref_service_) { int policy_val = pref_service_->GetInteger(prefs::kIndigoPolicy); if (policy_val != prefs::Policy::kAllowed) { @@ -147,6 +170,10 @@ } } +void IndigoService::OnIndigoComponentReady() { + UpdateLocalEligibilityAndNotify(); +} + void IndigoService::GetCombinedEligibility( CombinedEligibilityCallback callback) { CombinedEligibility status;
diff --git a/chrome/browser/indigo/indigo_service.h b/chrome/browser/indigo/indigo_service.h index 718b32e..18fb76e 100644 --- a/chrome/browser/indigo/indigo_service.h +++ b/chrome/browser/indigo/indigo_service.h
@@ -9,6 +9,7 @@ #include "base/callback_list.h" #include "base/check.h" +#include "base/files/file_path.h" #include "base/functional/callback.h" #include "base/memory/raw_ptr.h" #include "base/scoped_observation.h" @@ -34,6 +35,7 @@ kNotSignedIn, kMissingCapabilities, kDisabledByPolicy, + kMissingScript, }; // Combined eligibility status including local constraints (features, profile @@ -72,6 +74,10 @@ PrefService* pref_service); ~IndigoService() override; + // Returns the path to the Indigo script if available (either via command line + // override or component updater). + static std::optional<base::FilePath> GetScriptPath(); + // Get and subscribe to information about whether the profile is eligible to // use the feature, as far as Chrome is concerned. This includes the user // being signed in with an account which isn't barred, for instance, but not @@ -132,10 +138,13 @@ base::RepeatingCallbackList<void(LocalEligibility)> local_eligibility_callback_list_; + void OnIndigoComponentReady(); + base::ScopedObservation<signin::IdentityManager, signin::IdentityManager::Observer> identity_manager_observation_{this}; std::unique_ptr<PrefChangeRegistrar> pref_change_registrar_; + base::CallbackListSubscription indigo_component_ready_subscription_; std::unique_ptr<ApiClient> api_client_; // The earliest time the anchored message can be shown again.
diff --git a/chrome/browser/indigo/indigo_service_unittest.cc b/chrome/browser/indigo/indigo_service_unittest.cc index 5b08b2a..b78c13b4 100644 --- a/chrome/browser/indigo/indigo_service_unittest.cc +++ b/chrome/browser/indigo/indigo_service_unittest.cc
@@ -4,10 +4,13 @@ #include "chrome/browser/indigo/indigo_service.h" +#include "base/command_line.h" #include "base/test/mock_callback.h" +#include "base/test/scoped_command_line.h" #include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" #include "base/test/test_future.h" +#include "chrome/browser/component_updater/indigo_component_installer.h" #include "chrome/browser/indigo/indigo_prefs.h" #include "chrome/common/chrome_features.h" #include "chrome/test/base/testing_profile.h" @@ -30,6 +33,14 @@ void SetUp() override { scoped_feature_list_.InitAndEnableFeature(features::kIndigo); ::indigo::prefs::RegisterProfilePrefs(prefs_.registry()); + if (set_script_switch_in_setup_) { + scoped_command_line_.GetProcessCommandLine()->AppendSwitchASCII( + "indigo-script", "/dummy/path"); + } + } + + void TearDown() override { + component_updater::ResetIndigoInstallDirForTesting(); } void CreateService() { @@ -112,6 +123,8 @@ int remote_eligibility_fetch_count_ = 0; IndigoService::RemoteEligibilityCallback pending_remote_eligibility_callback_; bool auto_complete_remote_eligibility_fetch_ = true; + bool set_script_switch_in_setup_ = true; + base::test::ScopedCommandLine scoped_command_line_; }; TEST_F(IndigoServiceTest, DefaultStateNotSignedIn) { @@ -253,4 +266,33 @@ EXPECT_EQ(combined_eligibility.remote_eligibility.error(), "Server down"); } +class IndigoServiceNoScriptTest : public IndigoServiceTest { + public: + IndigoServiceNoScriptTest() { set_script_switch_in_setup_ = false; } +}; + +TEST_F(IndigoServiceNoScriptTest, ScriptNotAvailable) { + CreateService(); + EXPECT_EQ(service_->GetLocalEligibility(), LocalEligibility::kMissingScript); +} + +TEST_F(IndigoServiceNoScriptTest, DynamicComponentReady) { + CreateService(); + EXPECT_EQ(service_->GetLocalEligibility(), LocalEligibility::kMissingScript); + + base::test::TestFuture<LocalEligibility> future; + auto sub = service_->RegisterLocalEligibilityChangedCallback( + future.GetRepeatingCallback()); + + // Simulate component ready. + component_updater::IndigoComponentInstallerPolicy policy; + policy.ComponentReady(base::Version("1.0"), + base::FilePath(FILE_PATH_LITERAL("/dummy/path")), + base::DictValue()); + + // It should transition to kNotSignedIn (since we are not signed in). + EXPECT_EQ(future.Take(), LocalEligibility::kNotSignedIn); + EXPECT_EQ(service_->GetLocalEligibility(), LocalEligibility::kNotSignedIn); +} + } // namespace indigo
diff --git a/chrome/browser/magic_stack/android/java/src/org/chromium/chrome/browser/magic_stack/HomeModulesMediator.java b/chrome/browser/magic_stack/android/java/src/org/chromium/chrome/browser/magic_stack/HomeModulesMediator.java index 6b941a2..9b64be04 100644 --- a/chrome/browser/magic_stack/android/java/src/org/chromium/chrome/browser/magic_stack/HomeModulesMediator.java +++ b/chrome/browser/magic_stack/android/java/src/org/chromium/chrome/browser/magic_stack/HomeModulesMediator.java
@@ -761,7 +761,8 @@ ensureEnabledModuleSetCreated(); Set<Integer> set = new HashSet<>(mEnabledModuleSet); assert !set.contains(ModuleType.DEPRECATED_EDUCATIONAL_TIP) - && !set.contains(ModuleType.DEPRECATED_TAB_RESUMPTION); + && !set.contains(ModuleType.DEPRECATED_TAB_RESUMPTION) + && !set.contains(ModuleType.DEPRECATED_TIPS_NOTIFICATIONS_PROMO); boolean isHomeSurface = mModuleDelegateHost.isHomeSurface();
diff --git a/chrome/browser/magic_stack/android/java/src/org/chromium/chrome/browser/magic_stack/HomeModulesMetricsUtils.java b/chrome/browser/magic_stack/android/java/src/org/chromium/chrome/browser/magic_stack/HomeModulesMetricsUtils.java index 7319604..60046a2e 100644 --- a/chrome/browser/magic_stack/android/java/src/org/chromium/chrome/browser/magic_stack/HomeModulesMetricsUtils.java +++ b/chrome/browser/magic_stack/android/java/src/org/chromium/chrome/browser/magic_stack/HomeModulesMetricsUtils.java
@@ -10,6 +10,7 @@ import static org.chromium.chrome.browser.magic_stack.ModuleDelegate.ModuleType.DEFAULT_BROWSER_PROMO; import static org.chromium.chrome.browser.magic_stack.ModuleDelegate.ModuleType.DEPRECATED_EDUCATIONAL_TIP; import static org.chromium.chrome.browser.magic_stack.ModuleDelegate.ModuleType.DEPRECATED_TAB_RESUMPTION; +import static org.chromium.chrome.browser.magic_stack.ModuleDelegate.ModuleType.DEPRECATED_TIPS_NOTIFICATIONS_PROMO; import static org.chromium.chrome.browser.magic_stack.ModuleDelegate.ModuleType.ENHANCED_SAFE_BROWSING_PROMO; import static org.chromium.chrome.browser.magic_stack.ModuleDelegate.ModuleType.HISTORY_SYNC_PROMO; import static org.chromium.chrome.browser.magic_stack.ModuleDelegate.ModuleType.NTP_THEME_PROMO; @@ -24,7 +25,6 @@ import static org.chromium.chrome.browser.magic_stack.ModuleDelegate.ModuleType.SINGLE_TAB; import static org.chromium.chrome.browser.magic_stack.ModuleDelegate.ModuleType.TAB_GROUP_PROMO; import static org.chromium.chrome.browser.magic_stack.ModuleDelegate.ModuleType.TAB_GROUP_SYNC_PROMO; -import static org.chromium.chrome.browser.magic_stack.ModuleDelegate.ModuleType.TIPS_NOTIFICATIONS_PROMO; import androidx.annotation.VisibleForTesting; @@ -140,8 +140,6 @@ return "NtpThemePromo"; case HISTORY_SYNC_PROMO: return "HistorySyncPromo"; - case TIPS_NOTIFICATIONS_PROMO: - return "TipsNotificationsPromo"; case ENHANCED_SAFE_BROWSING_PROMO: return "EnhancedSafeBrowsingPromo"; case ADDRESS_BAR_PLACEMENT_PROMO: @@ -182,8 +180,6 @@ return QUICK_DELETE_PROMO; case "HistorySyncPromo": return HISTORY_SYNC_PROMO; - case "TipsNotificationsPromo": - return TIPS_NOTIFICATIONS_PROMO; case "EnhancedSafeBrowsingPromo": return ENHANCED_SAFE_BROWSING_PROMO; case "AddressBarPlacementPromo": @@ -211,7 +207,8 @@ HashSet<Integer> set = new HashSet<>(); for (@ModuleType int moduleType = 0; moduleType < ModuleType.NUM_ENTRIES; moduleType++) { if (moduleType == DEPRECATED_EDUCATIONAL_TIP - || moduleType == DEPRECATED_TAB_RESUMPTION) { + || moduleType == DEPRECATED_TAB_RESUMPTION + || moduleType == DEPRECATED_TIPS_NOTIFICATIONS_PROMO) { continue; } set.add(moduleType);
diff --git a/chrome/browser/magic_stack/android/java/src/org/chromium/chrome/browser/magic_stack/HomeModulesUtils.java b/chrome/browser/magic_stack/android/java/src/org/chromium/chrome/browser/magic_stack/HomeModulesUtils.java index 182dfea..da1fe6c 100644 --- a/chrome/browser/magic_stack/android/java/src/org/chromium/chrome/browser/magic_stack/HomeModulesUtils.java +++ b/chrome/browser/magic_stack/android/java/src/org/chromium/chrome/browser/magic_stack/HomeModulesUtils.java
@@ -22,7 +22,6 @@ import static org.chromium.chrome.browser.magic_stack.ModuleDelegate.ModuleType.SINGLE_TAB; import static org.chromium.chrome.browser.magic_stack.ModuleDelegate.ModuleType.TAB_GROUP_PROMO; import static org.chromium.chrome.browser.magic_stack.ModuleDelegate.ModuleType.TAB_GROUP_SYNC_PROMO; -import static org.chromium.chrome.browser.magic_stack.ModuleDelegate.ModuleType.TIPS_NOTIFICATIONS_PROMO; import android.content.Context; import android.os.SystemClock; @@ -77,7 +76,6 @@ TAB_GROUP_SYNC_PROMO, QUICK_DELETE_PROMO, HISTORY_SYNC_PROMO, - TIPS_NOTIFICATIONS_PROMO, ENHANCED_SAFE_BROWSING_PROMO, ADDRESS_BAR_PLACEMENT_PROMO, SIGN_IN_PROMO, @@ -135,7 +133,6 @@ case QUICK_DELETE_PROMO: case NTP_THEME_PROMO: case HISTORY_SYNC_PROMO: - case TIPS_NOTIFICATIONS_PROMO: case ENHANCED_SAFE_BROWSING_PROMO: case ADDRESS_BAR_PLACEMENT_PROMO: case SIGN_IN_PROMO:
diff --git a/chrome/browser/magic_stack/android/java/src/org/chromium/chrome/browser/magic_stack/ModuleDelegate.java b/chrome/browser/magic_stack/android/java/src/org/chromium/chrome/browser/magic_stack/ModuleDelegate.java index 943277ae..2cbd2ed 100644 --- a/chrome/browser/magic_stack/android/java/src/org/chromium/chrome/browser/magic_stack/ModuleDelegate.java +++ b/chrome/browser/magic_stack/android/java/src/org/chromium/chrome/browser/magic_stack/ModuleDelegate.java
@@ -37,7 +37,7 @@ ModuleType.TAB_GROUP_SYNC_PROMO, ModuleType.QUICK_DELETE_PROMO, ModuleType.HISTORY_SYNC_PROMO, - ModuleType.TIPS_NOTIFICATIONS_PROMO, + ModuleType.DEPRECATED_TIPS_NOTIFICATIONS_PROMO, ModuleType.ENHANCED_SAFE_BROWSING_PROMO, ModuleType.ADDRESS_BAR_PLACEMENT_PROMO, ModuleType.SETUP_LIST_TWO_CELL_CONTAINER, @@ -61,7 +61,7 @@ int TAB_GROUP_SYNC_PROMO = 8; int QUICK_DELETE_PROMO = 9; int HISTORY_SYNC_PROMO = 10; - int TIPS_NOTIFICATIONS_PROMO = 11; + int DEPRECATED_TIPS_NOTIFICATIONS_PROMO = 11; int ENHANCED_SAFE_BROWSING_PROMO = 12; int ADDRESS_BAR_PLACEMENT_PROMO = 13; int SETUP_LIST_TWO_CELL_CONTAINER = 14; @@ -73,7 +73,7 @@ int NUM_ENTRIES = 20; } - // LINT.ThenChange(//chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/ntp_cards/NtpCardsMediator.java:HomeModuleTypes) + // LINT.ThenChange(//chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/ntp_cards/NtpCardsMediator.java:HomeModuleTypes, //tools/metrics/histograms/metadata/magic_stack/enums.xml:ModuleType, //tools/metrics/histograms/metadata/magic_stack/histograms.xml:ModuleType) /** * Called when a module has a PropertyModel ready. This could be called multiple times from the
diff --git a/chrome/browser/magic_stack/android/junit/src/org/chromium/chrome/browser/magic_stack/HomeModulesCoordinatorUnitTest.java b/chrome/browser/magic_stack/android/junit/src/org/chromium/chrome/browser/magic_stack/HomeModulesCoordinatorUnitTest.java index 60a520f..af5fe84b 100644 --- a/chrome/browser/magic_stack/android/junit/src/org/chromium/chrome/browser/magic_stack/HomeModulesCoordinatorUnitTest.java +++ b/chrome/browser/magic_stack/android/junit/src/org/chromium/chrome/browser/magic_stack/HomeModulesCoordinatorUnitTest.java
@@ -273,7 +273,6 @@ ModuleType.TAB_GROUP_SYNC_PROMO, ModuleType.QUICK_DELETE_PROMO, ModuleType.HISTORY_SYNC_PROMO, - ModuleType.TIPS_NOTIFICATIONS_PROMO, ModuleType.ENHANCED_SAFE_BROWSING_PROMO, ModuleType.ADDRESS_BAR_PLACEMENT_PROMO, ModuleType.SETUP_LIST_TWO_CELL_CONTAINER,
diff --git a/chrome/browser/magic_stack/android/junit/src/org/chromium/chrome/browser/magic_stack/HomeModulesMediatorUnitTest.java b/chrome/browser/magic_stack/android/junit/src/org/chromium/chrome/browser/magic_stack/HomeModulesMediatorUnitTest.java index 72f1914..b0b95ca 100644 --- a/chrome/browser/magic_stack/android/junit/src/org/chromium/chrome/browser/magic_stack/HomeModulesMediatorUnitTest.java +++ b/chrome/browser/magic_stack/android/junit/src/org/chromium/chrome/browser/magic_stack/HomeModulesMediatorUnitTest.java
@@ -583,7 +583,6 @@ ModuleType.TAB_GROUP_SYNC_PROMO, ModuleType.QUICK_DELETE_PROMO, ModuleType.HISTORY_SYNC_PROMO, - ModuleType.TIPS_NOTIFICATIONS_PROMO, ModuleType.ENHANCED_SAFE_BROWSING_PROMO, ModuleType.ADDRESS_BAR_PLACEMENT_PROMO, ModuleType.SETUP_LIST_TWO_CELL_CONTAINER, @@ -607,7 +606,6 @@ ModuleType.TAB_GROUP_SYNC_PROMO, ModuleType.QUICK_DELETE_PROMO, ModuleType.HISTORY_SYNC_PROMO, - ModuleType.TIPS_NOTIFICATIONS_PROMO, ModuleType.ENHANCED_SAFE_BROWSING_PROMO, ModuleType.ADDRESS_BAR_PLACEMENT_PROMO, ModuleType.SETUP_LIST_TWO_CELL_CONTAINER,
diff --git a/chrome/browser/memory/oom_kills_monitor.cc b/chrome/browser/memory/oom_kills_monitor.cc index d056577..4f796da 100644 --- a/chrome/browser/memory/oom_kills_monitor.cc +++ b/chrome/browser/memory/oom_kills_monitor.cc
@@ -117,6 +117,23 @@ &::metrics::DailyEvent::CheckInterval); } +void OOMKillsMonitor::Shutdown() { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + DCHECK(!is_shutdown_); + + if (!monitoring_started_) { + return; + } + is_shutdown_ = true; + + checking_timer_.Stop(); + daily_event_timer_.Stop(); + + daily_event_.reset(); + + pref_service_ = nullptr; +} + // Both host and guest(ARCVM) oom kills are logged to the same histogram // Memory.OOMKills.Count. // @@ -168,6 +185,9 @@ } void OOMKillsMonitor::ReportOOMKills(unsigned long oom_kills_delta) { + if (is_shutdown_) { + return; + } for (size_t i = 0; i < oom_kills_delta; ++i) { ++oom_kills_count_;
diff --git a/chrome/browser/memory/oom_kills_monitor.h b/chrome/browser/memory/oom_kills_monitor.h index 27abb77..9ca7c8ff 100644 --- a/chrome/browser/memory/oom_kills_monitor.h +++ b/chrome/browser/memory/oom_kills_monitor.h
@@ -31,6 +31,10 @@ void Initialize(PrefService* pref_service); + // Stops timers and clears the PrefService pointer. Must be called before + // the PrefService is destroyed (e.g., during browser shutdown). + void Shutdown(); + void LogArcOOMKill(unsigned long current_oom_kills); // The following items are public for testing. @@ -102,7 +106,12 @@ static const char kDailyEventHistogramName[]; // A raw pointer to the PrefService used to read and write the statistics. - raw_ptr<PrefService, LeakedDanglingUntriaged> pref_service_; + // Cleared by Shutdown(). + raw_ptr<PrefService> pref_service_; + + // Set to true after Shutdown() is called. Used to guard against post-shutdown + // calls rather than relying on pref_service_ null checks. + bool is_shutdown_ = false; }; } // namespace memory
diff --git a/chrome/browser/memory/oom_kills_monitor_unittest.cc b/chrome/browser/memory/oom_kills_monitor_unittest.cc index 28288ae..7686d67e 100644 --- a/chrome/browser/memory/oom_kills_monitor_unittest.cc +++ b/chrome/browser/memory/oom_kills_monitor_unittest.cc
@@ -120,6 +120,7 @@ EXPECT_EQ(1, daily_samples->GetCount(4)); EXPECT_EQ(1, daily_samples->GetCount(5)); } + monitor_instance.Shutdown(); } } // namespace memory
diff --git a/chrome/browser/page_content_annotations/multi_source_page_context_fetcher_browsertest.cc b/chrome/browser/page_content_annotations/multi_source_page_context_fetcher_browsertest.cc index 76d384d..a42b9c4c 100644 --- a/chrome/browser/page_content_annotations/multi_source_page_context_fetcher_browsertest.cc +++ b/chrome/browser/page_content_annotations/multi_source_page_context_fetcher_browsertest.cc
@@ -162,6 +162,7 @@ IN_PROC_BROWSER_TEST_P( ScreenshotBackendMultiSourcePageContextFetcherBrowserTest, TakesScreenshot) { + base::HistogramTester histograms; GURL url = embedded_https_test_server().GetURL("/empty.html"); ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url)); @@ -211,6 +212,8 @@ // TODO(b/438825957): add test coverage for the output // of the CopyFromSurface screenshot. _)); + histograms.ExpectUniqueSample("Glic.PageContextFetcher.ScreenshotRedacted", + false, 1); } class ScreenshotTimeoutMultiSourcePageContextFetcherBrowserTest @@ -302,6 +305,7 @@ IN_PROC_BROWSER_TEST_F(RedactingMultiSourcePageContextFetcherBrowserTest, TakesScreenshot_SameOriginIframeNoRedaction) { + base::HistogramTester histograms; ASSERT_TRUE( ui_test_utils::NavigateToURL(browser(), GetURL(kHostA, "/iframe.html"))); @@ -338,10 +342,13 @@ EXPECT_FALSE(bitmap.empty()); EXPECT_THAT(bitmap.getColor(10, 10), IsColorWithinTolerance(SK_ColorRED, 0x20)); + histograms.ExpectUniqueSample("Glic.PageContextFetcher.ScreenshotRedacted", + false, 1); } IN_PROC_BROWSER_TEST_F(RedactingMultiSourcePageContextFetcherBrowserTest, TakesScreenshot_CrossOriginSameSiteIframeNoRedaction) { + base::HistogramTester histograms; ASSERT_TRUE( ui_test_utils::NavigateToURL(browser(), GetURL(kHostA, "/iframe.html"))); @@ -378,10 +385,13 @@ EXPECT_FALSE(bitmap.empty()); EXPECT_THAT(bitmap.getColor(10, 10), IsColorWithinTolerance(SK_ColorRED, 0x20)); + histograms.ExpectUniqueSample("Glic.PageContextFetcher.ScreenshotRedacted", + false, 1); } IN_PROC_BROWSER_TEST_F(RedactingMultiSourcePageContextFetcherBrowserTest, TakesScreenshot_CrossSiteIframeRedacted) { + base::HistogramTester histograms; ASSERT_TRUE( ui_test_utils::NavigateToURL(browser(), GetURL(kHostA, "/iframe.html"))); @@ -418,6 +428,8 @@ EXPECT_FALSE(bitmap.empty()); EXPECT_THAT(bitmap.getColor(10, 10), IsColorWithinTolerance(SK_ColorBLACK, 0x20)); + histograms.ExpectUniqueSample("Glic.PageContextFetcher.ScreenshotRedacted", + false, 1); } // Test class that sets png params and validates pngs are returned. @@ -444,6 +456,7 @@ // Tests that the mimetype returned is png and image decodes correctly. IN_PROC_BROWSER_TEST_F(PngMultiSourcePageContextFetcherBrowserTest, TakesScreenshot_Png) { + base::HistogramTester histograms; GURL url = embedded_https_test_server().GetURL("/empty.html"); ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url)); @@ -474,6 +487,8 @@ EXPECT_FALSE(bitmap.isNull()); EXPECT_FALSE(bitmap.empty()); + histograms.ExpectUniqueSample("Glic.PageContextFetcher.ScreenshotRedacted", + false, 1); } // Test class that sets webp params and validates webps are returned. @@ -500,6 +515,7 @@ // Tests that the mimetype returned is webp and image decodes correctly. IN_PROC_BROWSER_TEST_F(WebpMultiSourcePageContextFetcherBrowserTest, TakesScreenshot_Webp) { + base::HistogramTester histograms; GURL url = embedded_https_test_server().GetURL("/empty.html"); ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url)); @@ -525,6 +541,8 @@ EXPECT_FALSE(screenshot.dimensions.IsZero()); ASSERT_GT(screenshot.screenshot_data.size(), 0); ASSERT_EQ(screenshot.mime_type, "image/webp"); + histograms.ExpectUniqueSample("Glic.PageContextFetcher.ScreenshotRedacted", + false, 1); } class PasswordRedactionMultiSourcePageContextFetcherBrowserTest @@ -561,6 +579,7 @@ IN_PROC_BROWSER_TEST_F( PasswordRedactionMultiSourcePageContextFetcherBrowserTest, BasicRedaction) { + base::HistogramTester histograms; ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GetURL(kHostA, "/password.html"))); @@ -592,11 +611,14 @@ EXPECT_FALSE(bitmap.empty()); EXPECT_THAT(bitmap.getColor(10, 10), IsColorWithinTolerance(SK_ColorRED, 0x20)); + histograms.ExpectUniqueSample("Glic.PageContextFetcher.ScreenshotRedacted", + true, 1); } IN_PROC_BROWSER_TEST_F( PasswordRedactionMultiSourcePageContextFetcherBrowserTest, DISABLED_BasicRedactionInIframe) { + base::HistogramTester histograms; ASSERT_TRUE(ui_test_utils::NavigateToURL( browser(), GetURL(kHostA, "/password_in_iframe.html?domain=/cross-site/b.test/"))); @@ -647,6 +669,8 @@ EXPECT_FALSE(bitmap.empty()); EXPECT_THAT(bitmap.getColor(120, 120), IsColorWithinTolerance(SK_ColorRED, 0x20)); + histograms.ExpectUniqueSample("Glic.PageContextFetcher.ScreenshotRedacted", + true, 1); } IN_PROC_BROWSER_TEST_F( @@ -696,6 +720,8 @@ EXPECT_FALSE(bitmap.empty()); EXPECT_THAT(bitmap.getColor(10, 10), IsColorWithinTolerance(SK_ColorRED, 0x20)); + histograms.ExpectUniqueSample("Glic.PageContextFetcher.ScreenshotRedacted", + true, 1); } class SensitivePaymentRedactionMultiSourcePageContextFetcherBrowserTest @@ -735,6 +761,7 @@ IN_PROC_BROWSER_TEST_F( SensitivePaymentRedactionMultiSourcePageContextFetcherBrowserTest, BasicRedaction) { + base::HistogramTester histograms; ASSERT_TRUE(ui_test_utils::NavigateToURL( browser(), GetURL(kHostA, "/optimization_guide/credit_card.html"))); @@ -770,11 +797,14 @@ // cc-exp at (0, 110) size 100x100. EXPECT_THAT(bitmap.getColor(10, 120), IsColorWithinTolerance(SK_ColorRED, 0x20)); + histograms.ExpectUniqueSample("Glic.PageContextFetcher.ScreenshotRedacted", + true, 1); } IN_PROC_BROWSER_TEST_F( SensitivePaymentRedactionMultiSourcePageContextFetcherBrowserTest, BasicRedactionInIframe) { + base::HistogramTester histograms; ASSERT_TRUE(ui_test_utils::NavigateToURL( browser(), GetURL(kHostA, @@ -831,6 +861,8 @@ // cc-exp EXPECT_THAT(bitmap.getColor(120, 240), IsColorWithinTolerance(SK_ColorRED, 0x20)); + histograms.ExpectUniqueSample("Glic.PageContextFetcher.ScreenshotRedacted", + true, 1); } IN_PROC_BROWSER_TEST_F( @@ -884,10 +916,13 @@ // cc-exp at (0, 110) size 100x100. EXPECT_THAT(bitmap.getColor(10, 120), IsColorWithinTolerance(SK_ColorRED, 0x20)); + histograms.ExpectUniqueSample("Glic.PageContextFetcher.ScreenshotRedacted", + true, 1); } IN_PROC_BROWSER_TEST_F(MultiSourcePageContextFetcherBrowserTest, TakesScreenshot_PngWithDimensions) { + base::HistogramTester histograms; GURL url = embedded_https_test_server().GetURL("/empty.html"); ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url)); @@ -923,6 +958,8 @@ SkBitmap bitmap = gfx::PNGCodec::Decode(screenshot.screenshot_data); EXPECT_FALSE(bitmap.isNull()); EXPECT_FALSE(bitmap.empty()); + histograms.ExpectUniqueSample("Glic.PageContextFetcher.ScreenshotRedacted", + false, 1); } class ElementCSSRedactionMultiSourcePageContextFetcherBrowserTest @@ -958,6 +995,7 @@ IN_PROC_BROWSER_TEST_F( ElementCSSRedactionMultiSourcePageContextFetcherBrowserTest, BasicRedaction) { + base::HistogramTester histograms; ASSERT_TRUE(ui_test_utils::NavigateToURL( browser(), GetURL(kHostA, @@ -987,6 +1025,8 @@ EXPECT_FALSE(bitmap.empty()); EXPECT_THAT(bitmap.getColor(10, 10), IsColorWithinTolerance(SK_ColorRED, 0x20)); + histograms.ExpectUniqueSample("Glic.PageContextFetcher.ScreenshotRedacted", + true, 1); } } // namespace page_content_annotations
diff --git a/chrome/browser/pdf/pdf_searchify_browsertest.cc b/chrome/browser/pdf/pdf_searchify_browsertest.cc index da2156f..40639fb 100644 --- a/chrome/browser/pdf/pdf_searchify_browsertest.cc +++ b/chrome/browser/pdf/pdf_searchify_browsertest.cc
@@ -175,12 +175,8 @@ } // TODO(crbug.com/406839385): Re-enable this test on Mac. -#if BUILDFLAG(IS_MAC) -#define MAYBE_MultiPage DISABLED_MultiPage -#else -#define MAYBE_MultiPage MultiPage -#endif -IN_PROC_BROWSER_TEST_P(PDFSearchifyTest, MAYBE_MultiPage) { +// TODO(crbug.com/470431038): Test is flaky on multiple platforms. +IN_PROC_BROWSER_TEST_P(PDFSearchifyTest, DISABLED_MultiPage) { base::HistogramTester histograms; ASSERT_TRUE(LoadPdf(embedded_test_server()->GetURL( "/pdf/accessibility/inaccessible-text-in-three-page.pdf")));
diff --git a/chrome/browser/privacy_guide/android/BUILD.gn b/chrome/browser/privacy_guide/android/BUILD.gn index add220e..dc69aec 100644 --- a/chrome/browser/privacy_guide/android/BUILD.gn +++ b/chrome/browser/privacy_guide/android/BUILD.gn
@@ -162,6 +162,7 @@ "//third_party/jni_zero:gendeps_java", "//third_party/junit", "//third_party/mockito:mockito_java", + "//ui/android:ui_java", "//ui/android:ui_java_test_support", ] }
diff --git a/chrome/browser/privacy_guide/android/javatests/src/org/chromium/chrome/browser/privacy_guide/PrivacyGuideFragmentTest.java b/chrome/browser/privacy_guide/android/javatests/src/org/chromium/chrome/browser/privacy_guide/PrivacyGuideFragmentTest.java index d5a31f3..17edc0a 100644 --- a/chrome/browser/privacy_guide/android/javatests/src/org/chromium/chrome/browser/privacy_guide/PrivacyGuideFragmentTest.java +++ b/chrome/browser/privacy_guide/android/javatests/src/org/chromium/chrome/browser/privacy_guide/PrivacyGuideFragmentTest.java
@@ -54,6 +54,7 @@ import org.mockito.junit.MockitoRule; import org.chromium.base.test.util.CommandLineFlags; +import org.chromium.base.test.util.DisableIf; import org.chromium.base.test.util.DoNotBatch; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.Features.DisableFeatures; @@ -82,6 +83,7 @@ import org.chromium.components.signin.test.util.TestAccounts; import org.chromium.components.sync.UserSelectableType; import org.chromium.components.user_prefs.UserPrefs; +import org.chromium.ui.base.DeviceFormFactor; import java.io.IOException; import java.util.List; @@ -326,6 +328,7 @@ @LargeTest @Feature({"RenderTest"}) @DisableFeatures(ChromeFeatureList.SETTINGS_MULTI_COLUMN) + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testRenderSBCard() throws IOException { launchPrivacyGuide(); goToCard(FragmentType.SAFE_BROWSING); @@ -336,6 +339,7 @@ @LargeTest @Feature({"RenderTest"}) @DisableFeatures(ChromeFeatureList.SETTINGS_MULTI_COLUMN) + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testRenderSBEnhancedBottomSheet() throws IOException { launchPrivacyGuide(); goToCard(FragmentType.SAFE_BROWSING); @@ -656,6 +660,7 @@ @Test @LargeTest @Feature({"PrivacyGuide"}) + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testMSBBCard_offToOnSettingsStatesHistogram() { setMSBBState(false); launchPrivacyGuide(); @@ -884,6 +889,7 @@ @Test @LargeTest @Feature({"PrivacyGuide"}) + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testHistorySyncCard_nextButtonInitialSyncStateIsSet() { launchPrivacyGuide(); mPrivacyGuideTestRule @@ -899,6 +905,7 @@ @Test @LargeTest @Feature({"PrivacyGuide"}) + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testHistorySyncCard_backButtonInitialSyncStateIsSet() { launchPrivacyGuide(); mPrivacyGuideTestRule @@ -1131,6 +1138,7 @@ @Test @LargeTest @Feature({"PrivacyGuide"}) + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testCookiesCard_block3PIncognitoTo3PSettingsStatesHistogram() { setCookieControlsMode(CookieControlsMode.INCOGNITO_ONLY); launchPrivacyGuide();
diff --git a/chrome/browser/privacy_sandbox/android/javatests/src/org/chromium/chrome/browser/privacy_sandbox/AdMeasurementFragmentTest.java b/chrome/browser/privacy_sandbox/android/javatests/src/org/chromium/chrome/browser/privacy_sandbox/AdMeasurementFragmentTest.java index e424d6e..7420e0f 100644 --- a/chrome/browser/privacy_sandbox/android/javatests/src/org/chromium/chrome/browser/privacy_sandbox/AdMeasurementFragmentTest.java +++ b/chrome/browser/privacy_sandbox/android/javatests/src/org/chromium/chrome/browser/privacy_sandbox/AdMeasurementFragmentTest.java
@@ -4,6 +4,9 @@ package org.chromium.chrome.browser.privacy_sandbox; +import org.chromium.base.test.util.DisableIf; +import org.chromium.ui.base.DeviceFormFactor; + import static androidx.test.espresso.Espresso.onView; import static androidx.test.espresso.action.ViewActions.click; import static androidx.test.espresso.assertion.ViewAssertions.matches; @@ -170,6 +173,7 @@ @Test @SmallTest + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testTurnAdMeasurementOn() { setAdMeasurementPrefEnabled(false); startAdMeasuremenSettings(); @@ -183,6 +187,7 @@ @Test @SmallTest + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testTurnAdMeasurementOff() { setAdMeasurementPrefEnabled(true); startAdMeasuremenSettings();
diff --git a/chrome/browser/privacy_sandbox/android/javatests/src/org/chromium/chrome/browser/privacy_sandbox/FledgeFragmentTest.java b/chrome/browser/privacy_sandbox/android/javatests/src/org/chromium/chrome/browser/privacy_sandbox/FledgeFragmentTest.java index 8caf397..f736af33 100644 --- a/chrome/browser/privacy_sandbox/android/javatests/src/org/chromium/chrome/browser/privacy_sandbox/FledgeFragmentTest.java +++ b/chrome/browser/privacy_sandbox/android/javatests/src/org/chromium/chrome/browser/privacy_sandbox/FledgeFragmentTest.java
@@ -4,6 +4,9 @@ package org.chromium.chrome.browser.privacy_sandbox; +import org.chromium.base.test.util.DisableIf; +import org.chromium.ui.base.DeviceFormFactor; + import static androidx.test.espresso.Espresso.onView; import static androidx.test.espresso.Espresso.pressBack; import static androidx.test.espresso.action.ViewActions.click; @@ -433,6 +436,7 @@ @Test @SmallTest + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void unblockSitesV2() { setFledgePrefEnabled(true); mFakePrivacySandboxBridge.setBlockedFledgeSites(SITE_NAME_1, SITE_NAME_2);
diff --git a/chrome/browser/privacy_sandbox/android/javatests/src/org/chromium/chrome/browser/privacy_sandbox/TopicsFragmentTest.java b/chrome/browser/privacy_sandbox/android/javatests/src/org/chromium/chrome/browser/privacy_sandbox/TopicsFragmentTest.java index f2613ac..d885590f 100644 --- a/chrome/browser/privacy_sandbox/android/javatests/src/org/chromium/chrome/browser/privacy_sandbox/TopicsFragmentTest.java +++ b/chrome/browser/privacy_sandbox/android/javatests/src/org/chromium/chrome/browser/privacy_sandbox/TopicsFragmentTest.java
@@ -4,6 +4,9 @@ package org.chromium.chrome.browser.privacy_sandbox; +import org.chromium.base.test.util.DisableIf; +import org.chromium.ui.base.DeviceFormFactor; + import static androidx.test.espresso.Espresso.onView; import static androidx.test.espresso.Espresso.pressBack; import static androidx.test.espresso.action.ViewActions.click; @@ -218,6 +221,7 @@ @Test @SmallTest + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testTurnTopicsOnWhenTopicListEmpty() { setTopicsPrefEnabled(false); startTopicsSettings(); @@ -239,6 +243,7 @@ @Test @SmallTest + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testTurnTopicsOnWhenTopicsListPopulated() { setTopicsPrefEnabled(false); mFakePrivacySandboxBridge.setCurrentTopTopics(TOPIC_NAME_1, TOPIC_NAME_2); @@ -263,6 +268,7 @@ @Test @SmallTest + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testTurnTopicsOff() { setTopicsPrefEnabled(true); startTopicsSettings(); @@ -291,6 +297,7 @@ @Test @SmallTest + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testBlockedTopicsAppearWhenTopicOn() { setTopicsPrefEnabled(true); mFakePrivacySandboxBridge.setBlockedTopics(TOPIC_NAME_1, TOPIC_NAME_2); @@ -349,6 +356,7 @@ @Test @SmallTest + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testUnblockTopicsAdTopicsContentParity() { setTopicsPrefEnabled(true); mFakePrivacySandboxBridge.setBlockedTopics(TOPIC_NAME_1, TOPIC_NAME_2);
diff --git a/chrome/browser/resources/contextual_tasks/BUILD.gn b/chrome/browser/resources/contextual_tasks/BUILD.gn index 9b8f89c..b07dbed 100644 --- a/chrome/browser/resources/contextual_tasks/BUILD.gn +++ b/chrome/browser/resources/contextual_tasks/BUILD.gn
@@ -105,7 +105,7 @@ ts_definitions = [ "//tools/typescript/definitions/chrome_event.d.ts", - "//tools/typescript/definitions/metrics_private.d.ts", + "//tools/typescript/definitions/chrome_histograms.d.ts", "//tools/typescript/definitions/web_request.d.ts", "//tools/typescript/definitions/webview_tag.d.ts", ]
diff --git a/chrome/browser/resources/contextual_tasks/app.ts b/chrome/browser/resources/contextual_tasks/app.ts index f015701..63a220b 100644 --- a/chrome/browser/resources/contextual_tasks/app.ts +++ b/chrome/browser/resources/contextual_tasks/app.ts
@@ -39,6 +39,7 @@ import {PostMessageHandler} from './post_message_handler.js'; import type {Rect} from './post_message_handler.js'; import {getNonOccludedClipPath} from './utils/clip_path.js'; +import {recordAction} from './utils.js'; declare global { interface HTMLElementEventMap { @@ -492,11 +493,8 @@ } if (this.isShownInTab_) { - chrome.metricsPrivate.recordUserAction( + recordAction( 'ContextualTasks.HistoryNavigation.UserAction.NavigatedInFullTab'); - chrome.metricsPrivate.recordBoolean( - 'ContextualTasks.HistoryNavigation.UserAction.NavigatedInFullTab', - true); } this.browserProxy_.handler.setTaskId({value: taskUuid}); @@ -584,7 +582,10 @@ // Check if the initial render should be zero state. const {isZeroState} = await this.browserProxy_.handler.isZeroState(threadUrlAsUrl.href); + const {isAiPage} = + await this.browserProxy_.handler.isAiPage(threadUrlAsUrl.href); this.isZeroState_ = isZeroState; + this.isAiPage_ = isAiPage; this.inNlm_ = this.checkInNlm_(threadUrlAsUrl); @@ -925,9 +926,10 @@ {opacity: 1}, ], { - duration: 150, - easing: 'ease-in-out', - fill: 'forwards', + duration: 300, + delay: 100, + easing: 'cubic-bezier(0, 0, 0, 1)', + fill: 'both', }); } @@ -1064,10 +1066,7 @@ } protected async onNewThreadClick_() { - chrome.metricsPrivate.recordUserAction( - 'ContextualTasks.WebUI.UserAction.OpenNewThread'); - chrome.metricsPrivate.recordBoolean( - 'ContextualTasks.WebUI.UserAction.OpenNewThread', true); + recordAction('ContextualTasks.WebUI.UserAction.OpenNewThread'); const {url} = await this.browserProxy_.handler.getThreadUrl(); const newThreadUrl = new URL(url); const currentUrl = new URL(this.$.threadFrame.src);
diff --git a/chrome/browser/resources/contextual_tasks/composebox.css b/chrome/browser/resources/contextual_tasks/composebox.css index f03e1cb..e3fad56 100644 --- a/chrome/browser/resources/contextual_tasks/composebox.css +++ b/chrome/browser/resources/contextual_tasks/composebox.css
@@ -317,7 +317,8 @@ #composebox::part(input), #composebox::part(tool-chip-label), #composebox::part(file-thumbnail-title), -#composebox::part(mirror) { +#composebox::part(mirror), +#composebox::part(smart-compose) { font-family: var(--google-sans-font); }
diff --git a/chrome/browser/resources/contextual_tasks/composebox.ts b/chrome/browser/resources/contextual_tasks/composebox.ts index ef0cf40a..5bd45976 100644 --- a/chrome/browser/resources/contextual_tasks/composebox.ts +++ b/chrome/browser/resources/contextual_tasks/composebox.ts
@@ -42,11 +42,11 @@ function recordVoiceSearchAction(voiceSearchState: VoiceSearchState) { // Safety return statement in rare case chrome metrics is not available. - if (!chrome.metricsPrivate) { + if (!chrome.histograms) { return; } - chrome.metricsPrivate.recordEnumerationValue( + chrome.histograms.recordEnumerationValue( 'ContextualTasks.VoiceSearch.State', voiceSearchState, VoiceSearchState.MAX_VALUE + 1); }
diff --git a/chrome/browser/resources/contextual_tasks/sources_menu.ts b/chrome/browser/resources/contextual_tasks/sources_menu.ts index 895b7ca..9bfc494 100644 --- a/chrome/browser/resources/contextual_tasks/sources_menu.ts +++ b/chrome/browser/resources/contextual_tasks/sources_menu.ts
@@ -18,6 +18,7 @@ import {BrowserProxyImpl} from './contextual_tasks_browser_proxy.js'; import {getCss} from './sources_menu.css.js'; import {getHtml} from './sources_menu.html.js'; +import {recordAction} from './utils.js'; export interface SourcesMenuElement { $: { @@ -65,10 +66,7 @@ protected onTabClick_(e: Event) { this.close(); - chrome.metricsPrivate.recordUserAction( - 'ContextualTasks.WebUI.UserAction.TabFromSourcesMenuClicked'); - chrome.metricsPrivate.recordBoolean( - 'ContextualTasks.WebUI.UserAction.TabFromSourcesMenuClicked', true); + recordAction('ContextualTasks.WebUI.UserAction.TabFromSourcesMenuClicked'); const contextInfo = this.getContextInfoFromEvent_(e); this.browserProxy_.handler.onTabClickedFromSourcesMenu( contextInfo.tab!.tabId, contextInfo.tab!.url);
diff --git a/chrome/browser/resources/contextual_tasks/utils.ts b/chrome/browser/resources/contextual_tasks/utils.ts index 63dfd2d7..bad5e10 100644 --- a/chrome/browser/resources/contextual_tasks/utils.ts +++ b/chrome/browser/resources/contextual_tasks/utils.ts
@@ -3,6 +3,6 @@ // found in the LICENSE file. export function recordAction(actionName: string) { - chrome.metricsPrivate.recordUserAction(actionName); - chrome.metricsPrivate.recordBoolean(actionName, true); + chrome.histograms.recordUserAction(actionName); + chrome.histograms.recordBoolean(actionName, true); }
diff --git a/chrome/browser/resources/glic/glic.css b/chrome/browser/resources/glic/glic.css index 7301295..7b96041b 100644 --- a/chrome/browser/resources/glic/glic.css +++ b/chrome/browser/resources/glic/glic.css
@@ -270,8 +270,16 @@ display: none; } +#guestPanel.show-header { + display: flex; + flex-direction: column; +} + #guestPanel.show-header #webviewHeader { display: block; + position: relative; + width: 100%; + order: -1; } #webviewContainer { @@ -281,11 +289,10 @@ } #guestPanel.show-header #webviewContainer { - position: absolute; + position: relative; width: 100%; - /* If showing a login page, the window height will always be 800px */ - height: 752px; - bottom: 0; + height: auto; + flex: 1; } .tonal-button {
diff --git a/chrome/browser/resources/glic/internals/glic_internals_app.html.ts b/chrome/browser/resources/glic/internals/glic_internals_app.html.ts index a4113b2..bdce9a3 100644 --- a/chrome/browser/resources/glic/internals/glic_internals_app.html.ts +++ b/chrome/browser/resources/glic/internals/glic_internals_app.html.ts
@@ -78,34 +78,6 @@ </tr> </table>` : html`<h3 id="loadingMsg">Loading...</h3>`} - <h2>Guest URL Presets</h2> - ${this.data_?.config ? html` - <div class="presets-container"> - <label for="autopushInput">Autopush</label> - <input - id="autopushInput" .value="${this.data_.config.autopushGuestUrl}" - @change="${this.onAutopushInputChange}"> - </input> - <label for="stagingInput">Staging</label> - <input - id="stagingInput" .value="${this.data_.config.stagingGuestUrl}" - @change="${this.onStagingInputChange}"> - </input> - <label for="preprodInput">Preprod</label> - <input - id="preprodInput" .value="${this.data_.config.preprodGuestUrl}" - @change="${this.onPreprodInputChange}"> - </input> - <label for="prodInput">Prod</label> - <input id="prodInput" .value="${this.data_.config.prodGuestUrl}" - @change="${this.onProdInputChange}"> - </input> - <div id="inputErrorMsg" class="hiddenElement"> - Invalid URL submitted: presets not updated - </div> - <cr-button @click="${this.onSavePresetsClick_}">Save</cr-button> - </div>` : - html`<h3 id="loadingMsg">Loading...</h3>`} </div> <!-- ================= DEBUG CONTROLS TAB ================= --> @@ -164,6 +136,16 @@ <option value="${item.value}">${item.name}</option> `)} </select> + ${this.invokeFeatureMode_ === 2 ? html` + <label for="invokeActuationTargetSelect">Actuation Target</label> + <select id="invokeActuationTargetSelect" + .value="${this.invokeActuationTarget_.toString()}" + @change="${this.onInvokeActuationTargetChange_}"> + ${this.actuationTargetEnumValues_.map(item => html` + <option value="${item.value}">${item.name}</option> + `)} + </select> + ` : html``} <div style="display: flex; gap: 16px; align-items: center;"> <label> @@ -223,10 +205,36 @@ </div> ` : html``} </div> - </div> - - <h2>Web Continuity URL Preset</h2> - ${this.data_?.config ? html` + <h2>Guest URL Presets</h2> + ${this.data_?.config ? html` + <div class="presets-container"> + <label for="autopushInput">Autopush</label> + <input id="autopushInput" + .value="${this.data_.config.autopushGuestUrl}" + @change="${this.onAutopushInputChange}"> + </input> + <label for="stagingInput">Staging</label> + <input + id="stagingInput" .value="${this.data_.config.stagingGuestUrl}" + @change="${this.onStagingInputChange}"> + </input> + <label for="preprodInput">Preprod</label> + <input + id="preprodInput" .value="${this.data_.config.preprodGuestUrl}" + @change="${this.onPreprodInputChange}"> + </input> + <label for="prodInput">Prod</label> + <input id="prodInput" .value="${this.data_.config.prodGuestUrl}" + @change="${this.onProdInputChange}"> + </input> + <div id="inputErrorMsg" class="hiddenElement"> + Invalid URL submitted: presets not updated + </div> + <cr-button @click="${this.onSavePresetsClick_}">Save</cr-button> + </div>` : + html`<h3 id="loadingMsg">Loading...</h3>`} + <h2>Web Continuity URL Preset</h2> + ${this.data_?.config ? html` <div class="web-continuity-container"> <label for="webContinuityInput">Web Continuity</label> <input id="webContinuityInput"
diff --git a/chrome/browser/resources/glic/internals/glic_internals_app.ts b/chrome/browser/resources/glic/internals/glic_internals_app.ts index dc7a0c9..325a78f 100644 --- a/chrome/browser/resources/glic/internals/glic_internals_app.ts +++ b/chrome/browser/resources/glic/internals/glic_internals_app.ts
@@ -7,7 +7,7 @@ import {CrLitElement} from '//resources/lit/v3_0/lit.rollup.js'; -import {ActuationEligibility, AllowedInflightNavigation, FeatureMode, FreOverride, InvocationSource} from '../glic.mojom-webui.js'; +import {ActuationEligibility, ActuationTarget, AllowedInflightNavigation, FeatureMode, FreOverride, InvocationSource} from '../glic.mojom-webui.js'; import {InternalsPageHandlerFactory, InternalsPageHandlerRemote} from '../glic_internals.mojom-webui.js'; import type {InternalsDataPayload} from '../glic_internals.mojom-webui.js'; @@ -42,6 +42,8 @@ invokeZssOverride_: {type: Boolean}, invokeZssAdditionalContent_: {type: String}, invokeOpenInForeground_: {type: Boolean}, + invokeActuationTarget_: {type: Number}, + actuationTargetEnumValues_: {type: Array}, selectedTabIndex_: {type: Number}, tabNames_: {type: Array}, @@ -62,6 +64,8 @@ protected accessor invokeZssOverride_: boolean = false; protected accessor invokeZssAdditionalContent_: string = ''; protected accessor invokeOpenInForeground_: boolean = true; + protected accessor invokeActuationTarget_: ActuationTarget = + ActuationTarget.kAgentDecides; protected accessor selectedTabIndex_: number = 0; protected accessor tabNames_: string[] = ['General', 'Debug Controls']; @@ -70,6 +74,11 @@ Object.entries(FeatureMode) .filter(([key]) => isNaN(Number(key))) .map(([name, value]) => ({name, value: value as number})); + protected accessor actuationTargetEnumValues_: + Array<{name: string, value: number}> = + Object.entries(ActuationTarget) + .filter(([key]) => isNaN(Number(key))) + .map(([name, value]) => ({name, value: value as number})); @@ -279,6 +288,10 @@ this.invokeOpenInForeground_ = (e.target as HTMLInputElement).checked; } + protected onInvokeActuationTargetChange_(e: Event) { + this.invokeActuationTarget_ = Number((e.target as HTMLSelectElement).value); + } + protected onTriggerInvokeClick_() { this.invokeLogs_ = [`[${new Date().toLocaleTimeString()}] TRIGGERING INVOKE...`]; @@ -306,6 +319,7 @@ freOverride: this.invokeFreOverride_, waitForPanelOpen: this.invokeWaitForPanelOpen_, surface: surface, + actuationTarget: this.invokeActuationTarget_, }; this.pageHandler_.triggerInvokeFromInternalsAction(options).then(
diff --git a/chrome/browser/resources/indigo_internals/app.ts b/chrome/browser/resources/indigo_internals/app.ts index 3238b25..0d60f88 100644 --- a/chrome/browser/resources/indigo_internals/app.ts +++ b/chrome/browser/resources/indigo_internals/app.ts
@@ -101,6 +101,8 @@ return 'Missing Capabilities'; case LocalEligibility.kDisabledByPolicy: return 'Disabled By Policy'; + case LocalEligibility.kMissingScript: + return 'Missing Script'; default: assertNotReachedCase(this.localEligibility_); } @@ -115,6 +117,7 @@ case LocalEligibility.kNotSignedIn: case LocalEligibility.kMissingCapabilities: case LocalEligibility.kDisabledByPolicy: + case LocalEligibility.kMissingScript: return 'status-ineligible'; default: assertNotReachedCase(this.localEligibility_);
diff --git a/chrome/browser/resources/omnibox_popup/omnibox_composebox.ts b/chrome/browser/resources/omnibox_popup/omnibox_composebox.ts index c3d4197..c7f86095 100644 --- a/chrome/browser/resources/omnibox_popup/omnibox_composebox.ts +++ b/chrome/browser/resources/omnibox_popup/omnibox_composebox.ts
@@ -123,9 +123,7 @@ return false; } - return this.showDropdown && - (this.showFileCarousel || this.shouldShowSubmitButton() || - this.inToolMode); + return super.shouldShowDivider(); } // TODO(crbug.com/486707998): Remove once this is added to mixin.
diff --git a/chrome/browser/resources/settings/privacy_page/security/security_page_feature_row.html b/chrome/browser/resources/settings/privacy_page/security/security_page_feature_row.html index 1acb33a6..5026030b 100644 --- a/chrome/browser/resources/settings/privacy_page/security/security_page_feature_row.html +++ b/chrome/browser/resources/settings/privacy_page/security/security_page_feature_row.html
@@ -68,7 +68,7 @@ padding: 0 36px; } </style> -<cr-expand-button class="cr-row" id="expandButton" expanded="{{expanded}}"> +<cr-expand-button class="cr-row first" id="expandButton" expanded="{{expanded}}"> <div id="content-wrapper"> <span id="icon" aria-hidden="true"> <cr-icon slot="icon" icon="[[icon]]"></cr-icon>
diff --git a/chrome/browser/resources/webui_toolbar/location_icon.css b/chrome/browser/resources/webui_toolbar/location_icon.css index 5a70527a..b705763 100644 --- a/chrome/browser/resources/webui_toolbar/location_icon.css +++ b/chrome/browser/resources/webui_toolbar/location_icon.css
@@ -60,25 +60,29 @@ /* An invisible overlay that mimics the native views::InkDrop highlight (hover state). */ #container::before { + background-color: var(--color-omnibox-icon-hover, transparent); + border-radius: inherit; content: ''; - position: absolute; inset: 0; + opacity: 0; pointer-events: none; - background-color: transparent; + position: absolute; /* Matches views::kHighlightFadeOutOnHoverChangeDuration (250ms) */ - transition: background-color 250ms ease-in-out; + transition: opacity 250ms ease-in-out; } /* An invisible overlay that mimics the native views::InkDrop ripple (pressed state). */ #container::after { + background-color: var(--color-omnibox-icon-pressed, transparent); + border-radius: inherit; content: ''; - position: absolute; inset: 0; + opacity: 0; pointer-events: none; - background-color: transparent; + position: absolute; /* Matches views::FloodFillInkDropRipple::ACTION_TRIGGERED_FADE_OUT (300ms) */ - transition: background-color 300ms ease-in-out; + transition: opacity 300ms ease-in-out; } :host([has-text]) #container { @@ -105,37 +109,27 @@ :host([clickable]:hover) #container::before, :host([clickable]:active) #container::before, :host([clickable][anchor-highlighted]) #container::before { - background-color: var(--color-omnibox-icon-hover); + /* The alpha value is baked directly into the color variable in C++. */ + opacity: 1; } -:host([is-text-dangerous][clickable]:hover) #container::before, -:host([is-text-dangerous][clickable]:active) #container::before, -:host([is-text-dangerous][clickable][anchor-highlighted]) #container::before { - background-color: var(--color-omnibox-security-chip-ink-drop-hover); +:host([is-text-dangerous]) #container::before { + background-color: + var(--color-omnibox-security-chip-ink-drop-hover, transparent); } /* --- PRESSED LAYER (RIPPLE) --- Native Views composites the ripple on top of the hover highlight. */ -:host([clickable]:active) #container::after { - background-color: var(--color-omnibox-icon-pressed); +:host([clickable]:active) #container::after, +:host([clickable][anchor-highlighted]) #container::after { + /* The alpha value is baked directly into the color variable in C++. */ + opacity: 1; transition: none; /* Instant press */ } -:host([is-text-dangerous][clickable]:active) #container::after { - background-color: var(--color-omnibox-security-chip-ink-drop-ripple); - transition: none; -} - -/* Anchor highlighted state (bubble open) holds the pressed color. - Includes [clickable] to match the specificity of the :hover rule, - ensuring the highlight color isn't overridden when the mouse hovers - over the open bubble's anchor. */ -:host([clickable][anchor-highlighted]) #container::after { - background-color: var(--color-omnibox-icon-pressed); -} - -:host([is-text-dangerous][clickable][anchor-highlighted]) #container::after { - background-color: var(--color-omnibox-security-chip-ink-drop-ripple); +:host([is-text-dangerous]) #container::after { + background-color: + var(--color-omnibox-security-chip-ink-drop-ripple, transparent); } /* Renders the SVG icon using a webkit mask. This allows the icon to
diff --git a/chrome/browser/safe_browsing/tailored_security/chrome_tailored_security_service_unittest.cc b/chrome/browser/safe_browsing/tailored_security/chrome_tailored_security_service_unittest.cc index 8f23e7f..8d14570 100644 --- a/chrome/browser/safe_browsing/tailored_security/chrome_tailored_security_service_unittest.cc +++ b/chrome/browser/safe_browsing/tailored_security/chrome_tailored_security_service_unittest.cc
@@ -18,8 +18,9 @@ #include "chrome/browser/signin/chrome_signin_client_test_util.h" #include "chrome/browser/signin/identity_test_environment_profile_adaptor.h" #include "chrome/browser/sync/sync_service_factory.h" -#include "chrome/browser/ui/browser.h" -#include "chrome/test/base/test_browser_window.h" +#include "chrome/browser/ui/browser_manager_service.h" +#include "chrome/browser/ui/browser_manager_service_factory.h" +#include "chrome/browser/ui/browser_window/test/mock_browser_window_interface.h" #include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_profile.h" #include "chrome/test/base/testing_profile_manager.h" @@ -38,11 +39,11 @@ #include "content/public/browser/storage_partition_config.h" #include "content/public/browser/web_contents.h" #include "content/public/test/browser_task_environment.h" -#include "content/public/test/navigation_simulator.h" #include "content/public/test/test_renderer_host.h" -#include "content/public/test/web_contents_tester.h" #include "services/network/test/test_url_loader_factory.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/base/base_window.h" +#include "ui/base/mojom/window_show_state.mojom.h" #include "url/gurl.h" class Profile; @@ -54,6 +55,63 @@ const bool kTailoredSecurityDisabled = false; namespace { +class DummyBaseWindow : public ui::BaseWindow { + public: + bool IsActive() const override { return false; } + bool IsMaximized() const override { return false; } + bool IsMinimized() const override { return false; } + bool IsFullscreen() const override { return false; } + gfx::NativeWindow GetNativeWindow() const override { + return gfx::NativeWindow(); + } + gfx::Rect GetRestoredBounds() const override { return gfx::Rect(); } + ui::mojom::WindowShowState GetRestoredState() const override { + return ui::mojom::WindowShowState::kDefault; + } + gfx::Rect GetBounds() const override { return gfx::Rect(); } + void Show() override {} + void Hide() override {} + bool IsVisible() const override { return true; } + void ShowInactive() override {} + void Close() override {} + void Activate() override {} + void Deactivate() override {} + void Maximize() override {} + void Minimize() override {} + void Restore() override {} + void SetBounds(const gfx::Rect& bounds) override {} + void FlashFrame(bool flash) override {} + ui::ZOrderLevel GetZOrderLevel() const override { + return ui::ZOrderLevel::kNormal; + } + void SetZOrderLevel(ui::ZOrderLevel order) override {} +#if BUILDFLAG(IS_ANDROID) + bool CanResize(ui::WindowResizePrecheckResult& result) const override { + return false; + } +#endif +}; + +class FakeBrowserManagerService : public BrowserManagerService { + public: + explicit FakeBrowserManagerService(Profile* profile) + : BrowserManagerService(profile) {} + ~FakeBrowserManagerService() override = default; + + // Inject the mock browser to be returned. + void set_mock_browser(BrowserWindowInterface* mock) { mock_ = mock; } + + // ProfileBrowserCollection: + BrowserVector GetBrowsers(Order order) override { + if (mock_) { + return {mock_}; + } + return {}; + } + + private: + raw_ptr<BrowserWindowInterface> mock_ = nullptr; +}; // (TODO:crbug.com/394659061): We extracted the preference based retry logic to // a new class, however, we need to find a way to mock the new handler and test // the intended behavior. Explicitly the history sync on and policy controlled @@ -147,6 +205,11 @@ // will need to call `SetUpPrerequisites()` from their `SetUp()` method. void SetUpPrerequisites(bool history_sync_enabled, bool policy_controlled_sb_enabled) { + if (mock_browser_ && profile_) { + static_cast<FakeBrowserManagerService*>( + BrowserManagerServiceFactory::GetForProfile(profile_)) + ->set_mock_browser(nullptr); + } if (profile_manager_needs_setup_) { ASSERT_TRUE(profile_manager_.SetUp()); } @@ -183,13 +246,24 @@ // This may be called multiple times, we must reset the original test // browser and its associated window. - browser_.reset(); + mock_browser_.reset(); + mock_browser_ = + std::make_unique<testing::NiceMock<MockBrowserWindowInterface>>(); + ON_CALL(*mock_browser_, GetType()) + .WillByDefault(testing::Return(BrowserWindowInterface::TYPE_NORMAL)); + ON_CALL(*mock_browser_, GetProfile()) + .WillByDefault(testing::Return(profile())); + ON_CALL(*mock_browser_, IsDeleteScheduled()) + .WillByDefault(testing::Return(false)); + ON_CALL(*mock_browser_, GetWindow()) + .WillByDefault(testing::Return(&dummy_window_)); + ON_CALL(*mock_browser_, GetBrowserForMigrationOnly()) + .WillByDefault(testing::Return(nullptr)); - auto browser_window = std::make_unique<TestBrowserWindow>(); - Browser::CreateParams params(profile(), true); - params.type = Browser::TYPE_NORMAL; - params.window = browser_window.release(); - browser_ = Browser::DeprecatedCreateOwnedForTesting(params); + // Get the injected fake service and hand it the mock. + static_cast<FakeBrowserManagerService*>( + BrowserManagerServiceFactory::GetForProfile(profile())) + ->set_mock_browser(mock_browser_.get()); chrome_tailored_security_service_ = std::make_unique<TestChromeTailoredSecurityService>(profile_); } @@ -208,18 +282,24 @@ [](content::BrowserContext*) -> std::unique_ptr<KeyedService> { return std::make_unique<syncer::TestSyncService>(); })); + factories.emplace_back( + BrowserManagerServiceFactory::GetInstance(), + base::BindRepeating([](content::BrowserContext* context) + -> std::unique_ptr<KeyedService> { + return std::make_unique<FakeBrowserManagerService>( + Profile::FromBrowserContext(context)); + })); return factories; } void TearDown() override { // Remove any tabs in the tab strip otherwise the test will crash. - if (browser_) { - while (!browser_->tab_strip_model()->empty()) { - browser_->tab_strip_model()->DetachAndDeleteWebContentsAt(0); - } + if (mock_browser_ && profile_) { + static_cast<FakeBrowserManagerService*>( + BrowserManagerServiceFactory::GetForProfile(profile_)) + ->set_mock_browser(nullptr); } - - browser_.reset(); + mock_browser_.reset(); chrome_tailored_security_service_->Shutdown(); chrome_tailored_security_service_.reset(); @@ -235,26 +315,6 @@ return chrome_tailored_security_service_.get(); } - Browser* browser() { return browser_.get(); } - - // Add a tab with a test `content::WebContents` to the browser. - content::WebContents* AddTab(const GURL& url) { - std::unique_ptr<content::WebContents> web_contents( - content::WebContentsTester::CreateTestWebContents(profile(), nullptr)); - content::WebContents* raw_contents = web_contents.get(); - - browser()->tab_strip_model()->AppendWebContents(std::move(web_contents), - true); - EXPECT_EQ(browser()->tab_strip_model()->GetActiveWebContents(), - raw_contents); - - content::NavigationSimulator::NavigateAndCommitFromBrowser(raw_contents, - url); - EXPECT_EQ(url, raw_contents->GetLastCommittedURL()); - - return raw_contents; - } - sync_preferences::TestingPrefServiceSyncable* prefs() { return profile_->GetTestingPrefService(); } @@ -313,7 +373,8 @@ identity_test_env_adaptor_; TestingProfileManager profile_manager_; raw_ptr<TestingProfile> profile_; - std::unique_ptr<Browser> browser_; + std::unique_ptr<MockBrowserWindowInterface> mock_browser_; + DummyBaseWindow dummy_window_; std::unique_ptr<TestChromeTailoredSecurityService> chrome_tailored_security_service_; bool profile_manager_needs_setup_ = true; @@ -326,8 +387,7 @@ TEST_F(ChromeTailoredSecurityServiceTest, TailoredSecurityEnabledShowsEnableDialog) { SetSafeBrowsingState(prefs(), SafeBrowsingState::STANDARD_PROTECTION); - const GURL google_url("https://www.google.com"); - AddTab(google_url); + int initial_times_displayed = tailored_security_service()->times_dialog_displayed(); @@ -343,8 +403,7 @@ TEST_F(ChromeTailoredSecurityServiceTest, TailoredSecurityEnabledButHistorySyncDisabledDoesNotShowEnableDialog) { SetSafeBrowsingState(prefs(), SafeBrowsingState::STANDARD_PROTECTION); - const GURL google_url("https://www.google.com"); - AddTab(google_url); + int initial_times_displayed = tailored_security_service()->times_dialog_displayed(); @@ -362,8 +421,6 @@ TEST_F(ChromeTailoredSecurityServiceTest, TailoredSecurityEnabledButHistorySyncDisabledLogsHistoryNotSynced) { SetSafeBrowsingState(prefs(), SafeBrowsingState::STANDARD_PROTECTION); - const GURL google_url("https://www.google.com"); - AddTab(google_url); // disable history sync sync_service()->GetUserSettings()->SetSelectedTypes( @@ -381,8 +438,6 @@ TEST_F(ChromeTailoredSecurityServiceTest, TailoredSecurityEnabledButHistorySyncEnabledDoesNotLogHistoryNotSynced) { SetSafeBrowsingState(prefs(), SafeBrowsingState::STANDARD_PROTECTION); - const GURL google_url("https://www.google.com"); - AddTab(google_url); // enable history sync sync_service()->GetUserSettings()->SetSelectedTypes( @@ -399,8 +454,7 @@ TEST_F(ChromeTailoredSecurityServiceTest, TsEnabledEnablesEp) { SetSafeBrowsingState(prefs(), SafeBrowsingState::STANDARD_PROTECTION); - const GURL google_url("https://www.google.com"); - AddTab(google_url); + EXPECT_FALSE(IsEnhancedProtectionEnabled(*prefs())); tailored_security_service()->MaybeNotifySyncUser(kTailoredSecurityEnabled, base::Time::Now()); @@ -409,8 +463,7 @@ TEST_F(ChromeTailoredSecurityServiceTest, EpAlreadyEnabledDoesNotShowDialog) { SetSafeBrowsingState(prefs(), SafeBrowsingState::ENHANCED_PROTECTION); - const GURL google_url("https://www.google.com"); - AddTab(google_url); + int initial_times_displayed = tailored_security_service()->times_dialog_displayed(); tailored_security_service()->MaybeNotifySyncUser(kTailoredSecurityEnabled, @@ -421,8 +474,7 @@ TEST_F(ChromeTailoredSecurityServiceTest, EpAlreadyEnabledLeavesEpEnabled) { SetSafeBrowsingState(prefs(), SafeBrowsingState::ENHANCED_PROTECTION); - const GURL google_url("https://www.google.com"); - AddTab(google_url); + EXPECT_TRUE(IsEnhancedProtectionEnabled(*prefs())); tailored_security_service()->MaybeNotifySyncUser(kTailoredSecurityEnabled, base::Time::Now()); @@ -432,8 +484,7 @@ TEST_F(ChromeTailoredSecurityServiceTest, EpWasEnabledByTsAndTsNowDisabledShowsDialog) { SetSafeBrowsingState(prefs(), SafeBrowsingState::STANDARD_PROTECTION); - const GURL google_url("https://www.google.com"); - AddTab(google_url); + int initial_times_displayed = tailored_security_service()->times_dialog_displayed(); // Enable ESB - this will display the dialog once. @@ -456,8 +507,7 @@ TEST_F(ChromeTailoredSecurityServiceTest, EpEnabledByTsAndTsNowDisabledDisablesEp) { SetSafeBrowsingState(prefs(), SafeBrowsingState::STANDARD_PROTECTION); - const GURL google_url("https://www.google.com"); - AddTab(google_url); + // Enable ESB tailored_security_service()->MaybeNotifySyncUser(kTailoredSecurityEnabled, base::Time::Now()); @@ -474,8 +524,7 @@ TEST_F(ChromeTailoredSecurityServiceTest, SpEnabledAndTsNowDisabledDoesNotShowDialog) { SetSafeBrowsingState(prefs(), SafeBrowsingState::STANDARD_PROTECTION); - const GURL google_url("https://www.google.com"); - AddTab(google_url); + int initial_times_displayed = tailored_security_service()->times_dialog_displayed(); tailored_security_service()->MaybeNotifySyncUser(kTailoredSecurityDisabled, @@ -487,8 +536,6 @@ TEST_F(ChromeTailoredSecurityServiceTest, SpEnabledAndTsNowDisabledDoesNotChangeSb) { SetSafeBrowsingState(prefs(), SafeBrowsingState::STANDARD_PROTECTION); - const GURL google_url("https://www.google.com"); - AddTab(google_url); EXPECT_FALSE(IsEnhancedProtectionEnabled(*prefs())); EXPECT_TRUE(IsSafeBrowsingEnabled(*prefs())); @@ -502,8 +549,6 @@ TEST_F(ChromeTailoredSecurityServiceTest, EpEnabledByUserTsDisabledDoesNotShowDialog) { SetSafeBrowsingState(prefs(), SafeBrowsingState::ENHANCED_PROTECTION); - const GURL google_url("https://www.google.com"); - AddTab(google_url); int times_dialog_displayed_before = tailored_security_service()->times_dialog_displayed(); @@ -516,8 +561,6 @@ TEST_F(ChromeTailoredSecurityServiceTest, EpEnabledByUserTsDisabledDoesNotChangeSb) { SetSafeBrowsingState(prefs(), SafeBrowsingState::ENHANCED_PROTECTION); - const GURL google_url("https://www.google.com"); - AddTab(google_url); EXPECT_TRUE(IsEnhancedProtectionEnabled(*prefs())); EXPECT_FALSE(prefs()->GetBoolean(
diff --git a/chrome/browser/search_engines/android/java/src/org/chromium/chrome/browser/search_engines/settings/SearchEngineAdapter.java b/chrome/browser/search_engines/android/java/src/org/chromium/chrome/browser/search_engines/settings/SearchEngineAdapter.java index 4d30f0d1..43794973 100644 --- a/chrome/browser/search_engines/android/java/src/org/chromium/chrome/browser/search_engines/settings/SearchEngineAdapter.java +++ b/chrome/browser/search_engines/android/java/src/org/chromium/chrome/browser/search_engines/settings/SearchEngineAdapter.java
@@ -15,7 +15,6 @@ import android.view.View.AccessibilityDelegate; import android.view.View.OnClickListener; import android.view.ViewGroup; -import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; import android.widget.BaseAdapter; import android.widget.ImageView; @@ -499,13 +498,13 @@ view = mLayoutInflater.inflate(layoutId, parent, false); } + View containerView = view.findViewById(R.id.container); + if (ChromeFeatureList.sAndroidSettingsContainment.isEnabled()) { boolean isTop = position == 0 || getItemViewType(position - 1) == ViewType.DIVIDER; boolean isBottom = position == getCount() - 1 || getItemViewType(position + 1) == ViewType.DIVIDER; - View containerView = view.findViewById(R.id.container); - ContainerStyle containerStyle = mContainmentItemController .createStandardBuilder(isTop, isBottom, /* isSingleLine= */ true) @@ -547,25 +546,16 @@ updateLogo(logoView, templateUrl, faviconUrl); - // To improve the explore-by-touch experience, the radio button is hidden from accessibility - // and instead, "checked" or "not checked" is read along with the search engine's name, e.g. - // "google.com checked" or "google.com not checked". radioButton.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO); - description.setAccessibilityDelegate( - new AccessibilityDelegate() { - @Override - public void onInitializeAccessibilityEvent( - View host, AccessibilityEvent event) { - super.onInitializeAccessibilityEvent(host, event); - event.setChecked(selected); - } + containerView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO); + view.setAccessibilityDelegate( + new AccessibilityDelegate() { @Override public void onInitializeAccessibilityNodeInfo( View host, AccessibilityNodeInfo info) { super.onInitializeAccessibilityNodeInfo(host, info); - info.setCheckable(true); - info.setChecked(selected); + info.setSelected(selected); } });
diff --git a/chrome/browser/touch_to_fill/password_manager/android/javatests/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewTest.java b/chrome/browser/touch_to_fill/password_manager/android/javatests/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewTest.java index e74dc54..8db051b 100644 --- a/chrome/browser/touch_to_fill/password_manager/android/javatests/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewTest.java +++ b/chrome/browser/touch_to_fill/password_manager/android/javatests/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewTest.java
@@ -61,6 +61,7 @@ import org.chromium.base.test.util.Batch; import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.CriteriaHelper; +import org.chromium.base.test.util.DisableIf; import org.chromium.base.test.util.Features.DisableFeatures; import org.chromium.base.test.util.Features.EnableFeatures; import org.chromium.base.test.util.ScalableTimeout; @@ -83,6 +84,7 @@ import org.chromium.components.webauthn.cred_man.CredManSupportProvider; import org.chromium.content_public.browser.test.util.TouchCommon; import org.chromium.ui.accessibility.AccessibilityState; +import org.chromium.ui.base.DeviceFormFactor; import org.chromium.ui.modelutil.MVCListAdapter; import org.chromium.ui.modelutil.PropertyModel; @@ -610,6 +612,7 @@ @Test @MediumTest + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testButtonTitleWithoutAutoSubmission() { final boolean showSubmitButton = false; ThreadUtils.runOnUiThreadBlocking(
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index cd37dcb..c8a2b9a 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -1085,8 +1085,11 @@ "android/logo/logo_bridge.h", "android/omnibox/omnibox_view_util.cc", "android/omnibox/omnibox_view_util.h", + "android/overlay/immersive_overlay_window_android.cc", "android/overlay/overlay_window_android.cc", "android/overlay/overlay_window_android.h", + "android/overlay/overlay_window_android_factory.cc", + "android/overlay/picture_in_picture_overlay_window_android.cc", "android/passwords/all_passwords_bottom_sheet_view.h", "android/passwords/all_passwords_bottom_sheet_view_impl.cc", "android/passwords/all_passwords_bottom_sheet_view_impl.h",
diff --git a/chrome/browser/ui/android/digital_credentials/java/src/org/chromium/chrome/browser/ui/android/digital_credentials/DigitalIdentitySafetyInterstitialIntegrationTest.java b/chrome/browser/ui/android/digital_credentials/java/src/org/chromium/chrome/browser/ui/android/digital_credentials/DigitalIdentitySafetyInterstitialIntegrationTest.java index 27d98bb..6e0e1549 100644 --- a/chrome/browser/ui/android/digital_credentials/java/src/org/chromium/chrome/browser/ui/android/digital_credentials/DigitalIdentitySafetyInterstitialIntegrationTest.java +++ b/chrome/browser/ui/android/digital_credentials/java/src/org/chromium/chrome/browser/ui/android/digital_credentials/DigitalIdentitySafetyInterstitialIntegrationTest.java
@@ -26,6 +26,7 @@ import org.chromium.base.test.util.Criteria; import org.chromium.base.test.util.CriteriaHelper; import org.chromium.base.test.util.CriteriaNotSatisfiedException; +import org.chromium.base.test.util.DisableIf; import org.chromium.base.test.util.Features.EnableFeatures; import org.chromium.base.test.util.HistogramWatcher; import org.chromium.chrome.browser.ChromeTabbedActivity; @@ -41,6 +42,7 @@ import org.chromium.content_public.browser.test.util.DOMUtils; import org.chromium.content_public.browser.test.util.JavaScriptUtils; import org.chromium.net.test.EmbeddedTestServer; +import org.chromium.ui.base.DeviceFormFactor; import org.chromium.ui.base.WindowAndroid; import org.chromium.ui.modaldialog.ModalDialogManager; import org.chromium.ui.modaldialog.ModalDialogManager.ModalDialogManagerObserver; @@ -55,6 +57,7 @@ @RunWith(ChromeJUnit4ClassRunner.class) @Batch(Batch.PER_CLASS) @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) +@DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public class DigitalIdentitySafetyInterstitialIntegrationTest { /** * Observes shown modal dialogs.
diff --git a/chrome/browser/ui/android/extensions/windowing/internal/java/src/org/chromium/chrome/browser/ui/extensions/windowing/ExtensionWindowControllerBridgeIntegrationTest.java b/chrome/browser/ui/android/extensions/windowing/internal/java/src/org/chromium/chrome/browser/ui/extensions/windowing/ExtensionWindowControllerBridgeIntegrationTest.java index 9c7c9a7..e5cb3a3 100644 --- a/chrome/browser/ui/android/extensions/windowing/internal/java/src/org/chromium/chrome/browser/ui/extensions/windowing/ExtensionWindowControllerBridgeIntegrationTest.java +++ b/chrome/browser/ui/android/extensions/windowing/internal/java/src/org/chromium/chrome/browser/ui/extensions/windowing/ExtensionWindowControllerBridgeIntegrationTest.java
@@ -3,6 +3,8 @@ // found in the LICENSE file. package org.chromium.chrome.browser.ui.extensions.windowing; +import org.chromium.base.test.util.DisableIf; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; @@ -149,6 +151,7 @@ @Test @MediumTest @Restriction(DeviceFormFactor.TABLET_OR_DESKTOP /* Test needs "new window" in app menu. */) + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void startChromeTabbedActivity_openNewWindow_notifyExtensionInternalsOfWindowCreation() { // Arrange: // (1) Launch ChromeTabbedActivity (the first window). @@ -186,6 +189,7 @@ @Test @MediumTest @Restriction(DeviceFormFactor.TABLET_OR_DESKTOP /* Test needs "new window" in app menu. */) + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void openIncognitoWindow_destroyIncognitoTabModel_notifyExtensionInternalsOfWindowDestruction() { // Arrange: @@ -363,6 +367,7 @@ @Test @MediumTest @Restriction(DeviceFormFactor.TABLET_OR_DESKTOP /* Test needs "new window" in app menu. */) + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void startChromeTabbedActivity_triggerTaskFocusChange_notifyExtensionWindowController() { // Arrange: // (1) Launch ChromeTabbedActivity (the first window).
diff --git a/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/InstanceSwitcherCoordinatorTest.java b/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/InstanceSwitcherCoordinatorTest.java index 683aa87..7b94584 100644 --- a/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/InstanceSwitcherCoordinatorTest.java +++ b/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/InstanceSwitcherCoordinatorTest.java
@@ -63,6 +63,7 @@ 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.DisableIf; import org.chromium.base.test.util.Features.EnableFeatures; import org.chromium.base.test.util.Restriction; import org.chromium.chrome.browser.flags.ChromeFeatureList; @@ -1336,6 +1337,7 @@ @Test @SmallTest + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testCancelRenameWindow() throws Exception { InstanceInfo[] instances = createPersistedInstances( @@ -1778,6 +1780,7 @@ @Test @SmallTest + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testMoreButtonHiddenWhenListIsEmpty() throws Exception { // 1 active, 1 inactive instance. InstanceInfo[] instances =
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/fusebox/FuseboxPopup.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/fusebox/FuseboxPopup.java index cbdc4e7..a092089e1 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/fusebox/FuseboxPopup.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/fusebox/FuseboxPopup.java
@@ -52,6 +52,7 @@ /* package */ final List<TextView> mHeaders; private final DynamicRectProvider mDynamicRectProvider; + private @PopupState int mCurrentState = PopupState.HIDDEN; FuseboxPopup( Context context, @@ -62,6 +63,16 @@ mPopupWindow = popupWindow; mDynamicRectProvider = dynamicRectProvider; mViewGroup = contentView.findViewById(R.id.fusebox_view_group); + mViewGroup.addOnLayoutChangeListener( + (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> { + if (bottom - top != oldBottom - oldTop) { + PostTask.postTask( + TaskTraits.UI_DEFAULT, + () -> { + updateLayout(); + }); + } + }); ViewStub stub = contentView.findViewById(R.id.fusebox_attachments_stub); stub.setLayoutResource( @@ -140,6 +151,7 @@ * @param state The target state of the popup. */ void setPopupState(@PopupState int state) { + mCurrentState = state; if (state == FuseboxProperties.PopupState.BOTTOM) { mPopupWindow.setAnimationStyle(R.style.FuseboxBottomSheetAnimation); } else { @@ -155,13 +167,20 @@ return; } - int width = - mDynamicRectProvider.getPopupWidth(state, mViewGroup.getContext().getResources()); - - mPopupWindow.updateDesiredContentSize(width, /* height= */ 0, /* updateLayout= */ true); + updateLayout(); show(); } + /** + * Update the layout of the popup if it is showing. This is useful when contents change + * visibility. + */ + void updateLayout() { + if (!isShowing() || mCurrentState == PopupState.HIDDEN) return; + int width = mDynamicRectProvider.getPopupWidth(mCurrentState, mViewGroup.getResources()); + mPopupWindow.updateDesiredContentSize(width, /* height= */ 0, /* updateLayout= */ true); + } + private void initializeItem(View item, int textRes, int iconRes, int a11yRes) { TextView actionText = item.findViewById(R.id.action_text); actionText.setText(textRes);
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/fusebox/FuseboxPopupUnitTest.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/fusebox/FuseboxPopupUnitTest.java index 3442a383..142a0e2 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/fusebox/FuseboxPopupUnitTest.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/fusebox/FuseboxPopupUnitTest.java
@@ -5,10 +5,14 @@ package org.chromium.chrome.browser.omnibox.fusebox; import static org.junit.Assert.assertNotNull; +import static org.mockito.Mockito.any; import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.eq; import static org.mockito.Mockito.verify; import android.app.Activity; +import android.os.Looper; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -22,6 +26,7 @@ import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; import org.robolectric.Robolectric; +import org.robolectric.Shadows; import org.robolectric.annotation.Config; import org.chromium.base.test.BaseRobolectricTestRunner; @@ -121,6 +126,7 @@ @Test public void testSetPopupState_Floating() { mFuseboxPopup.setPopupState(FuseboxProperties.PopupState.FLOATING); + Shadows.shadowOf(Looper.getMainLooper()).idle(); verify(mDynamicRectProvider).setPopupState(FuseboxProperties.PopupState.FLOATING); verify(mPopupWindow).show(); } @@ -185,4 +191,19 @@ assertNotNull(mFuseboxPopup.mGalleryButton); assertNotNull(mFuseboxPopup.mFileButton); } + + @Test + public void testUpdateLayout() { + doReturn(100) + .when(mDynamicRectProvider) + .getPopupWidth(eq(FuseboxProperties.PopupState.FLOATING), any()); + + doReturn(true).when(mPopupWindow).isShowing(); + + mFuseboxPopup.setPopupState(FuseboxProperties.PopupState.FLOATING); + + Shadows.shadowOf(Looper.getMainLooper()).idle(); + + verify(mPopupWindow, atLeastOnce()).updateDesiredContentSize(100, 0, true); + } }
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 b02dcf8..4d03604 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
@@ -399,6 +399,8 @@ return R.drawable.ic_timer; } else if (iconId == IconResourceIds.BOLT_VALUE) { return R.drawable.bolt_24dp; + } else if (iconId == IconResourceIds.TASK_SPARK_VALUE) { + return R.drawable.task_spark_24dp; } return Resources.ID_NULL; }
diff --git a/chrome/browser/ui/android/overlay/immersive_overlay_window_android.cc b/chrome/browser/ui/android/overlay/immersive_overlay_window_android.cc new file mode 100644 index 0000000..db92059 --- /dev/null +++ b/chrome/browser/ui/android/overlay/immersive_overlay_window_android.cc
@@ -0,0 +1,79 @@ +// 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/android/jni_android.h" +#include "base/android/jni_array.h" +#include "base/android/unguessable_token_android.h" +#include "base/check.h" +#include "base/no_destructor.h" +#include "cc/slim/surface_layer.h" +#include "chrome/android/chrome_jni_headers/XrModuleBridge_jni.h" +#include "chrome/browser/android/tab_android.h" +#include "chrome/browser/ui/android/overlay/overlay_window_android.h" +#include "content/public/browser/video_picture_in_picture_window_controller.h" +#include "content/public/browser/web_contents.h" +#include "media/base/media_switches.h" +#include "third_party/blink/public/mojom/picture_in_picture/picture_in_picture.mojom.h" + +// ImmersiveOverlayWindowAndroid provides an implementation of the +// VideoOverlayWindow for Android XR, utilizing a Java-side Activity to display +// the video content in an immersive environment. +class ImmersiveOverlayWindowAndroid : public OverlayWindowAndroid { + public: + explicit ImmersiveOverlayWindowAndroid( + content::VideoPictureInPictureWindowController* controller) + : OverlayWindowAndroid(controller) { + CreateJavaActivity(); + } + + ~ImmersiveOverlayWindowAndroid() override { OnWindowDestroyedJava(); } + + // VideoOverlayWindow implementation. + void SetImmersiveVideoOptions( + blink::mojom::ImmersiveOptionsPtr options) override { + immersive_options_ = std::move(options); + SetImmersiveVideoOptionsJava(immersive_options_); + } + + void Initialize( + JNIEnv* env, + const base::android::JavaRef<jobject>& self, + const base::android::JavaRef<jobject>& jwindow_android) override { + OverlayWindowAndroid::Initialize(env, self, jwindow_android); + + if (immersive_options_) { + SetImmersiveVideoOptionsJava(immersive_options_); + } + } + + void UpdateNaturalSize(const gfx::Size& natural_size) override { + video_size_ = natural_size; + surface_layer_->SetBounds(natural_size); + UpdateVideoSizeJava(natural_size.width(), natural_size.height()); + } + + gfx::Rect GetBounds() override { return gfx::Rect(video_size_); } + + private: + void CreateJavaActivity() override { + auto* web_contents = controller_->GetWebContents(); + JNIEnv* env = base::android::AttachCurrentThread(); + auto j_token = base::android::UnguessableTokenAndroid::Create(env, token_); + Java_XrModuleBridge_createImmersiveVideoPlaybackActivity( + env, j_token, + TabAndroid::FromWebContents(web_contents)->GetJavaObject()); + } + + blink::mojom::ImmersiveOptionsPtr immersive_options_; +}; + +std::unique_ptr<content::VideoOverlayWindow> +CreateImmersiveOverlayWindowAndroid( + content::VideoPictureInPictureWindowController* controller) { + JNIEnv* env = base::android::AttachCurrentThread(); + // Immersive sessions are only initialized after the XR module is installed. + CHECK(Java_XrModuleBridge_isModuleInstalled(env)); + + return std::make_unique<ImmersiveOverlayWindowAndroid>(controller); +}
diff --git a/chrome/browser/ui/android/overlay/overlay_window_android.cc b/chrome/browser/ui/android/overlay/overlay_window_android.cc index 939ddb7..38a4004 100644 --- a/chrome/browser/ui/android/overlay/overlay_window_android.cc +++ b/chrome/browser/ui/android/overlay/overlay_window_android.cc
@@ -7,10 +7,11 @@ #include "base/android/jni_android.h" #include "base/android/jni_array.h" #include "base/android/unguessable_token_android.h" +#include "base/containers/flat_map.h" #include "base/memory/ptr_util.h" #include "base/no_destructor.h" #include "cc/slim/surface_layer.h" -#include "chrome/android/chrome_jni_headers/PictureInPictureActivity_jni.h" +#include "chrome/android/chrome_jni_headers/VideoOverlayActivity_jni.h" #include "chrome/browser/android/tab_android.h" #include "chrome/browser/picture_in_picture/auto_picture_in_picture_tab_helper.h" #include "components/thin_webview/compositor_view.h" @@ -31,10 +32,10 @@ } // namespace // static -std::unique_ptr<content::VideoOverlayWindow> -content::VideoOverlayWindow::Create( - VideoPictureInPictureWindowController* controller) { - return std::make_unique<OverlayWindowAndroid>(controller); +OverlayWindowAndroid* OverlayWindowAndroid::FromToken( + const base::UnguessableToken& token) { + auto iter = GetWindowMap().find(token); + return (iter == GetWindowMap().end()) ? nullptr : iter->second; } OverlayWindowAndroid::OverlayWindowAndroid( @@ -49,96 +50,11 @@ surface_layer_->SetIsDrawable(true); surface_layer_->SetStretchContentToFillBounds(true); surface_layer_->SetBackgroundColor(SkColors::kBlack); - - auto* web_contents = controller_->GetWebContents(); - - // Compute the screen position of the video, and see if it fits inside the - // WebContents or if it's clipped / off-screen. If it's onscreen, then T and - // later, Android can do a nicer animated transition to PiP with a screen - // capture of the video. However, if the video is clipped / offscreen, then - // it'll look nicer to use the default light grey transition. - - // We provide a small buffer for what "clipped" means, rather than enforcing - // it strictly. It'll still look fine while allowing small positioning errors - // that sites sometimes make. See https://crbug.com/40254849 for an example. - - // The java side will ignore any source bounds that are not on the screen for - // the source rect hint. It will use the aspect ratio only in that case. We - // set the x position to be <0 to ensure this, to skip the transition. - - // Get the size of the video, and inset it to provide some slack. - gfx::Rect source_bounds = controller_->GetSourceBounds(); - gfx::Rect smaller_source_bounds = source_bounds; - constexpr int inset_size = 4; // pixels on each side - smaller_source_bounds.Inset(inset_size); - - // Get the size of the WebContents, and convert to pixels. - gfx::Rect unscaled_content_bounds = web_contents->GetContainerBounds(); - auto* native_view = web_contents->GetNativeView(); - const float dip_scale = native_view->GetDipScale(); - gfx::Rect content_bounds(unscaled_content_bounds.x() * dip_scale, - unscaled_content_bounds.y() * dip_scale, - unscaled_content_bounds.width() * dip_scale, - unscaled_content_bounds.height() * dip_scale); - const bool out_of_bounds = !content_bounds.Contains(smaller_source_bounds); - // Use the new source location based transition when the source is not out of - // bound and the AllowEnhancedPipTransition feature is enabled. - // TODO(crbug.com/440384447): remove AllowEnhancedPipTransition check once the - // new transition works properly on desktop Android. - const bool use_source_hint_transition = - !out_of_bounds && - base::FeatureList::IsEnabled(media::kAllowEnhancedPipTransition); - - if (use_source_hint_transition) { - // Use the newer transition, if available. - // Convert to screen space. Since the comparison was with the inset source - // bounds, clamp the real source bounds to the container. - source_bounds.Intersect(content_bounds); - gfx::PointF offset = native_view->GetLocationOnScreen(0, 0); - source_bounds.Offset( - static_cast<int>(offset.x()), - static_cast<int>(offset.y()) + - native_view->content_offset() * native_view->GetDipScale()); - } else { - // Use the old transition. - // Slide this offscreen, while keeping the aspect ratio the same. - source_bounds.set_x(-1); - } - - JNIEnv* env = base::android::AttachCurrentThread(); - auto j_token = base::android::UnguessableTokenAndroid::Create(env, token_); - Java_PictureInPictureActivity_createActivity( - env, j_token, TabAndroid::FromWebContents(web_contents)->GetJavaObject(), - source_bounds.x(), source_bounds.y(), source_bounds.width(), - source_bounds.height()); } OverlayWindowAndroid::~OverlayWindowAndroid() { // Any future use of our token will fail. GetWindowMap().erase(token_); - if (java_ref_.is_uninitialized()) { - return; - } - // Notify the java side that the native side is gone. - JNIEnv* env = base::android::AttachCurrentThread(); - Java_PictureInPictureActivity_onWindowDestroyed(env, java_ref_.get(env)); -} - -static int64_t JNI_PictureInPictureActivity_OnActivityStart( - JNIEnv* env, - const jni_zero::JavaRef<jobject>& j_token, - const jni_zero::JavaRef<jobject>& self, - const jni_zero::JavaRef<jobject>& window) { - auto token = base::android::UnguessableTokenAndroid::FromJavaUnguessableToken( - env, j_token); - auto iter = GetWindowMap().find(token); - if (iter == GetWindowMap().end()) { - return 0; - } - OverlayWindowAndroid* thiz = iter->second; - thiz->Initialize(env, self, window); - - return reinterpret_cast<int64_t>(thiz); } void OverlayWindowAndroid::Initialize( @@ -149,23 +65,21 @@ window_android_ = ui::WindowAndroid::FromJavaWindowAndroid(jwindow_android); window_android_->AddObserver(this); - Java_PictureInPictureActivity_setPlaybackState(env, java_ref_.get(env), - playback_state_); - Java_PictureInPictureActivity_setMicrophoneMuted(env, java_ref_.get(env), - microphone_muted_); - Java_PictureInPictureActivity_setCameraState(env, java_ref_.get(env), - camera_on_); + SetPlaybackStateJava(playback_state_); + SetMicrophoneMutedJava(microphone_muted_); + SetCameraStateJava(camera_on_); if (!update_action_timer_->IsRunning()) { MaybeNotifyVisibleActionsChanged(); } - if (video_size_.IsEmpty()) { - return; + if (!video_size_.IsEmpty()) { + UpdateVideoSizeJava(video_size_.width(), video_size_.height()); } - Java_PictureInPictureActivity_updateVideoSize( - env, java_ref_.get(env), video_size_.width(), video_size_.height()); + if (media_position_.has_value()) { + SetMediaPositionJava(media_position_.value()); + } } void OverlayWindowAndroid::OnAttachCompositor() { @@ -254,6 +168,10 @@ controller_->HangUp(); } +void OverlayWindowAndroid::SeekTo(JNIEnv* env, int64_t position_ms) { + controller_->SeekTo(base::Milliseconds(position_ms)); +} + void OverlayWindowAndroid::Hide(JNIEnv* env) { if (auto* web_contents = controller_->GetWebContents()) { if (auto* helper = @@ -325,6 +243,114 @@ } } +static int64_t JNI_VideoOverlayActivity_OnActivityStart( + JNIEnv* env, + const jni_zero::JavaRef<jobject>& j_token, + const jni_zero::JavaRef<jobject>& self, + const jni_zero::JavaRef<jobject>& window) { + auto token = base::android::UnguessableTokenAndroid::FromJavaUnguessableToken( + env, j_token); + OverlayWindowAndroid* thiz = OverlayWindowAndroid::FromToken(token); + if (!thiz) { + return 0; + } + thiz->Initialize(env, self, window); + return reinterpret_cast<int64_t>(thiz); +} + +void OverlayWindowAndroid::OnWindowDestroyedJava() { + JNIEnv* env = base::android::AttachCurrentThread(); + base::android::ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); + if (obj.is_null()) { + return; + } + Java_VideoOverlayActivity_onWindowDestroyed(env, obj); +} + +void OverlayWindowAndroid::UpdateVideoSizeJava(int width, int height) { + JNIEnv* env = base::android::AttachCurrentThread(); + base::android::ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); + if (obj.is_null()) { + return; + } + Java_VideoOverlayActivity_updateVideoSize(env, obj, width, height); +} + +void OverlayWindowAndroid::SetPlaybackStateJava(PlaybackState playback_state) { + JNIEnv* env = base::android::AttachCurrentThread(); + base::android::ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); + if (obj.is_null()) { + return; + } + Java_VideoOverlayActivity_setPlaybackState(env, obj, + static_cast<int>(playback_state)); +} + +void OverlayWindowAndroid::CloseJava() { + JNIEnv* env = base::android::AttachCurrentThread(); + base::android::ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); + if (obj.is_null()) { + return; + } + Java_VideoOverlayActivity_close(env, obj); +} + +void OverlayWindowAndroid::UpdateVisibleActionsJava( + const std::vector<int>& actions) { + JNIEnv* env = base::android::AttachCurrentThread(); + base::android::ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); + if (obj.is_null()) { + return; + } + Java_VideoOverlayActivity_updateVisibleActions( + env, obj, base::android::ToJavaIntArray(env, actions)); +} + +void OverlayWindowAndroid::SetMicrophoneMutedJava(bool muted) { + JNIEnv* env = base::android::AttachCurrentThread(); + base::android::ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); + if (obj.is_null()) { + return; + } + Java_VideoOverlayActivity_setMicrophoneMuted(env, obj, muted); +} + +void OverlayWindowAndroid::SetCameraStateJava(bool turned_on) { + JNIEnv* env = base::android::AttachCurrentThread(); + base::android::ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); + if (obj.is_null()) { + return; + } + Java_VideoOverlayActivity_setCameraState(env, obj, turned_on); +} + +void OverlayWindowAndroid::SetMediaPositionJava( + const media_session::MediaPosition& position) { + JNIEnv* env = base::android::AttachCurrentThread(); + base::android::ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); + if (obj.is_null()) { + return; + } + Java_VideoOverlayActivity_setMediaPosition( + env, obj, position.duration().InMilliseconds(), + position.GetPosition().InMilliseconds(), position.playback_rate()); +} + +void OverlayWindowAndroid::SetImmersiveVideoOptionsJava( + const blink::mojom::ImmersiveOptionsPtr& immersive_options) { + if (!immersive_options) { + return; + } + JNIEnv* env = base::android::AttachCurrentThread(); + base::android::ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); + if (obj.is_null()) { + return; + } + Java_VideoOverlayActivity_setImmersiveVideoOptions( + env, obj, static_cast<int>(immersive_options->stereo_mode), + static_cast<int>(immersive_options->projection_type)); +} + void OverlayWindowAndroid::Close() { CloseInternal(); // Only pause the video when play/pause button is visible. @@ -349,8 +375,7 @@ DCHECK(window_android_); window_android_->RemoveObserver(this); window_android_ = nullptr; - JNIEnv* env = base::android::AttachCurrentThread(); - Java_PictureInPictureActivity_close(env, java_ref_.get(env)); + CloseJava(); // The java side forgets about us on close, so don't call back. java_ref_.reset(); @@ -389,10 +414,7 @@ bounds_.set_size(natural_size); return; } - - JNIEnv* env = base::android::AttachCurrentThread(); - Java_PictureInPictureActivity_updateVideoSize( - env, java_ref_.get(env), natural_size.width(), natural_size.height()); + UpdateVideoSizeJava(natural_size.width(), natural_size.height()); } void OverlayWindowAndroid::SetPlaybackState(PlaybackState playback_state) { @@ -401,13 +423,13 @@ } playback_state_ = playback_state; - if (java_ref_.is_uninitialized()) { - return; - } + SetPlaybackStateJava(playback_state); +} - JNIEnv* env = base::android::AttachCurrentThread(); - Java_PictureInPictureActivity_setPlaybackState(env, java_ref_.get(env), - playback_state); +void OverlayWindowAndroid::SetMediaPosition( + const media_session::MediaPosition& position) { + media_position_ = position; + SetMediaPositionJava(position); } void OverlayWindowAndroid::SetMicrophoneMuted(bool muted) { @@ -416,13 +438,7 @@ } microphone_muted_ = muted; - if (java_ref_.is_uninitialized()) { - return; - } - - JNIEnv* env = base::android::AttachCurrentThread(); - Java_PictureInPictureActivity_setMicrophoneMuted(env, java_ref_.get(env), - microphone_muted_); + SetMicrophoneMutedJava(microphone_muted_); } void OverlayWindowAndroid::SetCameraState(bool turned_on) { @@ -431,13 +447,7 @@ } camera_on_ = turned_on; - if (java_ref_.is_uninitialized()) { - return; - } - - JNIEnv* env = base::android::AttachCurrentThread(); - Java_PictureInPictureActivity_setCameraState(env, java_ref_.get(env), - camera_on_); + SetCameraStateJava(camera_on_); } void OverlayWindowAndroid::SetPlayPauseButtonVisibility(bool is_visible) { @@ -514,13 +524,8 @@ if (java_ref_.is_uninitialized()) { return; } - - JNIEnv* env = base::android::AttachCurrentThread(); - Java_PictureInPictureActivity_updateVisibleActions( - env, java_ref_.get(env), - base::android::ToJavaIntArray( - env, - std::vector<int>(visible_actions_.begin(), visible_actions_.end()))); + UpdateVisibleActionsJava( + std::vector<int>(visible_actions_.begin(), visible_actions_.end())); } void OverlayWindowAndroid::MaybeUpdateVisibleAction( @@ -546,4 +551,4 @@ } } -DEFINE_JNI(PictureInPictureActivity) +DEFINE_JNI(VideoOverlayActivity)
diff --git a/chrome/browser/ui/android/overlay/overlay_window_android.h b/chrome/browser/ui/android/overlay/overlay_window_android.h index a7035f3..f01f2d3 100644 --- a/chrome/browser/ui/android/overlay/overlay_window_android.h +++ b/chrome/browser/ui/android/overlay/overlay_window_android.h
@@ -31,15 +31,10 @@ class OverlayWindowAndroid : public content::VideoOverlayWindow, public ui::WindowAndroidObserver { public: + static OverlayWindowAndroid* FromToken(const base::UnguessableToken& token); explicit OverlayWindowAndroid( content::VideoPictureInPictureWindowController* controller); ~OverlayWindowAndroid() override; - - static OverlayWindowAndroid* OnActivityStart( - JNIEnv* env, - const base::android::JavaRef<jobject>& token, - - const base::android::JavaRef<jobject>& jwindow_android); void DestroyStartedByJava(JNIEnv* env); void TogglePlayPause(JNIEnv* env, bool toggleOn); void NextTrack(JNIEnv* env); @@ -53,9 +48,10 @@ void CompositorViewCreated( JNIEnv* env, const base::android::JavaRef<jobject>& compositor_view); - void OnViewSizeChanged(JNIEnv* env, int32_t width, int32_t height); + virtual void OnViewSizeChanged(JNIEnv* env, int32_t width, int32_t height); void OnBackToTab(JNIEnv* env); void OnDismissal(JNIEnv* env); + void SeekTo(JNIEnv* env, int64_t position_ms); // ui::WindowAndroidObserver implementation. void OnRootWindowVisibilityChanged(bool visible) override {} @@ -87,7 +83,7 @@ void SetHangUpButtonVisibility(bool is_visible) override; void SetNextSlideButtonVisibility(bool is_visible) override; void SetPreviousSlideButtonVisibility(bool is_visible) override; - void SetMediaPosition(const media_session::MediaPosition&) override {} + void SetMediaPosition(const media_session::MediaPosition&) override; void SetSourceTitle(const std::u16string& source_title) override {} void SetFaviconImages( const std::vector<media_session::MediaImage>& images) override {} @@ -96,14 +92,23 @@ void SetImmersiveVideoOptions( blink::mojom::ImmersiveOptionsPtr options) override {} - void Initialize(JNIEnv* env, - const base::android::JavaRef<jobject>& self, - const base::android::JavaRef<jobject>& jwindow_android); + virtual void Initialize( + JNIEnv* env, + const base::android::JavaRef<jobject>& self, + const base::android::JavaRef<jobject>& jwindow_android); - private: - // Notify PictureInPictureActivity that visible actions have changed. - void MaybeNotifyVisibleActionsChanged(); + void OnWindowDestroyedJava(); + void UpdateVideoSizeJava(int width, int height); + void SetPlaybackStateJava(PlaybackState playback_state); + void CloseJava(); + void UpdateVisibleActionsJava(const std::vector<int>& actions); + void SetMicrophoneMutedJava(bool muted); + void SetCameraStateJava(bool turned_on); + void SetMediaPositionJava(const media_session::MediaPosition& position); + void SetImmersiveVideoOptionsJava( + const blink::mojom::ImmersiveOptionsPtr& immersive_options); + protected: // Maybe update visible actions. Returns true if update happened. void MaybeUpdateVisibleAction( const media_session::mojom::MediaSessionAction& action, @@ -123,6 +128,7 @@ PlaybackState playback_state_ = PlaybackState::kEndOfVideo; absl::flat_hash_set<int> visible_actions_; + std::optional<media_session::MediaPosition> media_position_; bool microphone_muted_ = false; bool camera_on_ = false; @@ -130,6 +136,10 @@ std::unique_ptr<base::OneShotTimer> update_action_timer_; raw_ptr<content::VideoPictureInPictureWindowController> controller_; + + private: + void MaybeNotifyVisibleActionsChanged(); + virtual void CreateJavaActivity() = 0; }; #endif // CHROME_BROWSER_UI_ANDROID_OVERLAY_OVERLAY_WINDOW_ANDROID_H_
diff --git a/chrome/browser/ui/android/overlay/overlay_window_android_factory.cc b/chrome/browser/ui/android/overlay/overlay_window_android_factory.cc new file mode 100644 index 0000000..8724d46 --- /dev/null +++ b/chrome/browser/ui/android/overlay/overlay_window_android_factory.cc
@@ -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. + +#include <memory> + +#include "content/public/browser/overlay_window.h" +#include "content/public/browser/video_picture_in_picture_window_controller.h" + +std::unique_ptr<content::VideoOverlayWindow> +CreateImmersiveOverlayWindowAndroid( + content::VideoPictureInPictureWindowController* controller); + +std::unique_ptr<content::VideoOverlayWindow> +CreatePictureInPictureOverlayWindowAndroid( + content::VideoPictureInPictureWindowController* controller); + +// VideoOverlayWindow::Create is the platform-specific factory method for +// creating a video overlay window. On Android, it selects between a standard +// Picture-in-Picture window and an immersive playback window based on the +// session's immersive state. +std::unique_ptr<content::VideoOverlayWindow> +content::VideoOverlayWindow::Create( + content::VideoPictureInPictureWindowController* controller) { + if (controller->IsImmersive()) { + return CreateImmersiveOverlayWindowAndroid(controller); + } + return CreatePictureInPictureOverlayWindowAndroid(controller); +}
diff --git a/chrome/browser/ui/android/overlay/picture_in_picture_overlay_window_android.cc b/chrome/browser/ui/android/overlay/picture_in_picture_overlay_window_android.cc new file mode 100644 index 0000000..5db99276 --- /dev/null +++ b/chrome/browser/ui/android/overlay/picture_in_picture_overlay_window_android.cc
@@ -0,0 +1,101 @@ +// 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/android/jni_android.h" +#include "base/android/jni_array.h" +#include "base/android/unguessable_token_android.h" +#include "base/no_destructor.h" +#include "chrome/android/chrome_jni_headers/PictureInPictureActivity_jni.h" +#include "chrome/browser/android/tab_android.h" +#include "chrome/browser/ui/android/overlay/overlay_window_android.h" +#include "content/public/browser/video_picture_in_picture_window_controller.h" +#include "content/public/browser/web_contents.h" +#include "media/base/media_switches.h" + +// PictureInPictureOverlayWindowAndroid provides an implementation of the +// VideoOverlayWindow for Android, utilizing a Java-side Activity to display +// the video content in a Picture-in-Picture window. +class PictureInPictureOverlayWindowAndroid : public OverlayWindowAndroid { + public: + explicit PictureInPictureOverlayWindowAndroid( + content::VideoPictureInPictureWindowController* controller) + : OverlayWindowAndroid(controller) { + CreateJavaActivity(); + } + + ~PictureInPictureOverlayWindowAndroid() override { OnWindowDestroyedJava(); } + + private: + void CreateJavaActivity() override { + auto* web_contents = controller_->GetWebContents(); + + // Compute the screen position of the video, and see if it fits inside the + // WebContents or if it's clipped / off-screen. If it's onscreen, then T + // and later, Android can do a nicer animated transition to PiP with a + // screen capture of the video. However, if the video is clipped / + // offscreen, then it'll look nicer to use the default light grey + // transition. + // We provide a small buffer for what "clipped" means, rather than enforcing + // it strictly. It'll still look fine while allowing small positioning + // errors that sites sometimes make. See https://crbug.com/40254849 for an + // example. + // The java side will ignore any source bounds that are not on the screen + // for the source rect hint. It will use the aspect ratio only in that case. + // We set the x position to be <0 to ensure this, to skip the transition. + // Get the size of the video, and inset it to provide some slack. + gfx::Rect source_bounds = controller_->GetSourceBounds(); + gfx::Rect smaller_source_bounds = source_bounds; + constexpr int inset_size = 4; // pixels on each side + smaller_source_bounds.Inset(inset_size); + + // Get the size of the WebContents, and convert to pixels. + gfx::Rect unscaled_content_bounds = web_contents->GetContainerBounds(); + auto* native_view = web_contents->GetNativeView(); + const float dip_scale = native_view->GetDipScale(); + gfx::Rect content_bounds(unscaled_content_bounds.x() * dip_scale, + unscaled_content_bounds.y() * dip_scale, + unscaled_content_bounds.width() * dip_scale, + unscaled_content_bounds.height() * dip_scale); + const bool out_of_bounds = !content_bounds.Contains(smaller_source_bounds); + // Use the new source location based transition when the source is not out + // of bound and the AllowEnhancedPipTransition feature is enabled. + // TODO(crbug.com/440384447): remove AllowEnhancedPipTransition check once + // the new transition works properly on desktop Android. + const bool use_source_hint_transition = + !out_of_bounds && + base::FeatureList::IsEnabled(media::kAllowEnhancedPipTransition); + + if (use_source_hint_transition) { + // Use the newer transition, if available. + // Convert to screen space. Since the comparison was with the inset + // source bounds, clamp the real source bounds to the container. + source_bounds.Intersect(content_bounds); + gfx::PointF offset = native_view->GetLocationOnScreen(0, 0); + source_bounds.Offset( + static_cast<int>(offset.x()), + static_cast<int>(offset.y()) + + native_view->content_offset() * native_view->GetDipScale()); + } else { + // Use the old transition. + // Slide this offscreen, while keeping the aspect ratio the same. + source_bounds.set_x(-1); + } + + JNIEnv* env = base::android::AttachCurrentThread(); + auto j_token = base::android::UnguessableTokenAndroid::Create(env, token_); + Java_PictureInPictureActivity_createActivity( + env, j_token, + TabAndroid::FromWebContents(web_contents)->GetJavaObject(), + source_bounds.x(), source_bounds.y(), source_bounds.width(), + source_bounds.height()); + } +}; + +std::unique_ptr<content::VideoOverlayWindow> +CreatePictureInPictureOverlayWindowAndroid( + content::VideoPictureInPictureWindowController* controller) { + return std::make_unique<PictureInPictureOverlayWindowAndroid>(controller); +} + +DEFINE_JNI(PictureInPictureActivity)
diff --git a/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/history_sync/HistorySyncRenderTest.java b/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/history_sync/HistorySyncRenderTest.java index 6e526b3..8926752 100644 --- a/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/history_sync/HistorySyncRenderTest.java +++ b/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/history_sync/HistorySyncRenderTest.java
@@ -16,6 +16,7 @@ import androidx.appcompat.app.AppCompatDelegate; import androidx.test.filters.MediumTest; +import org.junit.Assume; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -25,6 +26,7 @@ import org.mockito.junit.MockitoRule; import org.mockito.quality.Strictness; +import org.chromium.base.DeviceInfo; import org.chromium.base.ThreadUtils; import org.chromium.base.test.BaseActivityTestRule; import org.chromium.base.test.params.ParameterAnnotations; @@ -111,6 +113,8 @@ @ParameterAnnotations.UseMethodParameterBefore( HistorySyncRenderTest.NightModeAndOrientationParameterProvider.class) public void setupNightModeAndDeviceOrientation(boolean nightModeEnabled, int orientation) { + Assume.assumeFalse( + DeviceInfo.isDesktop() && orientation == Configuration.ORIENTATION_PORTRAIT); ThreadUtils.runOnUiThreadBlocking( () -> { AppCompatDelegate.setDefaultNightMode(
diff --git a/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/history_sync/HistorySyncTest.java b/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/history_sync/HistorySyncTest.java index 7b07de29..39f71d7f 100644 --- a/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/history_sync/HistorySyncTest.java +++ b/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/history_sync/HistorySyncTest.java
@@ -44,10 +44,12 @@ import org.chromium.base.test.BaseActivityTestRule; import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.CriteriaHelper; +import org.chromium.base.test.util.DisableIf; import org.chromium.base.test.util.DoNotBatch; import org.chromium.base.test.util.Features.DisableFeatures; import org.chromium.base.test.util.Features.EnableFeatures; import org.chromium.base.test.util.HistogramWatcher; +import org.chromium.base.test.util.Restriction; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.browser.profiles.ProfileManager; import org.chromium.chrome.browser.sync.SyncServiceFactory; @@ -62,6 +64,7 @@ import org.chromium.components.sync.SyncService; import org.chromium.content_public.browser.test.ContentJUnit4ClassRunner; import org.chromium.content_public.browser.test.NativeLibraryTestUtils; +import org.chromium.ui.base.DeviceFormFactor; import org.chromium.ui.test.util.BlankUiTestActivity; import org.chromium.ui.test.util.ViewUtils; @@ -208,6 +211,7 @@ @Test @MediumTest + @DisableIf.Device(DeviceFormFactor.DESKTOP_FREEFORM) // crbug.com/444482498 public void testPositiveButtonWithNonMinorModeAccount() { HistogramWatcher histogramWatcher = HistogramWatcher.newBuilder() @@ -340,6 +344,7 @@ @Test @MediumTest + @Restriction(DeviceFormFactor.PHONE_OR_TABLET) public void testButtonsEquallyWeightedWithMinorAccount_portraitMode() { Activity historySyncActivity = mActivityTestRule.getActivity(); ActivityTestUtils.rotateActivityToOrientation( @@ -395,6 +400,7 @@ @Test @MediumTest + @Restriction(DeviceFormFactor.PHONE_OR_TABLET) public void testButtonsUnequallyWeightedWithNonMinorAccount_portraitMode() { Activity historySyncActivity = mActivityTestRule.getActivity(); ActivityTestUtils.rotateActivityToOrientation(
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuItemProperties.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuItemProperties.java index 4c511bf..c9fd3483 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuItemProperties.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuItemProperties.java
@@ -55,6 +55,9 @@ public static final WritableObjectPropertyKey<String> SITE_PERMISSIONS_BUTTON_TEXT = new WritableObjectPropertyKey<>(); + public static final WritableObjectPropertyKey<String> SITE_PERMISSIONS_BUTTON_TOOLTIP = + new WritableObjectPropertyKey<>(); + public static final WritableObjectPropertyKey<String> SITE_PERMISSIONS_BUTTON_ACCESSIBLE_NAME = new WritableObjectPropertyKey<>(); @@ -76,6 +79,7 @@ SITE_PERMISSIONS_BUTTON_ON_CLICK, SITE_PERMISSIONS_BUTTON_STATUS, SITE_PERMISSIONS_BUTTON_TEXT, + SITE_PERMISSIONS_BUTTON_TOOLTIP, IS_ENTERPRISE }; }
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuItemViewBinder.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuItemViewBinder.java index b39f514..bf3141cd 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuItemViewBinder.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuItemViewBinder.java
@@ -94,6 +94,10 @@ } else if (key == ExtensionsMenuItemProperties.SITE_PERMISSIONS_BUTTON_TEXT) { TextView button = view.findViewById(R.id.extensions_menu_item_site_permissions_button); button.setText(model.get(ExtensionsMenuItemProperties.SITE_PERMISSIONS_BUTTON_TEXT)); + } else if (key == ExtensionsMenuItemProperties.SITE_PERMISSIONS_BUTTON_TOOLTIP) { + View layout = view.findViewById(R.id.extensions_menu_item_site_permissions_layout); + layout.setTooltipText( + model.get(ExtensionsMenuItemProperties.SITE_PERMISSIONS_BUTTON_TOOLTIP)); } else if (key == ExtensionsMenuItemProperties.IS_ENTERPRISE) { boolean isEnterprise = model.get(ExtensionsMenuItemProperties.IS_ENTERPRISE); View icon = view.findViewById(R.id.extensions_menu_item_site_permissions_icon);
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuMediator.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuMediator.java index 43998eac..b61b61d 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuMediator.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuMediator.java
@@ -485,6 +485,9 @@ itemModel.set( ExtensionsMenuItemProperties.SITE_PERMISSIONS_BUTTON_TEXT, itemState.sitePermissionsButton.text); + itemModel.set( + ExtensionsMenuItemProperties.SITE_PERMISSIONS_BUTTON_TOOLTIP, + itemState.sitePermissionsButton.tooltipText); itemModel.set(ExtensionsMenuItemProperties.IS_ENTERPRISE, itemState.isEnterprise); }
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuMediatorTest.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuMediatorTest.java index d925ae4b..89b66e7 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuMediatorTest.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuMediatorTest.java
@@ -1071,6 +1071,9 @@ assertEquals( "Always on all sites. Select to change site permissions", model.get(ExtensionsMenuItemProperties.SITE_PERMISSIONS_BUTTON_ACCESSIBLE_NAME)); + assertEquals( + "Change site permissions", + model.get(ExtensionsMenuItemProperties.SITE_PERMISSIONS_BUTTON_TOOLTIP)); // Update the item to have an enabled site permissions button. sitePermissionsButtonState =
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/load_progress/LoadProgressMediator.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/load_progress/LoadProgressMediator.java index 2b048452..f88c8b70 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/load_progress/LoadProgressMediator.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/load_progress/LoadProgressMediator.java
@@ -89,6 +89,13 @@ return; } + if (progress < 1 + && mModel.get(LoadProgressProperties.COMPLETION_STATE) + != CompletionState.UNFINISHED) { + if (!tab.isLoading()) return; + startLoadProgress(); + } + updateLoadProgress(progress); }
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/load_progress/LoadProgressMediatorTest.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/load_progress/LoadProgressMediatorTest.java index 7048e08b..a4c0cd453 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/load_progress/LoadProgressMediatorTest.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/load_progress/LoadProgressMediatorTest.java
@@ -236,6 +236,37 @@ @Test @SmallTest + public void loadingTabProgressUpdateStartsProgressBar() { + initMediator(); + doReturn(true).when(mTab).isLoading(); + assertEquals( + CompletionState.FINISHED_DONT_ANIMATE, + mModel.get(LoadProgressProperties.COMPLETION_STATE)); + + mTabObserver.onLoadProgressChanged(mTab, 0.7f); + + assertEquals(0.7f, mModel.get(LoadProgressProperties.PROGRESS), MathUtils.EPSILON); + assertEquals( + CompletionState.UNFINISHED, mModel.get(LoadProgressProperties.COMPLETION_STATE)); + } + + @Test + @SmallTest + public void nonLoadingTabProgressUpdateDoesNotStartProgressBar() { + initMediator(); + assertEquals( + CompletionState.FINISHED_DONT_ANIMATE, + mModel.get(LoadProgressProperties.COMPLETION_STATE)); + + mTabObserver.onLoadProgressChanged(mTab, 0.7f); + + assertEquals( + CompletionState.FINISHED_DONT_ANIMATE, + mModel.get(LoadProgressProperties.COMPLETION_STATE)); + } + + @Test + @SmallTest public void testSameDocumentLoad_afterFinishedLoading() { initMediator(); GURL gurl = URL_1;
diff --git a/chrome/browser/ui/ash/input_method/candidate_window_view.cc b/chrome/browser/ui/ash/input_method/candidate_window_view.cc index 9e0e2b8..cf90e61 100644 --- a/chrome/browser/ui/ash/input_method/candidate_window_view.cc +++ b/chrome/browser/ui/ash/input_method/candidate_window_view.cc
@@ -241,8 +241,8 @@ CandidateWindowView::~CandidateWindowView() = default; std::unique_ptr<views::Widget> CandidateWindowView::InitWidget() { - views::Widget* widget = BubbleDialogDelegateView::CreateBubble( - this, views::Widget::InitParams::CLIENT_OWNS_WIDGET); + std::unique_ptr<views::Widget> widget = + BubbleDialogDelegate::CreateBubble(base::WrapUnique(this)); wm::SetWindowVisibilityAnimationTransition(widget->GetNativeView(), wm::ANIMATE_NONE); @@ -250,7 +250,7 @@ GetBubbleFrameView()->SetBubbleBorder( std::make_unique<CandidateWindowBorder>()); GetBubbleFrameView()->OnThemeChanged(); - return base::WrapUnique(widget); + return widget; } void CandidateWindowView::OnThemeChanged() {
diff --git a/chrome/browser/ui/ash/input_method/infolist_window.cc b/chrome/browser/ui/ash/input_method/infolist_window.cc index 612518f..7d8d0008 100644 --- a/chrome/browser/ui/ash/input_method/infolist_window.cc +++ b/chrome/browser/ui/ash/input_method/infolist_window.cc
@@ -229,15 +229,15 @@ InfolistWindow::~InfolistWindow() = default; std::unique_ptr<views::Widget> InfolistWindow::InitWidget() { - views::Widget* widget = views::BubbleDialogDelegateView::CreateBubble( - this, views::Widget::InitParams::CLIENT_OWNS_WIDGET); + std::unique_ptr<views::Widget> widget = + views::BubbleDialogDelegate::CreateBubble(base::WrapUnique(this)); wm::SetWindowVisibilityAnimationType( widget->GetNativeView(), wm::WINDOW_VISIBILITY_ANIMATION_TYPE_FADE); // BubbleFrameView will be initialized through CreateBubble. GetBubbleFrameView()->SetBubbleBorder(std::make_unique<InfolistBorder>()); SizeToContents(); - return base::WrapUnique(widget); + return widget; } void InfolistWindow::Relayout(const std::vector<ui::InfolistEntry>& entries) {
diff --git a/chrome/browser/ui/ash/media_client/media_client_impl.cc b/chrome/browser/ui/ash/media_client/media_client_impl.cc index edbce67..1173f58 100644 --- a/chrome/browser/ui/ash/media_client/media_client_impl.cc +++ b/chrome/browser/ui/ash/media_client/media_client_impl.cc
@@ -70,33 +70,6 @@ MediaClientImpl* g_media_client = nullptr; -// These values are persisted to logs. Entries should not be renumbered and -// numeric values should never be reused. -enum class CameraPrivacySwitchEvent { - kSwitchOn = 0, - kSwitchOff = 1, - kSwitchOnNotificationShown = 2, - kMaxValue = kSwitchOnNotificationShown -}; - -// The name for the histogram used to record camera privacy switch related -// events. -constexpr char kCameraPrivacySwitchEventsHistogramName[] = - "Ash.Media.CameraPrivacySwitch.Event"; - -// The name for the histogram used to record delay (in seconds) after a -// notification about camera privacy switch being on before the user turns -// the camera privacy switch off. -constexpr char kCameraPrivacySwitchTimeToTurnOffHistogramName[] = - "Ash.Media.CameraPrivacySwitch.TimeFromNotificationToOff"; - -// The max recorded value for `kCameraPrivacySwitchTimeToTurnOffHistogramName`. -constexpr int kMaxRecordedTimeInSeconds = 60; - -// The granularity used for -// reporting`kCameraPrivacySwitchToTurnOffHistogramName`. -constexpr int kRecordedTimeGranularityInSeconds = 5; - // The prefix of ID of the notification shown when the user tries to use a // camera while the camera privacy switch is on. constexpr char kCameraPrivacySwitchOnNotificationIdPrefix[] = @@ -586,12 +559,6 @@ return; } - base::UmaHistogramEnumeration( - kCameraPrivacySwitchEventsHistogramName, - CameraPrivacySwitchEvent::kSwitchOnNotificationShown); - - camera_switch_notification_shown_timestamp_ = base::TimeTicks::Now(); - const std::u16string device_name_u16 = base::UTF8ToUTF16(device_name); if (resurface) { @@ -650,11 +617,6 @@ case cros::mojom::CameraPrivacySwitchState::UNKNOWN: break; case cros::mojom::CameraPrivacySwitchState::ON: { - if (old_state != cros::mojom::CameraPrivacySwitchState::UNKNOWN) { - base::UmaHistogramEnumeration(kCameraPrivacySwitchEventsHistogramName, - CameraPrivacySwitchEvent::kSwitchOn); - } - if (hw_switch_toasts_disabled_) { break; } @@ -670,24 +632,6 @@ break; } case cros::mojom::CameraPrivacySwitchState::OFF: { - if (old_state != cros::mojom::CameraPrivacySwitchState::UNKNOWN) { - base::UmaHistogramEnumeration(kCameraPrivacySwitchEventsHistogramName, - CameraPrivacySwitchEvent::kSwitchOff); - } - - // Record the time since the time notification that the privacy switch was - // on was shown. - if (!camera_switch_notification_shown_timestamp_.is_null()) { - base::TimeDelta time_from_notification = - base::TimeTicks::Now() - - camera_switch_notification_shown_timestamp_; - int64_t seconds_from_notification = time_from_notification.InSeconds(); - base::UmaHistogramExactLinear( - kCameraPrivacySwitchTimeToTurnOffHistogramName, - seconds_from_notification / kRecordedTimeGranularityInSeconds, - kMaxRecordedTimeInSeconds / kRecordedTimeGranularityInSeconds); - camera_switch_notification_shown_timestamp_ = base::TimeTicks(); - } // Only show the "Camera is on" toast if the privacy switch state changed // from ON (avoiding the toast when the state changes from UNKNOWN). if (old_state != cros::mojom::CameraPrivacySwitchState::ON) {
diff --git a/chrome/browser/ui/ash/media_client/media_client_impl.h b/chrome/browser/ui/ash/media_client/media_client_impl.h index 481fba07..e80c7f8 100644 --- a/chrome/browser/ui/ash/media_client/media_client_impl.h +++ b/chrome/browser/ui/ash/media_client/media_client_impl.h
@@ -181,10 +181,6 @@ int active_camera_client_count_ = 0; - // Most recent time the notification that the camera privacy switch is on was - // shown. - base::TimeTicks camera_switch_notification_shown_timestamp_; - mojo::Remote<video_capture::mojom::VideoSourceProvider> video_source_provider_remote_;
diff --git a/chrome/browser/ui/browser_window/internal/android/android_browser_window_unittest.cc b/chrome/browser/ui/browser_window/internal/android/android_browser_window_unittest.cc index c3ecac1..f9f16085 100644 --- a/chrome/browser/ui/browser_window/internal/android/android_browser_window_unittest.cc +++ b/chrome/browser/ui/browser_window/internal/android/android_browser_window_unittest.cc
@@ -66,12 +66,6 @@ AttachCurrentThread(), java_test_support_)); } - AndroidBrowserWindow* InvokeJavaGetNativePtrForTesting() const { - return reinterpret_cast<AndroidBrowserWindow*>( - Java_AndroidBrowserWindowNativeUnitTestSupport_invokeGetNativePtrForTesting( - AttachCurrentThread(), java_test_support_)); - } - AndroidBaseWindow* InvokeJavaGetNativeBaseWindowPtrForTesting() const { return reinterpret_cast<AndroidBaseWindow*>( Java_AndroidBrowserWindowNativeUnitTestSupport_invokeGetNativeBaseWindowPtrForTesting( @@ -140,11 +134,6 @@ } TEST_F(AndroidBrowserWindowUnitTest, - JavaGetNativePtrMethodCrashesIfNoPtrWasCreated) { - EXPECT_DEATH(InvokeJavaGetNativePtr(), ""); -} - -TEST_F(AndroidBrowserWindowUnitTest, JavaDestroyMethodMarksWindowAsScheduledForDeletion) { // Arrange. InvokeJavaGetOrCreateNativePtr(); @@ -165,8 +154,7 @@ InvokeJavaResetAndDestroy(); // Assert: the native pointers on the Java side should be set to null. - AndroidBrowserWindow* android_browser_window = - InvokeJavaGetNativePtrForTesting(); + AndroidBrowserWindow* android_browser_window = InvokeJavaGetNativePtr(); AndroidBaseWindow* android_base_window = InvokeJavaGetNativeBaseWindowPtrForTesting(); EXPECT_EQ(nullptr, android_browser_window);
diff --git a/chrome/browser/ui/browser_window/internal/android/java/src/org/chromium/chrome/browser/ui/browser_window/AndroidBrowserWindow.java b/chrome/browser/ui/browser_window/internal/android/java/src/org/chromium/chrome/browser/ui/browser_window/AndroidBrowserWindow.java index b3ba26f..6471f25 100644 --- a/chrome/browser/ui/browser_window/internal/android/java/src/org/chromium/chrome/browser/ui/browser_window/AndroidBrowserWindow.java +++ b/chrome/browser/ui/browser_window/internal/android/java/src/org/chromium/chrome/browser/ui/browser_window/AndroidBrowserWindow.java
@@ -70,10 +70,10 @@ /** * Returns the address of the native {@code AndroidBrowserWindow}. * - * <p>This method assumes the native object has been created. + * <p>This method returns 0 if the native {@code AndroidBrowserWindow} + * hasn't been created. */ long getNativePtr() { - assert mNativeAndroidBrowserWindow != 0 : "Native object has not been created."; return mNativeAndroidBrowserWindow; } @@ -103,10 +103,6 @@ return mIsDeleteScheduled; } - long getNativePtrForTesting() { - return mNativeAndroidBrowserWindow; - } - long getNativeBaseWindowPtrForTesting() { return mAndroidBaseWindow.getNativePtrForTesting(); }
diff --git a/chrome/browser/ui/browser_window/internal/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskImpl.java b/chrome/browser/ui/browser_window/internal/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskImpl.java index 49f2036..6dd624b 100644 --- a/chrome/browser/ui/browser_window/internal/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskImpl.java +++ b/chrome/browser/ui/browser_window/internal/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskImpl.java
@@ -765,6 +765,25 @@ } @Override + public long getNativeBrowserWindowPtr(Profile profile, Activity activity) { + ThreadUtils.assertOnUiThread(); + assert mState == State.PENDING_CREATE + || mState == State.IDLE + || mState == State.PENDING_UPDATE + : "This Task is not pending or alive."; + for (var obj : mActivityScopedObjectsDeque) { + if (obj.mActivityScopedObjects.mActivityWindowAndroid.getActivity().get() == activity) { + var browserWindow = obj.mAndroidBrowserWindows.get(profile); + if (browserWindow != null) { + return browserWindow.getNativePtr(); + } + return 0; + } + } + return 0; + } + + @Override public void destroy() { ThreadUtils.assertOnUiThread(); if (mState != State.IDLE) { @@ -824,6 +843,7 @@ == internalActivityScopedObjects.mActivityScopedObjects.mActivityWindowAndroid; } long ptr = browserWindow.getNativePtr(); + assert ptr != 0 : "Native object has not been created."; if (internalActivityScopedObjects != null) { var profile = browserWindow.getProfile();
diff --git a/chrome/browser/ui/browser_window/internal/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskImplUnitTest.java b/chrome/browser/ui/browser_window/internal/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskImplUnitTest.java index 738b888..2af424f3 100644 --- a/chrome/browser/ui/browser_window/internal/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskImplUnitTest.java +++ b/chrome/browser/ui/browser_window/internal/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskImplUnitTest.java
@@ -34,6 +34,7 @@ import static org.chromium.chrome.browser.ui.browser_window.ChromeAndroidTaskUnitTestSupport.FAKE_NATIVE_ANDROID_BROWSER_WINDOW_PTR; import android.annotation.SuppressLint; +import android.app.Activity; import android.app.ActivityManager; import android.app.role.RoleManager; import android.content.Context; @@ -1145,6 +1146,63 @@ } @Test + public void getNativeBrowserWindowPtr_returnsPtrValueForRegisteredActivity() { + // Arrange. + var chromeAndroidTaskWithMockDeps = createChromeAndroidTaskWithMockDeps(/* taskId= */ 1); + var chromeAndroidTask = chromeAndroidTaskWithMockDeps.mChromeAndroidTask; + var profile = chromeAndroidTaskWithMockDeps.mMockProfile; + var activity = + chromeAndroidTaskWithMockDeps + .mActivityScopedObjects + .mActivityWindowAndroid + .getActivity() + .get(); + + // Act. + long nativeBrowserWindowPtr = + chromeAndroidTask.getNativeBrowserWindowPtr(profile, activity); + + // Assert. + assertEquals(FAKE_NATIVE_ANDROID_BROWSER_WINDOW_PTR, nativeBrowserWindowPtr); + } + + @Test + public void getNativeBrowserWindowPtr_returnsZeroForUnregisteredActivity() { + // Arrange. + var chromeAndroidTaskWithMockDeps = createChromeAndroidTaskWithMockDeps(/* taskId= */ 1); + var chromeAndroidTask = chromeAndroidTaskWithMockDeps.mChromeAndroidTask; + var profile = chromeAndroidTaskWithMockDeps.mMockProfile; + var unregisteredActivity = mock(Activity.class); + + // Act. + long nativeBrowserWindowPtr = + chromeAndroidTask.getNativeBrowserWindowPtr(profile, unregisteredActivity); + + // Assert. + assertEquals(0, nativeBrowserWindowPtr); + } + + @Test + public void getNativeBrowserWindowPtr_calledAfterTaskDestroyed_throwsException() { + // Arrange. + var chromeAndroidTaskWithMockDeps = createChromeAndroidTaskWithMockDeps(/* taskId= */ 1); + var chromeAndroidTask = chromeAndroidTaskWithMockDeps.mChromeAndroidTask; + var profile = chromeAndroidTaskWithMockDeps.mMockProfile; + var activity = + chromeAndroidTaskWithMockDeps + .mActivityScopedObjects + .mActivityWindowAndroid + .getActivity() + .get(); + chromeAndroidTask.destroy(); + + // Act & Assert. + assertThrows( + AssertionError.class, + () -> chromeAndroidTask.getNativeBrowserWindowPtr(profile, activity)); + } + + @Test public void destroy_unregisterListenersForTopActivity() { // Arrange: Add the 1st instance of ActivityScopedObjects. int taskId = 1;
diff --git a/chrome/browser/ui/browser_window/public/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTask.java b/chrome/browser/ui/browser_window/public/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTask.java index 351af78..d025fb82e 100644 --- a/chrome/browser/ui/browser_window/public/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTask.java +++ b/chrome/browser/ui/browser_window/public/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTask.java
@@ -4,6 +4,7 @@ package org.chromium.chrome.browser.ui.browser_window; +import android.app.Activity; import android.content.Intent; import android.graphics.Rect; @@ -222,6 +223,17 @@ long getOrCreateNativeBrowserWindowPtr(Profile profile); /** + * Returns the address of the native {@code BrowserWindowInterface} if it exists this should be + * uniquely identifiable via the {@link Profile} and {@link Activity}. + * + * <p>If the native object hasn't been created, this method will return 0. + * + * @param profile The profile associated with the browser window. + * @param activity The activity associated with the browser window. + */ + long getNativeBrowserWindowPtr(Profile profile, Activity activity); + + /** * Returns an array of the all native {@code BrowserWindowInterface} addresses. * * <p>If the native object hasn't been created, this method will create it before returning its
diff --git a/chrome/browser/ui/browser_window/test/android/java/src/org/chromium/chrome/browser/ui/browser_window/AndroidBrowserWindowNativeUnitTestSupport.java b/chrome/browser/ui/browser_window/test/android/java/src/org/chromium/chrome/browser/ui/browser_window/AndroidBrowserWindowNativeUnitTestSupport.java index c7bb9ec..cd40445 100644 --- a/chrome/browser/ui/browser_window/test/android/java/src/org/chromium/chrome/browser/ui/browser_window/AndroidBrowserWindowNativeUnitTestSupport.java +++ b/chrome/browser/ui/browser_window/test/android/java/src/org/chromium/chrome/browser/ui/browser_window/AndroidBrowserWindowNativeUnitTestSupport.java
@@ -63,11 +63,6 @@ } @CalledByNative - private long invokeGetNativePtrForTesting() { - return mAndroidBrowserWindow.getNativePtrForTesting(); - } - - @CalledByNative private long invokeGetNativeBaseWindowPtrForTesting() { return mAndroidBrowserWindow.getNativeBaseWindowPtrForTesting(); }
diff --git a/chrome/browser/ui/color/chrome_color_id.h b/chrome/browser/ui/color/chrome_color_id.h index 4ed3c623..2e734b42 100644 --- a/chrome/browser/ui/color/chrome_color_id.h +++ b/chrome/browser/ui/color/chrome_color_id.h
@@ -93,6 +93,7 @@ E_CPONLY(kColorBnplIssuerLinkedIneligibleBackground) \ E_CPONLY(kColorBnplIssuerLinkedPillBackground) \ E_CPONLY(kColorBnplIssuerLinkedPillForeground) \ + E_CPONLY(kColorAutofillPopupDeactivatedBnplForeground) \ /* Compose colors */ \ E_CPONLY(kColorComposeDialogBackground) \ E_CPONLY(kColorComposeDialogDivider) \
diff --git a/chrome/browser/ui/color/material_chrome_color_mixer.cc b/chrome/browser/ui/color/material_chrome_color_mixer.cc index 88537661..ddc459ed 100644 --- a/chrome/browser/ui/color/material_chrome_color_mixer.cc +++ b/chrome/browser/ui/color/material_chrome_color_mixer.cc
@@ -147,6 +147,8 @@ mixer[kColorBnplIssuerLinkedIneligibleBackground] = {ui::kColorSysSurface2}; mixer[kColorBnplIssuerLinkedPillBackground] = {ui::kColorBadgeBackground}; mixer[kColorBnplIssuerLinkedPillForeground] = {ui::kColorBadgeForeground}; + mixer[kColorAutofillPopupDeactivatedBnplForeground] = ui::SetAlpha( + ui::kColorLabelForegroundSecondary, gfx::kDisabledControlAlpha); // Tab Search colors. mixer[kColorTabSearchButtonBackground] = {ui::kColorSysSurface2};
diff --git a/chrome/browser/ui/lens/lens_query_flow_router.cc b/chrome/browser/ui/lens/lens_query_flow_router.cc index e10ddc1..cd201a6 100644 --- a/chrome/browser/ui/lens/lens_query_flow_router.cc +++ b/chrome/browser/ui/lens/lens_query_flow_router.cc
@@ -57,6 +57,18 @@ } return contextual_inputs; } + +omnibox::ChromeAimEntryPoint AimEntryPointFromInvocationSource( + lens::LensOverlayInvocationSource invocation_source) { + // TODO(crbug.com/483805922): Create individual AIM entry points for each + // Lens invocation source. + if (invocation_source == + lens::LensOverlayInvocationSource::kOmniboxContextualSuggestion) { + return omnibox::DESKTOP_CHROME_OTHER_OMNIBOX_COMPOSEBOX_ENTRY_POINT; + } + return omnibox::DESKTOP_CHROME_LENS_CONTEXTUAL_SEARCHBOX_ENTRY_POINT; +} + } // namespace namespace lens { @@ -812,10 +824,8 @@ request_info->additional_params = additional_search_query_params; request_info->invocation_source = invocation_source; - // TODO(crbug.com/483805922): Create individual AIM entry points for each - // Lens invocation source. request_info->aim_entry_point = - omnibox::DESKTOP_CHROME_LENS_CONTEXTUAL_SEARCHBOX_ENTRY_POINT; + AimEntryPointFromInvocationSource(invocation_source); if (region) { auto client_logs =
diff --git a/chrome/browser/ui/lens/lens_query_flow_router_unittest.cc b/chrome/browser/ui/lens/lens_query_flow_router_unittest.cc index 64f6998..f6b0073 100644 --- a/chrome/browser/ui/lens/lens_query_flow_router_unittest.cc +++ b/chrome/browser/ui/lens/lens_query_flow_router_unittest.cc
@@ -1817,6 +1817,95 @@ lens::LensOverlayInvocationSource::kAppMenu); } +TEST_F( + LensQueryFlowRouterContextualTaskEnabledTest, + SendContextualTextQuery_OmniboxContextualSuggestion_RoutesToContextualTasks) { + // Arrange: Set up and create the router. + TestLensQueryFlowRouter router(mock_lens_search_controller_.get(), + mock_context_controller_.get(), + profile_.get()); + router.SetTabContextualizationController( + mock_tab_contextualization_controller_.get()); + + // Arrange: Set up the parameters. + base::Time query_start_time = base::Time::Now(); + std::string query_text = "test query"; + lens::LensOverlaySelectionType selection_type = + lens::LensOverlaySelectionType::MULTIMODAL_SUGGEST_TYPEAHEAD; + std::map<std::string, std::string> additional_params; + additional_params["lns_fp"] = "1"; + additional_params["lns_mode"] = "text"; + additional_params["plla"] = "0"; + base::UnguessableToken file_token = base::UnguessableToken::Create(); + + // Arrange: Create expected request info. + auto expected_request_info = std::make_unique<CreateSearchUrlRequestInfo>(); + expected_request_info->search_url_type = + contextual_search::ContextualSearchContextController::SearchUrlType::kAim; + expected_request_info->query_text = query_text; + expected_request_info->query_start_time = query_start_time; + expected_request_info->lens_overlay_selection_type = selection_type; + lens::AppendLensOverlaySidePanelParams(additional_params, router.gen204_id(), + /*has_text=*/true, + /*has_image=*/false); + expected_request_info->additional_params = additional_params; + expected_request_info->image_crop = std::nullopt; + expected_request_info->aim_entry_point = + omnibox::DESKTOP_CHROME_OTHER_OMNIBOX_COMPOSEBOX_ENTRY_POINT; + expected_request_info->file_tokens.push_back(file_token); + + // Assert: Expect NotifyResultsPanelOpened to be called. + EXPECT_CALL(*mock_lens_overlay_controller_, NotifyResultsPanelOpened()) + .Times(1); + + // Mock GetFileInfo to return valid status so IsActiveTabContextEligible + // returns true. + SetFileInfoWithEligibility(file_token, /*is_eligible=*/true); + + // Assert: Create expectation to call CreateSearchUrl. + EXPECT_CALL(*router.mock_session_handle(), NotifySessionStarted()); + EXPECT_CALL(*router.mock_session_handle(), CreateContextToken()) + .WillOnce(Return(file_token)); + // StartTabContextUploadFlow is called as part of UploadContextualInputData. + EXPECT_CALL(*router.mock_session_handle(), + StartTabContextUploadFlow(_, _, _)); + + GURL example_url("https://example.com"); + router.StartQueryFlow(router.GetViewportScreenshot(), example_url, "Title", + {}, {}, lens::MimeType::kAnnotatedPageContent, + std::nullopt, 1.0f, base::TimeTicks::Now()); + expected_request_info->additional_params["plla"] = + base::NumberToString(router.gen204_id()); + EXPECT_CALL( + *router.mock_session_handle(), + CreateSearchUrl( + CreateSearchUrlRequestInfoMatches(expected_request_info.get()), _)) + .WillOnce(base::test::RunOnceCallback<1>( + GURL("https://www.google.com/search?q=test"))); + auto* service = static_cast<MockContextualTasksUiService*>( + contextual_tasks::ContextualTasksUiServiceFactory::GetForBrowserContext( + profile_.get())); + // Expect StartTaskUiInSidePanel to be called with the real URL and the + // session handle. + EXPECT_CALL(*service, + StartTaskUiInSidePanel( + mock_browser_window_interface_.get(), &mock_tab_interface_, + GURL("https://www.google.com/search?q=test"), + testing::Pointer(router.mock_session_handle()))) + .WillOnce( + [&router]( + BrowserWindowInterface*, tabs::TabInterface*, const GURL&, + std::unique_ptr<contextual_search::ContextualSearchSessionHandle> + handle) { + router.SetTransferredSessionHandle(std::move(handle)); + }); + + // Act: Call the method. + router.SendContextualTextQuery( + query_start_time, query_text, selection_type, additional_params, + lens::LensOverlayInvocationSource::kOmniboxContextualSuggestion); +} + TEST_F(LensQueryFlowRouterContextualTaskEnabledTest, SendMultimodalRequest_RoutesToContextualTasks) { // Arrange: Set up and create the router.
diff --git a/chrome/browser/ui/lens/lens_searchbox_controller.cc b/chrome/browser/ui/lens/lens_searchbox_controller.cc index d41544b..ff36955 100644 --- a/chrome/browser/ui/lens/lens_searchbox_controller.cc +++ b/chrome/browser/ui/lens/lens_searchbox_controller.cc
@@ -74,8 +74,7 @@ } void LensSearchboxController::SetSearchboxInputText(const std::string& text) { - if (side_panel_searchbox_handler_ && - side_panel_searchbox_handler_->IsRemoteBound()) { + if (side_panel_searchbox_handler_) { init_data_->text_query = text; side_panel_searchbox_handler_->SetInputText(text); } else { @@ -96,15 +95,13 @@ // Store the thumbnail. init_data_->thumbnail_uri = thumbnail_uri; - if (side_panel_searchbox_handler_ && - side_panel_searchbox_handler_->IsRemoteBound()) { + if (side_panel_searchbox_handler_) { side_panel_searchbox_handler_->SetThumbnail( init_data_->show_side_panel_thumbnail ? thumbnail_uri : "", /*is_deletable=*/!IsContextualSearchbox()); } - if (overlay_searchbox_handler_ && - overlay_searchbox_handler_->IsRemoteBound()) { + if (overlay_searchbox_handler_) { overlay_searchbox_handler_->SetThumbnail( thumbnail_uri, /*is_deletable=*/!IsContextualSearchbox()); } @@ -117,8 +114,7 @@ init_data_->show_side_panel_thumbnail = shown; - if (side_panel_searchbox_handler_ && - side_panel_searchbox_handler_->IsRemoteBound()) { + if (side_panel_searchbox_handler_) { side_panel_searchbox_handler_->SetThumbnail( shown ? init_data_->thumbnail_uri : "", /*is_deletable=*/!IsContextualSearchbox()); @@ -258,8 +254,7 @@ void LensSearchboxController::OnPageBound() { // Send any pending inputs for the searchbox. - if (pending_text_query_.has_value() && side_panel_searchbox_handler_ && - side_panel_searchbox_handler_->IsRemoteBound()) { + if (pending_text_query_.has_value() && side_panel_searchbox_handler_) { side_panel_searchbox_handler_->SetInputText(*pending_text_query_); pending_text_query_.reset(); }
diff --git a/chrome/browser/ui/lens/lens_searchbox_controller.h b/chrome/browser/ui/lens/lens_searchbox_controller.h index 0771a8b..b7d06b3 100644 --- a/chrome/browser/ui/lens/lens_searchbox_controller.h +++ b/chrome/browser/ui/lens/lens_searchbox_controller.h
@@ -168,21 +168,14 @@ // Searchbox handler for passing in image and text selections. The handler is // null if the WebUI containing the searchbox has not been initialized yet, - // like in the case of side panel opening. In addition, the handler may be - // initialized, but the remote not yet set because the WebUI calls SetPage() - // once it is ready to receive data from C++. Therefore, we must always check - // that: - // 1) searchbox_handler_ exists and - // 2) searchbox_handler_->IsRemoteBound() is true. + // like in the case of side panel opening. Therefore, we must always check + // that side_panel_searchbox_handler_ exists. std::unique_ptr<LensSearchboxHandler> side_panel_searchbox_handler_; // Handler for the contextual searchbox in the overlay. The handler is // null if the WebUI containing the searchbox has not been initialized yet. - // In addition, the handler may be initialized, but the remote not yet set - // because the WebUI calls SetPage() once it is ready to receive data from - // C++. Therefore, we must always check that: - // 1) contextual_searchbox_handler_ exists and - // 2) contextual_searchbox_handler_->IsRemoteBound() is true. + // Therefore, we must always check that overlay_searchbox_handler_ + // exists. // TODO(crbug.com/404941800): Does this actually need to be kept alive? Its // currently unused. std::unique_ptr<LensSearchboxHandler> overlay_searchbox_handler_;
diff --git a/chrome/browser/ui/side_panel_container/internal/BUILD.gn b/chrome/browser/ui/side_panel_container/internal/BUILD.gn index 0be0baf..98df37c 100644 --- a/chrome/browser/ui/side_panel_container/internal/BUILD.gn +++ b/chrome/browser/ui/side_panel_container/internal/BUILD.gn
@@ -23,7 +23,6 @@ deps = [ ":java_resources", "//base:callback_java", - "//base:log_java", "//base:supplier_java", "//base:tasks_java", "//base/version_info/android:version_constants_java", @@ -101,8 +100,8 @@ "//chrome/test/android:chrome_java_unit_test_support", "//third_party/androidx:androidx_annotation_annotation_java", "//third_party/androidx:androidx_test_runner_java", + "//third_party/androidx:androidx_window_window_java", "//third_party/junit", - "//third_party/mockito:mockito_java", "//ui/android:ui_no_recycler_view_java", ] resources_package = "org.chromium.chrome.browser.ui.side_panel_container"
diff --git a/chrome/browser/ui/side_panel_container/internal/android/java/src/org/chromium/chrome/browser/ui/side_panel_container/SidePanelContainerCoordinatorImpl.java b/chrome/browser/ui/side_panel_container/internal/android/java/src/org/chromium/chrome/browser/ui/side_panel_container/SidePanelContainerCoordinatorImpl.java index 070b31d..1ca96e37 100644 --- a/chrome/browser/ui/side_panel_container/internal/android/java/src/org/chromium/chrome/browser/ui/side_panel_container/SidePanelContainerCoordinatorImpl.java +++ b/chrome/browser/ui/side_panel_container/internal/android/java/src/org/chromium/chrome/browser/ui/side_panel_container/SidePanelContainerCoordinatorImpl.java
@@ -34,7 +34,14 @@ implements SidePanelContainerCoordinator, SideUiContainer { private static final String TAG = "SidePanelContainerCoordinatorImpl"; - @VisibleForTesting static final int SIDE_PANEL_MIN_WIDTH_DP = 360; + /** + * Threshold of available width in the window, in dp. Once crossed, it will lead to a change in + * side panel width. + */ + private static final int AVAILABLE_WINDOW_WIDTH_THRESHOLD_DP = 1200; + + private static final int SIDE_PANEL_MAX_WIDTH_DP = 412; + private static final int SIDE_PANEL_MIN_WIDTH_DP = 360; private static final @AnchorSide int SIDE_PANEL_DEFAULT_ANCHOR_SIDE = AnchorSide.END; @@ -91,10 +98,11 @@ mContainerView.removeAllViews(); mContainerView.addView(content.mView); - // TODO(http://crbug.com/487414343): Refine the side panel width. - @Px int sidePanelWidth = ViewUtils.dpToPx(mParentActivity, SIDE_PANEL_MIN_WIDTH_DP); + // It's fine to always _request_ the max width. The final width will be determined in + // determineContainerWidth(). + @Px int sidePanelMaxWidth = ViewUtils.dpToPx(mParentActivity, SIDE_PANEL_MAX_WIDTH_DP); mSideUiCoordinator.requestUpdateContainer( - new SideUiContainerProperties(SIDE_PANEL_DEFAULT_ANCHOR_SIDE, sidePanelWidth), + new SideUiContainerProperties(SIDE_PANEL_DEFAULT_ANCHOR_SIDE, sidePanelMaxWidth), suppressAnimations); // TODO(crbug.com/496407828): Move this around so it actually runs after the animation is // finished. @@ -142,13 +150,18 @@ @Override @Px - public int determineContainerWidth(@Px int availableWidth, @Px int windowWidth) { - log(TAG, "determineContainerWidth", availableWidth, windowWidth); + public int determineContainerWidth( + @Px int requestedWidth, @Px int availableWidth, @Px int windowWidth) { + log(TAG, "determineContainerWidth", requestedWidth, availableWidth, windowWidth); ThreadUtils.assertOnUiThread(); - // TODO(http://crbug.com/487414343): Refine the implementation. - // Calculate the final container width based on "availableWidth" and "windowWidth". - return ViewUtils.dpToPx(mParentActivity, SIDE_PANEL_MIN_WIDTH_DP); + if (requestedWidth == 0) { + return 0; + } + + int availableWidthDp = ViewUtils.pxToDp(mParentActivity, availableWidth); + int containerWidthDp = determineContainerWidthDp(availableWidthDp); + return ViewUtils.dpToPx(mParentActivity, containerWidthDp); } @Override @@ -183,4 +196,26 @@ // TODO(http://crbug.com/488047364): Notify the SidePanelContent View of the width change. } + + /** + * Returns the final width (in dp) of the side panel given the available width in the window. + */ + @VisibleForTesting + static int determineContainerWidthDp(int availableWidthDp) { + if (availableWidthDp >= AVAILABLE_WINDOW_WIDTH_THRESHOLD_DP) { + return SIDE_PANEL_MAX_WIDTH_DP; + } + + if (availableWidthDp > SIDE_PANEL_MIN_WIDTH_DP) { + return SIDE_PANEL_MIN_WIDTH_DP; + } + + // As of May 1, 2026, there were side panel browser tests running on _phone_ bots, where + // there may not be enough space for SIDE_PANEL_MIN_WIDTH_DP. So we just give side panel + // half the available width to make the tests happy. + // TODO(crbug.com/510044610): Stop running side panel browser tests on _phone_ bots, then + // delete this logic. + log(TAG, "available width is less than min side panel width"); + return availableWidthDp / 2; + } }
diff --git a/chrome/browser/ui/side_panel_container/internal/android/java/src/org/chromium/chrome/browser/ui/side_panel_container/SidePanelContainerCoordinatorIntegrationTest.java b/chrome/browser/ui/side_panel_container/internal/android/java/src/org/chromium/chrome/browser/ui/side_panel_container/SidePanelContainerCoordinatorIntegrationTest.java index 6f01ddc..56f9138 100644 --- a/chrome/browser/ui/side_panel_container/internal/android/java/src/org/chromium/chrome/browser/ui/side_panel_container/SidePanelContainerCoordinatorIntegrationTest.java +++ b/chrome/browser/ui/side_panel_container/internal/android/java/src/org/chromium/chrome/browser/ui/side_panel_container/SidePanelContainerCoordinatorIntegrationTest.java
@@ -18,8 +18,8 @@ import android.widget.TextView; import androidx.annotation.ColorInt; -import androidx.annotation.Px; import androidx.test.filters.MediumTest; +import androidx.window.layout.WindowMetricsCalculator; import org.junit.Before; import org.junit.Rule; @@ -160,12 +160,17 @@ FrameLayout containerView = waitForContainerViewWithValidWidth(coordinator); // Assert. - @Px - int expectedWidth = - ViewUtils.dpToPx( - mFreshCtaTransitTestRule.getActivity(), - SidePanelContainerCoordinatorImpl.SIDE_PANEL_MIN_WIDTH_DP); - assertEquals(expectedWidth, containerView.getWidth()); + var activity = mFreshCtaTransitTestRule.getActivity(); + int windowWidthPx = + WindowMetricsCalculator.getOrCreate() + .computeCurrentWindowMetrics(activity) + .getBounds() + .width(); + int windowWidthDp = ViewUtils.pxToDp(activity, windowWidthPx); + int expectedWidthDp = + SidePanelContainerCoordinatorImpl.determineContainerWidthDp(windowWidthDp); + int expectedWidthPx = ViewUtils.dpToPx(activity, expectedWidthDp); + assertEquals(expectedWidthPx, containerView.getWidth()); } @Test
diff --git a/chrome/browser/ui/side_ui/internal/BUILD.gn b/chrome/browser/ui/side_ui/internal/BUILD.gn index eb0551c2c..75846da6 100644 --- a/chrome/browser/ui/side_ui/internal/BUILD.gn +++ b/chrome/browser/ui/side_ui/internal/BUILD.gn
@@ -26,6 +26,7 @@ "//chrome/browser/ui/side_ui/public:java", "//components/cached_flags:java", "//third_party/androidx:androidx_annotation_annotation_java", + "//third_party/androidx:androidx_window_window_java", "//ui/android:ui_no_recycler_view_java", ] }
diff --git a/chrome/browser/ui/side_ui/internal/android/java/src/org/chromium/chrome/browser/ui/side_ui/SideUiCoordinatorFactory.java b/chrome/browser/ui/side_ui/internal/android/java/src/org/chromium/chrome/browser/ui/side_ui/SideUiCoordinatorFactory.java index 08e3b8a..d1d35ce 100644 --- a/chrome/browser/ui/side_ui/internal/android/java/src/org/chromium/chrome/browser/ui/side_ui/SideUiCoordinatorFactory.java +++ b/chrome/browser/ui/side_ui/internal/android/java/src/org/chromium/chrome/browser/ui/side_ui/SideUiCoordinatorFactory.java
@@ -4,6 +4,7 @@ package org.chromium.chrome.browser.ui.side_ui; +import android.app.Activity; import android.view.ViewGroup; import android.view.ViewStub; @@ -21,6 +22,7 @@ /** * Creates a {@link SideUiCoordinator}. * + * @param parentActivity The {@link Activity} containing all Side UIs. * @param anchorContainerParent The {@link ViewGroup} that is the parent for the side UI * containers. * @param startAnchorContainerStub The {@link ViewStub} for the start-anchored container. @@ -30,6 +32,7 @@ */ @Nullable public static SideUiCoordinator create( + Activity parentActivity, @Nullable ViewGroup anchorContainerParent, @Nullable ViewStub startAnchorContainerStub, @Nullable ViewStub endAnchorContainerStub, @@ -45,8 +48,8 @@ if (topMarginSupplier == null) { topMarginSupplier = ObservableSuppliers.createNonNull(0); } - return new SideUiCoordinatorImpl( + parentActivity, anchorContainerParent, startAnchorContainerStub, endAnchorContainerStub,
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 30f655a..dc4a761 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
@@ -9,6 +9,7 @@ import static org.chromium.chrome.browser.ui.side_ui.SideUiCoordinator.SideUiSpecs.EMPTY_SIDE_UI_SPECS; +import android.app.Activity; import android.transition.Transition; import android.transition.TransitionListenerAdapter; import android.transition.TransitionManager; @@ -21,6 +22,7 @@ import android.view.ViewStub; import androidx.annotation.Px; +import androidx.window.layout.WindowMetricsCalculator; import org.chromium.base.Callback; import org.chromium.base.ObserverList; @@ -36,6 +38,8 @@ final class SideUiCoordinatorImpl implements SideUiCoordinator { private static final long TRANSITION_DURATION_MS = 350L; + private final Activity mParentActivity; + private final ViewGroup mAnchorContainerParent; private final ViewGroup mStartAnchorContainer; private final ViewGroup mEndAnchorContainer; @@ -55,6 +59,7 @@ /** * Constructor for a {@link SideUiCoordinatorImpl}. * + * @param parentActivity The {@link Activity} containing all Side UIs. * @param anchorContainerParent The {@link ViewGroup} that is the parent for the side UI * containers. * @param startAnchorContainerStub The {@link ViewStub} for the start-anchored container. @@ -62,11 +67,14 @@ * @param topMarginSupplier The supplier for the Side UI's top margin. */ /* package */ SideUiCoordinatorImpl( + Activity parentActivity, ViewGroup anchorContainerParent, ViewStub startAnchorContainerStub, ViewStub endAnchorContainerStub, NonNullObservableSupplier<Integer> topMarginSupplier) { + mParentActivity = parentActivity; mAnchorContainerParent = anchorContainerParent; + // TODO(crbug.com/485309827): Account for the height of Side UI. Specifically, show beneath // the tab strip when it is visible. mStartAnchorContainer = (ViewGroup) startAnchorContainerStub.inflate(); @@ -107,11 +115,14 @@ || ChromeFeatureList.sEnableAndroidSidePanelDisableAnimations.getValue(); // 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; + // Currently we only have one side UI container, so "availableWidth" is the same as + // "windowWidth". + // TODO(crbug.com/478338737): Update to account for multiple side containers. + @Px int windowWidth = getWindowWidth(); + @Px + int acceptedWidth = + mSideUiContainer.determineContainerWidth( + properties.mWidth, /* availableWidth= */ windowWidth, windowWidth); SideUiSpecs newSideUiSpecs = new SideUiSpecs( properties.mAnchorSide == AnchorSide.START ? acceptedWidth : 0, @@ -403,6 +414,13 @@ mEndAnchorContainer.setLayoutParams(endLayoutParams); } + private @Px int getWindowWidth() { + return WindowMetricsCalculator.getOrCreate() + .computeCurrentWindowMetrics(mParentActivity) + .getBounds() + .width(); + } + // Test Support @Nullable SideUiContainer getSideUiContainerForTesting() {
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 d3b28732..0eb1e463 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
@@ -12,11 +12,11 @@ import static org.mockito.Mockito.verify; import android.app.Activity; -import android.content.Context; import android.util.Size; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.ViewGroup.LayoutParams; import android.view.ViewGroup.MarginLayoutParams; import android.view.ViewStub; import android.widget.FrameLayout; @@ -36,16 +36,17 @@ import org.chromium.base.supplier.ObservableSuppliers; import org.chromium.base.supplier.SettableNonNullObservableSupplier; import org.chromium.base.test.BaseRobolectricTestRunner; +import org.chromium.base.test.RobolectricUtil; import org.chromium.chrome.browser.ui.side_ui.SideUiCoordinator.AnchorSide; import org.chromium.chrome.browser.ui.side_ui.SideUiCoordinator.SideUiContainerProperties; import org.chromium.chrome.browser.ui.side_ui.SideUiCoordinator.SideUiSpecs; /** Unit tests for {@link SideUiCoordinatorImpl}. */ @RunWith(BaseRobolectricTestRunner.class) -@Config(manifest = Config.NONE) +@Config(qualifiers = "w1920dp-h1080dp-mdpi") public class SideUiCoordinatorImplTest { - - private static final Size SIDE_UI_PARENT_SIZE = new Size(1000, 1000); + /** Window size in this test; it must match {@code @Config}. */ + private static final Size WINDOW_SIZE_PX = new Size(1920, 1080); @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule(); @@ -56,7 +57,7 @@ private final SettableNonNullObservableSupplier<Integer> mTopMarginSupplier = ObservableSuppliers.createNonNull(0); - private FrameLayout mSideUiParent; + private FrameLayout mAnchorContainerParent; private ViewGroup mStartAnchorContainer; private ViewGroup mEndAnchorContainer; private View mSideUiContainerView; @@ -65,31 +66,27 @@ @Before public void setUp() { - Context context = Robolectric.buildActivity(Activity.class).setup().get(); + Activity activity = Robolectric.buildActivity(Activity.class).setup().get(); - // Set up side UI's parent View. - // Note that we simulate a measure pass and a layout pass, like what Android framework does. - mSideUiParent = new FrameLayout(context); - mSideUiParent.measure( - View.MeasureSpec.makeMeasureSpec( - SIDE_UI_PARENT_SIZE.getWidth(), View.MeasureSpec.EXACTLY), - View.MeasureSpec.makeMeasureSpec( - SIDE_UI_PARENT_SIZE.getHeight(), View.MeasureSpec.EXACTLY)); - mSideUiParent.layout(0, 0, SIDE_UI_PARENT_SIZE.getWidth(), SIDE_UI_PARENT_SIZE.getHeight()); + // Set up the parent View of side UI anchor containers. + mAnchorContainerParent = new FrameLayout(activity); + activity.addContentView( + mAnchorContainerParent, + new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); // Set up anchor containers. mStartAnchorContainer = (ViewGroup) - LayoutInflater.from(context) + LayoutInflater.from(activity) .inflate(R.layout.side_ui_anchor_container, /* root= */ null); mEndAnchorContainer = (ViewGroup) - LayoutInflater.from(context) + LayoutInflater.from(activity) .inflate(R.layout.side_ui_anchor_container, /* root= */ null); - mSideUiParent.addView(mStartAnchorContainer); - mSideUiParent.addView(mEndAnchorContainer); + mAnchorContainerParent.addView(mStartAnchorContainer); + mAnchorContainerParent.addView(mEndAnchorContainer); - mSideUiContainerView = new View(context); + mSideUiContainerView = new View(activity); mSideUiContainer = new TestSideUiContainer(mSideUiContainerView); doReturn(mStartAnchorContainer).when(mStartAnchorContainerStub).inflate(); @@ -98,10 +95,18 @@ // Initialize the SideUiCoordinator under test. mCoordinator = new SideUiCoordinatorImpl( - mSideUiParent, + activity, + mAnchorContainerParent, mStartAnchorContainerStub, mEndAnchorContainerStub, mTopMarginSupplier); + + // Make sure the measure pass and the layout pass are completed before running tests. + RobolectricUtil.runAllBackgroundAndUi(); + + // mAnchorContainerParent should have the size specified in @Config. + assertEquals(WINDOW_SIZE_PX.getWidth(), mAnchorContainerParent.getWidth()); + assertEquals(WINDOW_SIZE_PX.getHeight(), mAnchorContainerParent.getHeight()); } @Test @@ -144,7 +149,7 @@ } @Test - public void testRequestUpdateContainer_Start() { + public void testRequestUpdateContainer_AnchorSideIsStart() { mCoordinator.registerSideUiContainer(mSideUiContainer); mCoordinator.addObserver(mSideUiObserver); clearInvocations(mSideUiObserver); @@ -164,7 +169,7 @@ } @Test - public void testRequestUpdateContainer_End() { + public void testRequestUpdateContainer_AnchorSideIsEnd() { mCoordinator.registerSideUiContainer(mSideUiContainer); mCoordinator.addObserver(mSideUiObserver); clearInvocations(mSideUiObserver); @@ -202,6 +207,22 @@ } @Test + public void testRequestUpdateContainer_InvokeDetermineContainerWidth() { + mCoordinator.registerSideUiContainer(mSideUiContainer); + + int width = 200; + mCoordinator.requestUpdateContainer( + new SideUiContainerProperties(AnchorSide.END, width), + /* suppressAnimations= */ true); + + // Verify SideUiContainer#determineContainerWidth() is invoked with correct parameters. + assertEquals(Integer.valueOf(width), mSideUiContainer.mLastRequestedWidth); + assertEquals( + Integer.valueOf(WINDOW_SIZE_PX.getWidth()), mSideUiContainer.mLastAvailableWidth); + assertEquals(Integer.valueOf(WINDOW_SIZE_PX.getWidth()), mSideUiContainer.mLastWindowWidth); + } + + @Test public void testSwitchAnchorSides() { mCoordinator.registerSideUiContainer(mSideUiContainer); @@ -279,21 +300,21 @@ assertEquals( "Unexpected measured height.", - SIDE_UI_PARENT_SIZE.getHeight() - sideUiTopMargin, + mAnchorContainerParent.getHeight() - sideUiTopMargin, mStartAnchorContainer.getMeasuredHeight()); assertEquals( "Unexpected measured height.", - SIDE_UI_PARENT_SIZE.getHeight() - sideUiTopMargin, + mAnchorContainerParent.getHeight() - sideUiTopMargin, mEndAnchorContainer.getMeasuredHeight()); } @Test public void testGetCurrentSideUiSpecs_AfterParentResize() { // Simulate the measure pass for when side UI's parent is resized. - int newParentHeight = mSideUiParent.getHeight() - 100; - mSideUiParent.measure( + int newParentHeight = mAnchorContainerParent.getHeight() - 100; + mAnchorContainerParent.measure( View.MeasureSpec.makeMeasureSpec( - mSideUiParent.getWidth(), View.MeasureSpec.EXACTLY), + mAnchorContainerParent.getWidth(), View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(newParentHeight, View.MeasureSpec.EXACTLY)); // Call getCurrentSideUiSpecs() before the layout pass. @@ -304,7 +325,7 @@ assertEquals(newParentHeight, mEndAnchorContainer.getMeasuredHeight()); // Now simulate the layout pass. - mSideUiParent.layout(0, 0, SIDE_UI_PARENT_SIZE.getWidth(), newParentHeight); + mAnchorContainerParent.layout(0, 0, mAnchorContainerParent.getWidth(), newParentHeight); // Call getCurrentSideUiSpecs() again. mCoordinator.getCurrentSideUiSpecs();
diff --git a/chrome/browser/ui/side_ui/public/BUILD.gn b/chrome/browser/ui/side_ui/public/BUILD.gn index 1ebdbd3..1cdf4c2f 100644 --- a/chrome/browser/ui/side_ui/public/BUILD.gn +++ b/chrome/browser/ui/side_ui/public/BUILD.gn
@@ -13,11 +13,11 @@ # Public Java interfaces android_library("java") { sources = [ - "android/java/src/org/chromium/chrome/browser/ui/side_ui/MarginContainerSideUiObserver.java", "android/java/src/org/chromium/chrome/browser/ui/side_ui/SideUiContainer.java", "android/java/src/org/chromium/chrome/browser/ui/side_ui/SideUiCoordinator.java", "android/java/src/org/chromium/chrome/browser/ui/side_ui/SideUiObserver.java", "android/java/src/org/chromium/chrome/browser/ui/side_ui/SideUiStateProvider.java", + "android/java/src/org/chromium/chrome/browser/ui/side_ui/ViewMarginAdjusterForSideUi.java", ] deps = [ "//build/android:build_java", @@ -35,7 +35,7 @@ } robolectric_library("junit") { - sources = [ "android/java/src/org/chromium/chrome/browser/ui/side_ui/MarginContainerSideUiObserverTest.java" ] + sources = [ "android/java/src/org/chromium/chrome/browser/ui/side_ui/ViewMarginAdjusterForSideUiTest.java" ] deps = [ ":java", "//base:base_junit_test_support",
diff --git a/chrome/browser/ui/side_ui/public/android/java/src/org/chromium/chrome/browser/ui/side_ui/SideUiContainer.java b/chrome/browser/ui/side_ui/public/android/java/src/org/chromium/chrome/browser/ui/side_ui/SideUiContainer.java index 455cb616..d1b4aad 100644 --- a/chrome/browser/ui/side_ui/public/android/java/src/org/chromium/chrome/browser/ui/side_ui/SideUiContainer.java +++ b/chrome/browser/ui/side_ui/public/android/java/src/org/chromium/chrome/browser/ui/side_ui/SideUiContainer.java
@@ -34,18 +34,21 @@ View getView(); /** - * Called by {@link SideUiCoordinator} to determine the container's desired width given the - * available width and window width. + * Called by {@link SideUiCoordinator} for this container to determine its final width given the + * constraints of {@code availableWidth} and {@code windowWidth}. * * <p>Notably, no UI changes should actually occur in this method. The {@link SideUiCoordinator} * that is hosting this container is responsible for calling {@link #setWidth}, etc. to actually - * reflect the newly calculated width. + * apply the final width. * + * @param requestedWidth The width requested by this container via {@link + * SideUiCoordinator#requestUpdateContainer}, in px. * @param availableWidth The available width that this container can consume in px. * @param windowWidth The new window width in px. */ @Px - int determineContainerWidth(@Px int availableWidth, @Px int windowWidth); + int determineContainerWidth( + @Px int requestedWidth, @Px int availableWidth, @Px int windowWidth); /** Returns the container's current width. */ @Px
diff --git a/chrome/browser/ui/side_ui/public/android/java/src/org/chromium/chrome/browser/ui/side_ui/MarginContainerSideUiObserver.java b/chrome/browser/ui/side_ui/public/android/java/src/org/chromium/chrome/browser/ui/side_ui/ViewMarginAdjusterForSideUi.java similarity index 93% rename from chrome/browser/ui/side_ui/public/android/java/src/org/chromium/chrome/browser/ui/side_ui/MarginContainerSideUiObserver.java rename to chrome/browser/ui/side_ui/public/android/java/src/org/chromium/chrome/browser/ui/side_ui/ViewMarginAdjusterForSideUi.java index 67e7298..81e478c 100644 --- a/chrome/browser/ui/side_ui/public/android/java/src/org/chromium/chrome/browser/ui/side_ui/MarginContainerSideUiObserver.java +++ b/chrome/browser/ui/side_ui/public/android/java/src/org/chromium/chrome/browser/ui/side_ui/ViewMarginAdjusterForSideUi.java
@@ -18,7 +18,7 @@ * XML) but will not account for padding applied programmatically after construction. */ @NullMarked -public class MarginContainerSideUiObserver implements SideUiObserver { +public class ViewMarginAdjusterForSideUi implements SideUiObserver { private final View mView; private final int mBaseStartMargin; private final int mBaseEndMargin; @@ -28,7 +28,7 @@ * * @param view The view to which margins should be applied. */ - public MarginContainerSideUiObserver(View view) { + public ViewMarginAdjusterForSideUi(View view) { mView = view; // Save the existing, base margins for the container view. Margins added to account for side
diff --git a/chrome/browser/ui/side_ui/public/android/java/src/org/chromium/chrome/browser/ui/side_ui/MarginContainerSideUiObserverTest.java b/chrome/browser/ui/side_ui/public/android/java/src/org/chromium/chrome/browser/ui/side_ui/ViewMarginAdjusterForSideUiTest.java similarity index 92% rename from chrome/browser/ui/side_ui/public/android/java/src/org/chromium/chrome/browser/ui/side_ui/MarginContainerSideUiObserverTest.java rename to chrome/browser/ui/side_ui/public/android/java/src/org/chromium/chrome/browser/ui/side_ui/ViewMarginAdjusterForSideUiTest.java index 9ba08a0..d5f2443 100644 --- a/chrome/browser/ui/side_ui/public/android/java/src/org/chromium/chrome/browser/ui/side_ui/MarginContainerSideUiObserverTest.java +++ b/chrome/browser/ui/side_ui/public/android/java/src/org/chromium/chrome/browser/ui/side_ui/ViewMarginAdjusterForSideUiTest.java
@@ -25,9 +25,9 @@ import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.chrome.browser.ui.side_ui.SideUiCoordinator.SideUiSpecs; -/** Tests for {@link MarginContainerSideUiObserver}. */ +/** Tests for {@link ViewMarginAdjusterForSideUi}. */ @RunWith(BaseRobolectricTestRunner.class) -public class MarginContainerSideUiObserverTest { +public class ViewMarginAdjusterForSideUiTest { @Rule public MockitoRule mockitoRule = MockitoJUnit.rule(); @Mock View mView; @@ -43,7 +43,7 @@ @Test public void testOnSideUiSpecsChanged_noBaseMargin() { - SideUiObserver marginContainerObserver = new MarginContainerSideUiObserver(mView); + SideUiObserver marginContainerObserver = new ViewMarginAdjusterForSideUi(mView); // End margin marginContainerObserver.onSideUiSpecsChanged(new SideUiSpecs(0, 200)); @@ -69,7 +69,7 @@ mMarginLayoutParams.setMarginStart(20); mMarginLayoutParams.setMarginEnd(35); - SideUiObserver marginContainerObserver = new MarginContainerSideUiObserver(mView); + SideUiObserver marginContainerObserver = new ViewMarginAdjusterForSideUi(mView); // End margin marginContainerObserver.onSideUiSpecsChanged(new SideUiSpecs(0, 200));
diff --git a/chrome/browser/ui/side_ui/test/android/BUILD.gn b/chrome/browser/ui/side_ui/test/android/BUILD.gn index aabfa4f..a820d59 100644 --- a/chrome/browser/ui/side_ui/test/android/BUILD.gn +++ b/chrome/browser/ui/side_ui/test/android/BUILD.gn
@@ -13,5 +13,6 @@ deps = [ "//build/android:build_java", "//chrome/browser/ui/side_ui/public:java", + "//third_party/androidx:androidx_annotation_annotation_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 index 5740ff77..07505112 100644 --- 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
@@ -7,8 +7,24 @@ import android.view.View; import android.view.ViewGroup.LayoutParams; +import androidx.annotation.Px; + +import org.chromium.build.annotations.NullMarked; +import org.chromium.build.annotations.Nullable; + /** Minimum implementation of {@link SideUiContainer} to allow setting/getting width for tests. */ -public class TestSideUiContainer implements SideUiContainer { +@NullMarked +public final class TestSideUiContainer implements SideUiContainer { + + /** The last {@code requestedWidth} received by {@link #determineContainerWidth}. */ + public @Nullable @Px Integer mLastRequestedWidth; + + /** The last {@code availableWidth} received by {@link #determineContainerWidth}. */ + public @Nullable @Px Integer mLastAvailableWidth; + + /** The last {@code windowWidth} received by {@link #determineContainerWidth}. */ + public @Nullable @Px Integer mLastWindowWidth; + private final View mSideUiContainerView; public TestSideUiContainer(View view) { @@ -21,8 +37,13 @@ } @Override - public int determineContainerWidth(int availableWidth, int windowWidth) { - return 0; + public int determineContainerWidth( + @Px int requestedWidth, @Px int availableWidth, @Px int windowWidth) { + mLastRequestedWidth = requestedWidth; + mLastAvailableWidth = availableWidth; + mLastWindowWidth = windowWidth; + + return requestedWidth; } @Override
diff --git a/chrome/browser/ui/startup/default_browser_prompt/default_browser_bubble_dialog.cc b/chrome/browser/ui/startup/default_browser_prompt/default_browser_bubble_dialog.cc index 8db9944..dc9993c0 100644 --- a/chrome/browser/ui/startup/default_browser_prompt/default_browser_bubble_dialog.cc +++ b/chrome/browser/ui/startup/default_browser_prompt/default_browser_bubble_dialog.cc
@@ -188,9 +188,8 @@ auto bubble = std::make_unique<views::BubbleDialogModelHost>( std::move(dialog_model), anchor, views::BubbleBorder::TOP_RIGHT); - auto widget = - base::WrapUnique(views::BubbleDialogDelegate::CreateBubbleDeprecated( - std::move(bubble), views::Widget::InitParams::CLIENT_OWNS_WIDGET)); + std::unique_ptr<views::Widget> widget = + views::BubbleDialogDelegate::CreateBubble(std::move(bubble)); widget->Show();
diff --git a/chrome/browser/ui/views/accessibility_annotator/accessibility_annotator_info_dialog_controller.cc b/chrome/browser/ui/views/accessibility_annotator/accessibility_annotator_info_dialog_controller.cc index fa56a2f..d00a996 100644 --- a/chrome/browser/ui/views/accessibility_annotator/accessibility_annotator_info_dialog_controller.cc +++ b/chrome/browser/ui/views/accessibility_annotator/accessibility_annotator_info_dialog_controller.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/ui/views/accessibility_annotator/accessibility_annotator_info_dialog_controller.h" +#include <memory> #include <utility> #include "base/functional/callback_helpers.h" @@ -90,9 +91,8 @@ dialog_view->set_has_parent(false); } - views::Widget* widget = views::BubbleDialogDelegateView::CreateBubble( - std::move(dialog_view), views::Widget::InitParams::CLIENT_OWNS_WIDGET); - dialog_widget_ = base::WrapUnique(widget); + dialog_widget_ = + views::BubbleDialogDelegate::CreateBubble(std::move(dialog_view)); // Ensure that the dialog is closed synchronously when the widget is // destroyed.
diff --git a/chrome/browser/ui/views/autofill/popup/popup_row_factory_utils.cc b/chrome/browser/ui/views/autofill/popup/popup_row_factory_utils.cc index efcc7189..b8d88c8 100644 --- a/chrome/browser/ui/views/autofill/popup/popup_row_factory_utils.cc +++ b/chrome/browser/ui/views/autofill/popup/popup_row_factory_utils.cc
@@ -25,6 +25,7 @@ #include "chrome/app/vector_icons/vector_icons.h" #include "chrome/browser/ui/autofill/autofill_popup_controller.h" #include "chrome/browser/ui/autofill/autofill_suggestion_controller_utils.h" +#include "chrome/browser/ui/color/chrome_color_id.h" #include "chrome/browser/ui/views/autofill/payments/bnpl_issuer_linked_pill.h" #include "chrome/browser/ui/views/autofill/popup/lazy_loading_image_view.h" #include "chrome/browser/ui/views/autofill/popup/popup_base_view.h" @@ -55,6 +56,7 @@ #include "ui/accessibility/ax_enums.mojom.h" #include "ui/base/l10n/l10n_util.h" #include "ui/color/color_id.h" +#include "ui/compositor/layer.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/text_constants.h" #include "ui/views/accessibility/view_accessibility.h" @@ -108,6 +110,7 @@ views::style::TextStyle::STYLE_BODY_3_BOLD; constexpr auto kMinorTextStyle = views::style::TextStyle::STYLE_BODY_4; constexpr auto kDisabledTextStyle = views::style::TextStyle::STYLE_DISABLED; +constexpr float kDisabledBnplOpacity = 0.38f; // Returns a wrapper around `closure` that posts it to the default message // queue instead of executing it directly. This is to avoid that the callback's @@ -143,6 +146,15 @@ } } +// Used to check if a suggestion should be displayed with styling specific to +// deactivated BNPL suggestions. +// TODO(crbug.com/503847790): Consolidate all deactivated suggestion styles, +// pending alignment from UX. +bool IsDeactivatedBnplSuggestion(const Suggestion& suggestion) { + return suggestion.type == SuggestionType::kBnplEntry && + suggestion.HasDeactivatedStyle(); +} + std::unique_ptr<views::BoxLayoutView> GetAlternativePaymentMethodBadge( std::u16string_view label) { // 100 is guaranteed to be larger than half the height of this view. Using 100 @@ -217,6 +229,10 @@ if (!suggestion.main_text.is_primary) { label->SetEnabledColor(ui::kColorLabelForegroundSecondary); } + if (IsDeactivatedBnplSuggestion(suggestion)) { + label->SetEnabledColor(kColorAutofillPopupDeactivatedBnplForeground); + } + return label; } @@ -274,6 +290,9 @@ if (!IsDeactivatedPasswordOrPasskey(suggestion)) { label->SetEnabledColor(ui::kColorLabelForegroundSecondary); } + if (IsDeactivatedBnplSuggestion(suggestion)) { + label->SetEnabledColor(kColorAutofillPopupDeactivatedBnplForeground); + } // To make sure the popup width will not exceed its maximum value, // divide the maximum label width by the number of labels. FormatLabel(*label, label_text, main_filling_product, @@ -544,10 +563,20 @@ std::vector<std::unique_ptr<views::View>> subtexts = CreateSubtextViews(*view, suggestion, main_filling_product); + std::unique_ptr<views::ImageView> icon = + popup_cell_utils::GetIconImageView(suggestion); + if (suggestion.HasDeactivatedStyle()) { + if (icon) { + icon->SetPaintToLayer(); + icon->layer()->SetFillsBoundsOpaquely(false); + icon->layer()->SetOpacity(kDisabledBnplOpacity); + } + } + popup_cell_utils::AddSuggestionContentToView( suggestion, std::move(main_text_label), std::move(minor_texts), - /*description_label=*/nullptr, std::move(subtexts), - popup_cell_utils::GetIconImageView(suggestion), *view); + /*description_label=*/nullptr, std::move(subtexts), std::move(icon), + *view); return view; }
diff --git a/chrome/browser/ui/views/autofill/popup/popup_row_factory_utils_unittest.cc b/chrome/browser/ui/views/autofill/popup/popup_row_factory_utils_unittest.cc index 4e9f7975..3bfac64 100644 --- a/chrome/browser/ui/views/autofill/popup/popup_row_factory_utils_unittest.cc +++ b/chrome/browser/ui/views/autofill/popup/popup_row_factory_utils_unittest.cc
@@ -34,6 +34,7 @@ #include "ui/events/test/event_generator.h" #include "ui/views/accessibility/view_accessibility.h" #include "ui/views/controls/button/image_button.h" +#include "ui/views/controls/image_view.h" #include "ui/views/controls/throbber.h" #include "ui/views/view_utils.h" #include "ui/views/widget/widget_utils.h" @@ -44,6 +45,10 @@ namespace autofill { +namespace { +constexpr float kDisabledBnplOpacity = 0.38f; +} + class PopupRowFactoryUtilsTest : public ChromeViewsTestBase { public: void SetUp() override { @@ -216,7 +221,28 @@ payments::BnplLinkedIssuerPill::kBnplLinkedPillElementId); ASSERT_THAT(pill, NotNull()); EXPECT_FALSE(pill->GetEnabled()); - EXPECT_FLOAT_EQ(0.38f, pill->layer()->opacity()); + EXPECT_FLOAT_EQ(kDisabledBnplOpacity, pill->layer()->opacity()); +} + +TEST_F(BnplPopupRowViewTest, Deactivated_IconOpacity) { + Suggestion suggestion(u"Bnpl", SuggestionType::kBnplEntry); + suggestion.icon = Suggestion::Icon::kBnplGeneric; + suggestion.acceptability = + Suggestion::Acceptability::kUnacceptableWithDeactivatedStyle; + + ShowSuggestion(suggestion); + + views::ImageView* icon_view = nullptr; + for (const auto& child : row_view().GetContentView().children()) { + if (auto* img = views::AsViewClass<views::ImageView>(child.get())) { + icon_view = img; + break; + } + } + + ASSERT_THAT(icon_view, NotNull()); + EXPECT_TRUE(icon_view->layer()); + EXPECT_FLOAT_EQ(kDisabledBnplOpacity, icon_view->layer()->opacity()); } TEST_F(BnplPopupRowViewTest, UnlinkedIssuer_NoLinkedPill) {
diff --git a/chrome/browser/ui/views/data_sharing/data_sharing_bubble_controller.cc b/chrome/browser/ui/views/data_sharing/data_sharing_bubble_controller.cc index 96b6c12..e928bde 100644 --- a/chrome/browser/ui/views/data_sharing/data_sharing_bubble_controller.cc +++ b/chrome/browser/ui/views/data_sharing/data_sharing_bubble_controller.cc
@@ -142,21 +142,20 @@ views::Widget::InitParams::CLIENT_OWNS_WIDGET); bubble_view_ = bubble_view->GetWeakPtr(); - views::Widget* widget = nullptr; + std::unique_ptr<views::Widget> widget; if (flow_value == data_sharing::kFlowShare) { // Sharing flow uses a normal bubble. - widget = views::BubbleDialogDelegateView::CreateBubble( - std::move(bubble_view), views::Widget::InitParams::CLIENT_OWNS_WIDGET); + widget = views::BubbleDialogDelegate::CreateBubble(std::move(bubble_view)); } else { // Manage and Join flow use modals. In this case the `anchor_view_for_share` // doesn't take effect. bubble_view->SetModalType(ui::mojom::ModalType::kWindow); - widget = constrained_window::CreateBrowserModalDialogViews( - std::move(bubble_view), browser_view->GetNativeWindow()); + widget = base::WrapUnique(constrained_window::CreateBrowserModalDialogViews( + std::move(bubble_view), browser_view->GetNativeWindow())); } CHECK(widget); - bubble_widget_ = base::WrapUnique(widget); + bubble_widget_ = std::move(widget); bubble_widget_->MakeCloseSynchronous(base::BindOnce( &DataSharingBubbleController::OnWidgetClosing, base::Unretained(this))); }
diff --git a/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc b/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc index 2b8b573..a2e4162 100644 --- a/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc +++ b/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc
@@ -547,7 +547,7 @@ feature_list_.InitWithFeaturesAndParameters( {{blink::features::kPreserveDropEffect, {}}, {blink::features::kSetDefaultDropEffect, {}}}, - {blink::features::kSupportOpeningDraggedLinksInSameTab}); + {}); InProcessBrowserTest::SetUp(); } @@ -958,52 +958,6 @@ EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_TAB_CONTAINER)); } -class DragAndDropDragLinksInSameTabBrowserTest : public DragAndDropBrowserTest { - public: - void SetUp() override { - // Ensure PreserveDropEffect is enabled based on the setting of parent class - // DragAndDropBrowserTest. - feature_list_.InitWithFeaturesAndParameters( - {{blink::features::kPreserveDropEffect, {}}, - {blink::features::kSupportOpeningDraggedLinksInSameTab, {}}}, - {}); - InProcessBrowserTest::SetUp(); - } - - private: - base::test::ScopedFeatureList feature_list_; -}; - -// Scenario: drag URL from outside the browser and drop to half of a Split View. -IN_PROC_BROWSER_TEST_P(DragAndDropDragLinksInSameTabBrowserTest, - DropValidUrlFromOutside) { - std::string frame_site = use_cross_site_subframe() ? "b.test" : "a.test"; - ASSERT_TRUE(NavigateToTestPage(frame_site)); - - // Create a second tab and create split view. - chrome::AddTabAt(browser(), GURL(), -1, true); - browser()->tab_strip_model()->ActivateTabAt(1); - browser()->tab_strip_model()->AddToNewSplit( - {0}, split_tabs::SplitTabVisualData(), - split_tabs::SplitTabCreatedSource::kToolbarButton); - ASSERT_EQ(2, browser()->tab_strip_model()->count()); - - // Drag a normal URL from outside the browser into/over the left side of the - // Split View. - GURL dragged_url = https_test_server()->GetURL("d.test", "/title2.html"); - ASSERT_TRUE( - drag_simulator()->SimulateDragEnter(gfx::Point(100, 100), dragged_url)); - ASSERT_TRUE(drag_simulator()->SimulateDrop(gfx::Point(100, 100))); - - // Verify that dropping |dragged_url| navigates the left tab to that URL. - EXPECT_EQ(2, browser()->tab_strip_model()->count()); - content::WebContents* left_web_contents = - browser()->tab_strip_model()->GetWebContentsAt(0); - content::TestNavigationObserver(left_web_contents, 1).Wait(); - EXPECT_EQ(dragged_url, - left_web_contents->GetPrimaryMainFrame()->GetLastCommittedURL()); -} - #if BUILDFLAG(IS_WIN) // Scenario: Drag and drop a file from outside the browser and it should have // associated file type, fetched from it's diplay_name. Test coverage: @@ -2320,18 +2274,6 @@ ::testing::Combine(::testing::Values(true), ::testing::ValuesIn(ui_scaling_factors))); -INSTANTIATE_TEST_SUITE_P( - SameSiteSubframe, - DragAndDropDragLinksInSameTabBrowserTest, - ::testing::Combine(::testing::Values(false), - ::testing::ValuesIn(ui_scaling_factors))); - -INSTANTIATE_TEST_SUITE_P( - CrossSiteSubframe, - DragAndDropDragLinksInSameTabBrowserTest, - ::testing::Combine(::testing::Values(true), - ::testing::ValuesIn(ui_scaling_factors))); - #if BUILDFLAG(IS_CHROMEOS) class DragAndDropBrowserTestNoParam : public InProcessBrowserTest { protected:
diff --git a/chrome/browser/ui/views/omnibox/omnibox_match_cell_view.cc b/chrome/browser/ui/views/omnibox/omnibox_match_cell_view.cc index d73ecdac..5f81ac5 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_match_cell_view.cc +++ b/chrome/browser/ui/views/omnibox/omnibox_match_cell_view.cc
@@ -347,6 +347,10 @@ } } +void OmniboxMatchCellView::OnSecondaryTextVisibilityChanged() { + PreferredSizeChanged(); +} + void OmniboxMatchCellView::SetIcon(const gfx::ImageSkia& image, const AutocompleteMatch& match) { const bool is_pedal_suggestion_row = @@ -510,7 +514,9 @@ } int content_width = content_view_->GetPreferredSize().width(); - int description_width = description_view_->GetPreferredSize().width(); + int description_width = description_view_->GetVisible() + ? description_view_->GetPreferredSize().width() + : 0; const gfx::Size separator_size = separator_view_->GetPreferredSize(); int iph_link_width = iph_link_view_->GetPreferredSize().width(); ComputeMatchMaxWidths( @@ -562,7 +568,10 @@ tail_suggest_common_prefix_width_ + content_view_->GetPreferredSize().width() + iph_link_view_->GetPreferredSize().width(); - const int description_width = description_view_->GetPreferredSize().width(); + const int description_width = + description_view_->GetVisible() + ? description_view_->GetPreferredSize().width() + : 0; if (description_width > 0) { width += separator_view_->GetPreferredSize().width() + description_width; }
diff --git a/chrome/browser/ui/views/omnibox/omnibox_match_cell_view.h b/chrome/browser/ui/views/omnibox/omnibox_match_cell_view.h index c4e367c..a190df7 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_match_cell_view.h +++ b/chrome/browser/ui/views/omnibox/omnibox_match_cell_view.h
@@ -80,6 +80,9 @@ void OnMatchUpdate(const OmniboxResultView* result_view, const AutocompleteMatch& match); + // Notifies the view that the visibility of the secondary text has changed. + void OnSecondaryTextVisibilityChanged(); + // Set's the `icon_view_` image, possibly with a rounded square background. void SetIcon(const gfx::ImageSkia& image, const AutocompleteMatch& match);
diff --git a/chrome/browser/ui/views/omnibox/omnibox_popup_view_webui_interactive_uitest.cc b/chrome/browser/ui/views/omnibox/omnibox_popup_view_webui_interactive_uitest.cc index 708d655..60b406f 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_popup_view_webui_interactive_uitest.cc +++ b/chrome/browser/ui/views/omnibox/omnibox_popup_view_webui_interactive_uitest.cc
@@ -112,9 +112,6 @@ void SetUp() override; - // Wait until page remote is bound and ready to receive calls. - void WaitForHandler(); - private: OmniboxTriggeredFeatureService triggered_feature_service_; base::test::ScopedFeatureList feature_list_; @@ -185,23 +182,7 @@ InProcessBrowserTest::SetUp(); } -void OmniboxPopupViewWebUITest::WaitForHandler() { - auto* popup_view = static_cast<OmniboxPopupViewWebUI*>( - location_bar()->GetOmniboxPopupViewForTesting()); - auto* omnibox_popup_webui_content = - popup_view->presenter()->GetWebUIContent(); - auto* web_contents = omnibox_popup_webui_content->GetWebContents(); - content::WaitForLoadStop(web_contents); - - WebuiOmniboxHandler* handler = - static_cast<OmniboxPopupUI*>(web_contents->GetWebUI()->GetController()) - ->omnibox_handler(); - base::test::TestFuture<void> future; - handler->set_page_is_bound_callback_for_testing(future.GetCallback()); - EXPECT_TRUE(future.Wait()); - EXPECT_TRUE(handler->IsRemoteBound()); -} // Check that the location bar background (and the background of the textfield // it contains) changes when it receives focus, and matches the popup background @@ -239,7 +220,6 @@ } IN_PROC_BROWSER_TEST_F(OmniboxPopupViewWebUITest, PopupLoadsAndAcceptsCalls) { - WaitForHandler(); auto* popup_view = static_cast<OmniboxPopupViewWebUI*>( location_bar()->GetOmniboxPopupViewForTesting()); popup_view->presenter()->Show();
diff --git a/chrome/browser/ui/views/omnibox/omnibox_result_view.cc b/chrome/browser/ui/views/omnibox/omnibox_result_view.cc index 5a41c6d..82ed466 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_result_view.cc +++ b/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
@@ -381,6 +381,7 @@ suggestion_view_->OnMatchUpdate(this, match_); UpdateDividerLineVisibility(); + UpdateSecondaryTextVisibility(); UpdateFeedbackButtonsVisibility(); UpdateRemoveSuggestionVisibility(); if (match_.IsIphSuggestion()) { @@ -523,6 +524,7 @@ void OmniboxResultView::OnSelectionStateChanged() { UpdateDividerLineVisibility(); + UpdateSecondaryTextVisibility(); UpdateFeedbackButtonsVisibility(); UpdateRemoveSuggestionVisibility(); UpdateAccessibleName(); @@ -695,6 +697,7 @@ void OmniboxResultView::UpdateHoverState() { UpdateDividerLineVisibility(); + UpdateSecondaryTextVisibility(); UpdateFeedbackButtonsVisibility(); UpdateRemoveSuggestionVisibility(); ApplyThemeAndRefreshIcons(); @@ -712,6 +715,20 @@ } } +void OmniboxResultView::UpdateSecondaryTextVisibility() { + const bool is_contextual = match_.IsContextualSearchSuggestion(); + + const bool show_description = + !is_contextual || GetMatchSelected() || IsMouseHovered(); + if (suggestion_view_->description()->GetVisible() != show_description) { + suggestion_view_->description()->SetVisible(show_description); + suggestion_view_->separator()->SetVisible(show_description); + // Explicitly notify the parent that the preferred size has changed, as + // the row's FlexLayout depends on this to allocate space. + suggestion_view_->OnSecondaryTextVisibilityChanged(); + } +} + void OmniboxResultView::UpdateFeedbackButtonsVisibility() { const bool old_visibility = thumbs_up_button_->GetVisible(); const bool new_visibility =
diff --git a/chrome/browser/ui/views/omnibox/omnibox_result_view.h b/chrome/browser/ui/views/omnibox/omnibox_result_view.h index e305ac3..aaeaef3 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_result_view.h +++ b/chrome/browser/ui/views/omnibox/omnibox_result_view.h
@@ -103,6 +103,7 @@ private: FRIEND_TEST_ALL_PREFIXES(OmniboxPopupViewViewsTest, DeleteSuggestion); + FRIEND_TEST_ALL_PREFIXES(OmniboxResultViewTest, ContextualSecondaryText); void OpenIphLink(); @@ -114,6 +115,10 @@ void UpdateDividerLineVisibility(); + // Sets the visibility of the secondary text (description) based on the + // current state. Only applies to contextual suggestions. + void UpdateSecondaryTextVisibility(); + // Sets the visibility of the |thumbs_up_button_| and |thumbs_down_button_| // based on the current state. void UpdateFeedbackButtonsVisibility();
diff --git a/chrome/browser/ui/views/omnibox/omnibox_result_view_unittest.cc b/chrome/browser/ui/views/omnibox/omnibox_result_view_unittest.cc index f9632f7..60729184 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_result_view_unittest.cc +++ b/chrome/browser/ui/views/omnibox/omnibox_result_view_unittest.cc
@@ -11,11 +11,14 @@ #include "chrome/browser/ui/omnibox/omnibox_controller.h" #include "chrome/browser/ui/omnibox/omnibox_theme.h" #include "chrome/browser/ui/views/omnibox/omnibox_header_view.h" +#include "chrome/browser/ui/views/omnibox/omnibox_match_cell_view.h" #include "chrome/browser/ui/views/omnibox/omnibox_popup_view_views.h" #include "chrome/browser/ui/views/omnibox/omnibox_row_view.h" +#include "chrome/browser/ui/views/omnibox/omnibox_text_view.h" #include "chrome/test/views/chrome_views_test_base.h" #include "components/omnibox/browser/test_omnibox_client.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/omnibox_proto/types.pb.h" #include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_node_data.h" #include "ui/display/test/test_screen.h" @@ -317,3 +320,40 @@ // No assertions necessary; just exercising code paths for featured Enterprise // search match. } + +TEST_F(OmniboxResultViewTest, ContextualSecondaryText) { + OmniboxMatchCellView* suggestion_view = result_view()->suggestion_view_; + OmniboxTextView* description_view = suggestion_view->description(); + + // 1. Test subtype-based identification. + { + AutocompleteMatch match; + match.subtypes.insert(omnibox::SuggestSubtype::SUBTYPE_CONTEXTUAL_SEARCH); + match.description = u"secondary text"; + result_view()->SetMatch(match); + + // Initially not hovered or selected, so description should be hidden. + EXPECT_FALSE(description_view->GetVisible()); + + // Hovering should show the description. + result_view()->OnMouseEntered( + FakeMouseEvent(ui::EventType::kMouseEntered, 0)); + EXPECT_TRUE(description_view->GetVisible()); + + // Un-hovering should hide it again. + result_view()->OnMouseExited( + FakeMouseEvent(ui::EventType::kMouseMoved, 0, 200, 200)); + EXPECT_FALSE(description_view->GetVisible()); + } + + // 2. Test reusability (contextual -> normal). + { + AutocompleteMatch normal_match; + normal_match.description = u"normal description"; + // Reuse the view that was previously contextual. + result_view()->SetMatch(normal_match); + + // Normal suggestions should always show their description. + EXPECT_TRUE(description_view->GetVisible()); + } +}
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc index 6b6efbb..e2b2736 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc +++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
@@ -51,14 +51,15 @@ #include "chrome/browser/ui/omnibox/omnibox_controller.h" #include "chrome/browser/ui/omnibox/omnibox_edit_model.h" #include "chrome/browser/ui/omnibox/omnibox_next_features.h" +#include "chrome/browser/ui/omnibox/omnibox_popup_view.h" #include "chrome/browser/ui/omnibox/omnibox_tab_helper.h" #include "chrome/browser/ui/page_action/page_action_icon_type.h" +#include "chrome/browser/ui/ui_features.h" #include "chrome/browser/ui/view_ids.h" #include "chrome/browser/ui/views/chrome_layout_provider.h" #include "chrome/browser/ui/views/frame/immersive_mode_controller.h" #include "chrome/browser/ui/views/location_bar/icon_label_bubble_view.h" #include "chrome/browser/ui/views/location_bar/location_bar_view.h" -#include "chrome/browser/ui/omnibox/omnibox_popup_view.h" #include "chrome/browser/ui/views/omnibox/omnibox_popup_closer.h" #include "chrome/browser/ui/views/omnibox/omnibox_text_view.h" #include "chrome/browser/ui/views/page_action/page_action_container_view.h" @@ -2385,6 +2386,21 @@ } void OmniboxViewViews::UpdateContextMenu(ui::SimpleMenuModel* menu_contents) { + if (base::FeatureList::IsEnabled(features::kMenuSimplification)) { + // Remove the emoji item from the omnibox context menu. + const std::optional<size_t> emoji_position = + menu_contents->GetIndexOfCommandId(IDS_CONTENT_CONTEXT_EMOJI); + if (emoji_position.has_value()) { + menu_contents->RemoveItemAt(emoji_position.value()); + // If the next item is a separator, remove it too. + if (emoji_position.value() < menu_contents->GetItemCount() && + menu_contents->GetTypeAt(emoji_position.value()) == + ui::MenuModel::ItemType::TYPE_SEPARATOR) { + menu_contents->RemoveItemAt(emoji_position.value()); + } + } + } + MaybeAddSendTabToSelfItem(menu_contents); const std::optional<size_t> paste_position = @@ -2402,6 +2418,10 @@ ? IDS_MANAGE_SEARCH_ENGINES_AND_SHORTCUTS : IDS_MANAGE_SEARCH_ENGINES_AND_SITE_SEARCH); + if (base::FeatureList::IsEnabled(features::kMenuSimplification)) { + menu_contents->AddSeparator(ui::NORMAL_SEPARATOR); + } + const PrefService::Preference* show_full_urls_pref = location_bar_view_->GetProfile()->GetPrefs()->FindPreference( omnibox::kPreventUrlElisionsInOmnibox); @@ -2618,6 +2638,10 @@ return; } + if (base::FeatureList::IsEnabled(features::kMenuSimplification)) { + return; + } + size_t index = menu_contents->GetIndexOfCommandId(Textfield::kUndo).value(); // Add a separator if this is not the first item. if (index) {
diff --git a/chrome/browser/ui/views/record_replay/replay_recording_bubble_view.cc b/chrome/browser/ui/views/record_replay/replay_recording_bubble_view.cc index 4db60e0..7d11b5c 100644 --- a/chrome/browser/ui/views/record_replay/replay_recording_bubble_view.cc +++ b/chrome/browser/ui/views/record_replay/replay_recording_bubble_view.cc
@@ -44,8 +44,8 @@ ui::ImageModel::FromImage(gfx::Image(gfx::CreateVectorIcon( vector_icons::kPlayArrowIcon, /*dip_size=*/100, anchor_view->GetColorProvider()->GetColor(ui::kColorIcon))))); - auto widget = base::WrapUnique(views::BubbleDialogDelegateView::CreateBubble( - std::move(bubble), views::Widget::InitParams::CLIENT_OWNS_WIDGET)); + std::unique_ptr<views::Widget> widget = + views::BubbleDialogDelegate::CreateBubble(std::move(bubble)); bubble_ptr->ShowForReason(LocationBarBubbleDelegateView::USER_GESTURE); return widget; }
diff --git a/chrome/browser/ui/views/user_education/custom_webui_help_bubble.h b/chrome/browser/ui/views/user_education/custom_webui_help_bubble.h index bfa8635..9857683 100644 --- a/chrome/browser/ui/views/user_education/custom_webui_help_bubble.h +++ b/chrome/browser/ui/views/user_education/custom_webui_help_bubble.h
@@ -5,6 +5,9 @@ #ifndef CHROME_BROWSER_UI_VIEWS_USER_EDUCATION_CUSTOM_WEBUI_HELP_BUBBLE_H_ #define CHROME_BROWSER_UI_VIEWS_USER_EDUCATION_CUSTOM_WEBUI_HELP_BUBBLE_H_ +#include <memory> +#include <utility> + #include "base/functional/callback_forward.h" #include "base/memory/ptr_util.h" #include "chrome/browser/profiles/profiles_state.h" @@ -149,8 +152,8 @@ bubble->set_shadow( user_education::HelpBubbleFactoryViews::GetDefaultBubbleShadow()); - auto widget = base::WrapUnique(views::BubbleDialogDelegateView::CreateBubble( - std::move(bubble_ptr), views::Widget::InitParams::CLIENT_OWNS_WIDGET)); + std::unique_ptr<views::Widget> widget = + views::BubbleDialogDelegate::CreateBubble(std::move(bubble_ptr)); // Maybe set the arrow. This may require recalculating the bubble bounds. if (params.arrow != user_education::HelpBubbleArrow::kNone) {
diff --git a/chrome/browser/ui/views/web_apps/web_app_install_dialog_browsertest.cc b/chrome/browser/ui/views/web_apps/web_app_install_dialog_browsertest.cc index 7be7497..fbbeb20 100644 --- a/chrome/browser/ui/views/web_apps/web_app_install_dialog_browsertest.cc +++ b/chrome/browser/ui/views/web_apps/web_app_install_dialog_browsertest.cc
@@ -230,7 +230,13 @@ base::WeakPtrFactory<WebAppInstallDialogBrowserTest> weak_ptr_factory_{this}; }; -IN_PROC_BROWSER_TEST_P(WebAppInstallDialogBrowserTest, InvokeUi_Intro) { +// TODO(crbug.com/510455863): Re-enable the test +#if BUILDFLAG(IS_WIN) +#define MAYBE_InvokeUi_Intro DISABLED_InvokeUi_Intro +#else +#define MAYBE_InvokeUi_Intro InvokeUi_Intro +#endif +IN_PROC_BROWSER_TEST_P(WebAppInstallDialogBrowserTest, MAYBE_InvokeUi_Intro) { ShowAndVerifyUi(); }
diff --git a/chrome/browser/ui/views/web_apps/web_app_install_flow_dialog_delegate.cc b/chrome/browser/ui/views/web_apps/web_app_install_flow_dialog_delegate.cc index 005b6fb..faf7be3 100644 --- a/chrome/browser/ui/views/web_apps/web_app_install_flow_dialog_delegate.cc +++ b/chrome/browser/ui/views/web_apps/web_app_install_flow_dialog_delegate.cc
@@ -168,9 +168,7 @@ WebAppInstallFlowDialogDelegate::~WebAppInstallFlowDialogDelegate() = default; bool WebAppInstallFlowDialogDelegate::AdvanceToNextStepOrClose() { - if (!dialog_model()) { - return false; - } + CHECK(dialog_model()); // Update install dialog step. switch (current_step_) { @@ -299,18 +297,17 @@ break; } - if (dialog_model() && dialog_model()->host()) { - auto* host = - static_cast<views::BubbleDialogModelHost*>(dialog_model()->host()); - host->SetTitle(title); - host->SetAccessibleTitle(title); - // Clear the subtitle for all subsequent steps. - host->SetSubtitle(std::u16string()); + CHECK(dialog_model() && dialog_model()->host()); + auto* host = + static_cast<views::BubbleDialogModelHost*>(dialog_model()->host()); + host->SetTitle(title); + host->SetAccessibleTitle(title); + // Clear the subtitle for all subsequent steps. + host->SetSubtitle(std::u16string()); - // Clear the header for all subsequent steps. - if (host->GetBubbleFrameView()) { - host->GetBubbleFrameView()->SetHeaderView(nullptr); - } + // Clear the header for all subsequent steps. + if (host->GetBubbleFrameView()) { + host->GetBubbleFrameView()->SetHeaderView(nullptr); } }
diff --git a/chrome/browser/ui/webauthn/authenticator_dialog_browsertest.cc b/chrome/browser/ui/webauthn/authenticator_dialog_browsertest.cc index 634f5525..2acd0cd 100644 --- a/chrome/browser/ui/webauthn/authenticator_dialog_browsertest.cc +++ b/chrome/browser/ui/webauthn/authenticator_dialog_browsertest.cc
@@ -1102,7 +1102,7 @@ } // EnclaveManager::Observer - void OnKeysStored() override { + void OnKeysStored(const GaiaId& gaia_id) override { EnclaveManagerFactory::GetAsEnclaveManagerForProfile(browser_->profile()) ->RemoveObserver(this); browser_ = nullptr;
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 73507c81..52946db 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
@@ -364,29 +364,17 @@ void ContextualSearchboxHandler::OnTabAdded(TabListInterface& tab_list, tabs::TabInterface* tab, int index) { - if (!IsRemoteBound()) { - return; - } - page_->OnTabStripChanged(); } void ContextualSearchboxHandler::OnActiveTabChanged(TabListInterface& tab_list, tabs::TabInterface* tab) { - if (!IsRemoteBound()) { - return; - } - page_->OnTabStripChanged(); } void ContextualSearchboxHandler::OnTabRemoved(TabListInterface& tab_list, tabs::TabInterface* tab, TabRemovedReason removed_reason) { - if (!IsRemoteBound()) { - return; - } - page_->OnTabStripChanged(); } @@ -397,10 +385,6 @@ void ContextualSearchboxHandler::OnAllTabsAreClosing( TabListInterface& tab_list) { - if (!IsRemoteBound()) { - return; - } - page_->OnTabStripChanged(); } @@ -734,9 +718,6 @@ void ContextualSearchboxHandler::OnInputStateChanged( const contextual_search::InputState& state) { - if (!IsRemoteBound()) { - return; - } page_->OnInputStateChanged(state); } @@ -964,10 +945,8 @@ contextual_search::ContextUploadStatus context_upload_status, const std::optional<contextual_search::ContextUploadErrorType>& error_type) { - if (IsRemoteBound()) { - page_->OnContextualInputStatusChanged(context_token, context_upload_status, - error_type); - } + page_->OnContextualInputStatusChanged(context_token, context_upload_status, + error_type); // Ensure `input_state_model_` is updated when file is uploaded. if (input_state_model_) {
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 68ee756..c9ad08b5 100644 --- a/chrome/browser/ui/webui/cr_components/searchbox/searchbox_handler.cc +++ b/chrome/browser/ui/webui/cr_components/searchbox/searchbox_handler.cc
@@ -956,9 +956,6 @@ page_handler_(this, std::move(pending_page_handler)), page_(std::move(pending_page)) { controller_ = owned_controller_.get(); - if (page_is_bound_callback_for_testing_) { - std::move(page_is_bound_callback_for_testing_).Run(); - } } SearchboxHandler::~SearchboxHandler() { @@ -966,28 +963,17 @@ controller_ = nullptr; } -// TODO(crbug.com/500739761): Remove this check since searchbox.mojom uses -// factory pattern for instantiation making the remote and receiver bound -// at the same time. -bool SearchboxHandler::IsRemoteBound() const { - return page_.is_bound(); -} - void SearchboxHandler::AddFileContextFromBrowser( base::UnguessableToken token, searchbox::mojom::SelectedFileInfoPtr file_info) { - if (page_ && IsRemoteBound()) { - page_->AddFileContext(token, std::move(file_info)); - } + page_->AddFileContext(token, std::move(file_info)); } void SearchboxHandler::OnContextualInputStatusChanged( base::UnguessableToken token, contextual_search::ContextUploadStatus status, std::optional<contextual_search::ContextUploadErrorType> error_type) { - if (page_ && IsRemoteBound()) { - page_->OnContextualInputStatusChanged(token, status, error_type); - } + page_->OnContextualInputStatusChanged(token, status, error_type); } void SearchboxHandler::OnFocusChanged(bool focused) { @@ -1441,15 +1427,6 @@ return omnibox_controller()->autocomplete_controller(); } -void SearchboxHandler::set_page_is_bound_callback_for_testing( - base::OnceClosure callback) { - if (page_.is_bound() && callback) { - std::move(callback).Run(); - return; - } - page_is_bound_callback_for_testing_ = std::move(callback); -} - OmniboxEditModel* SearchboxHandler::edit_model() const { return omnibox_controller()->edit_model(); }
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 3be850e..23df38b1 100644 --- a/chrome/browser/ui/webui/cr_components/searchbox/searchbox_handler.h +++ b/chrome/browser/ui/webui/cr_components/searchbox/searchbox_handler.h
@@ -76,9 +76,6 @@ virtual std::string AutocompleteIconToResourceName( const gfx::VectorIcon& icon) const; - // Returns true if the page remote is bound and ready to receive calls. - bool IsRemoteBound() const; - // Adds file context to the searchbox from the browser. void AddFileContextFromBrowser( base::UnguessableToken token, @@ -165,10 +162,6 @@ void OnDriveUploadClicked(OnDriveUploadClickedCallback callback) override; void GetPageClassification(GetPageClassificationCallback callback) override; - // Stores `callback` to be run when the page remote is bound and ready to - // receive calls. Runs `callback` immediately if the remote is already bound. - void set_page_is_bound_callback_for_testing(base::OnceClosure callback); - protected: FRIEND_TEST_ALL_PREFIXES(RealboxHandlerTest, AutocompleteController_Start); FRIEND_TEST_ALL_PREFIXES(RealboxHandlerTest, RealboxUpdatesEditModelInput); @@ -206,7 +199,6 @@ mojo::Receiver<searchbox::mojom::PageHandler> page_handler_; mojo::Remote<searchbox::mojom::Page> page_; - base::OnceClosure page_is_bound_callback_for_testing_; searchbox::mojom::AutocompleteResultPtr CreateAutocompleteResult( const std::u16string& input,
diff --git a/chrome/browser/ui/webui/indigo_internals/indigo_internals.mojom b/chrome/browser/ui/webui/indigo_internals/indigo_internals.mojom index 7c72f19..914f3b9 100644 --- a/chrome/browser/ui/webui/indigo_internals/indigo_internals.mojom +++ b/chrome/browser/ui/webui/indigo_internals/indigo_internals.mojom
@@ -10,6 +10,7 @@ kNotSignedIn, kMissingCapabilities, kDisabledByPolicy, + kMissingScript, }; // Whether Optimization Guide can make queries to determine whether to offer
diff --git a/chrome/browser/ui/webui/indigo_internals/indigo_internals_page_handler.cc b/chrome/browser/ui/webui/indigo_internals/indigo_internals_page_handler.cc index 1c6ff47..236ac83 100644 --- a/chrome/browser/ui/webui/indigo_internals/indigo_internals_page_handler.cc +++ b/chrome/browser/ui/webui/indigo_internals/indigo_internals_page_handler.cc
@@ -24,6 +24,8 @@ return indigo_internals::mojom::LocalEligibility::kMissingCapabilities; case indigo::LocalEligibility::kDisabledByPolicy: return indigo_internals::mojom::LocalEligibility::kDisabledByPolicy; + case indigo::LocalEligibility::kMissingScript: + return indigo_internals::mojom::LocalEligibility::kMissingScript; } }
diff --git a/chrome/browser/ui/webui/infobar_internals/BUILD.gn b/chrome/browser/ui/webui/infobar_internals/BUILD.gn index a240372d..e599c383 100644 --- a/chrome/browser/ui/webui/infobar_internals/BUILD.gn +++ b/chrome/browser/ui/webui/infobar_internals/BUILD.gn
@@ -53,7 +53,7 @@ "//chrome/browser/profiles:profile", "//chrome/browser/resources/infobar_internals:resources", "//chrome/browser/ui/browser_window", - "//components/infobars/content:content", + "//components/infobars/content", "//content/public/browser", ] @@ -79,8 +79,10 @@ if (enable_extensions) { deps += [ + "//chrome/browser/extensions", "//chrome/browser/extensions/api/debugger", "//chrome/browser/extensions/api/messaging", + "//chrome/browser/themes", "//extensions/browser", "//extensions/common", ]
diff --git a/chrome/browser/ui/webui/infobar_internals/infobar_internals.mojom b/chrome/browser/ui/webui/infobar_internals/infobar_internals.mojom index a56b5317..cf3ead9 100644 --- a/chrome/browser/ui/webui/infobar_internals/infobar_internals.mojom +++ b/chrome/browser/ui/webui/infobar_internals/infobar_internals.mojom
@@ -33,6 +33,10 @@ // Startup launch infobar. Can only be triggered on Windows. [EnableIf=is_win] kStartupLaunch, + + // Theme installed infobar. + [EnableIf=enable_extensions] + kThemeInstalled, }; // Metadata describing an individual infobar that can be triggered.
diff --git a/chrome/browser/ui/webui/infobar_internals/infobar_internals_handler.cc b/chrome/browser/ui/webui/infobar_internals/infobar_internals_handler.cc index 03c0d0e..3d4b572 100644 --- a/chrome/browser/ui/webui/infobar_internals/infobar_internals_handler.cc +++ b/chrome/browser/ui/webui/infobar_internals/infobar_internals_handler.cc
@@ -37,6 +37,9 @@ #include "chrome/browser/extensions/api/debugger/extension_dev_tools_infobar_delegate.h" #include "chrome/browser/extensions/api/messaging/incognito_connectability.h" #include "chrome/browser/extensions/api/messaging/incognito_connectability_infobar_delegate.h" +#include "chrome/browser/extensions/theme_installed_infobar_delegate.h" +#include "chrome/browser/themes/theme_service.h" +#include "chrome/browser/themes/theme_service_factory.h" #include "extensions/browser/extension_registry.h" #include "extensions/common/extension.h" #endif @@ -133,6 +136,15 @@ "enabled.")); #endif +#if BUILDFLAG(ENABLE_EXTENSIONS) + infobar_list.emplace_back(InfoBarEntry::New( + /*type=*/InfoBarType::kThemeInstalled, /*name=*/"Theme Installed", + /*description=*/ + "The Theme Installed infobar is shown when a user installs a theme. " + "This trigger shows the infobar for the current theme, allowing you " + "to 'undo' to the state before this trigger.")); +#endif + std::move(callback).Run(std::move(infobar_list)); } @@ -312,6 +324,37 @@ return false; } #endif +#if BUILDFLAG(ENABLE_EXTENSIONS) + case InfoBarType::kThemeInstalled: { + BrowserWindowInterface* const bwi = + GetLastActiveBrowserWindowInterfaceWithAnyProfile(); + Profile* profile = bwi->GetProfile(); + if (!profile) { + return false; + } + + ThemeService* theme_service = ThemeServiceFactory::GetForProfile(profile); + extensions::ExtensionRegistry* registry = + extensions::ExtensionRegistry::Get(profile); + + std::string theme_name = "Default"; + std::string theme_id = ""; + + if (theme_service->UsingExtensionTheme()) { + theme_id = theme_service->GetThemeID(); + const extensions::Extension* extension = registry->GetExtensionById( + theme_id, extensions::ExtensionRegistry::EVERYTHING); + if (extension) { + theme_name = extension->name(); + } + } + + ThemeInstalledInfoBarDelegate::CreateForLastActiveTab( + profile, theme_name, theme_id, + theme_service->BuildReinstallerForCurrentTheme()); + return true; + } +#endif } return false;
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 92bbc62..d5884e4d 100644 --- a/chrome/browser/ui/webui/searchbox/contextual_searchbox_handler_unittest.cc +++ b/chrome/browser/ui/webui/searchbox/contextual_searchbox_handler_unittest.cc
@@ -191,10 +191,6 @@ void SetUp() override { ContextualSearchboxHandlerTestHarness::SetUp(); - // TODO(crbug.com/503732217): Fix tests to support lazy fetching of cluster - // info and enable this feature by default in tests. - scoped_feature_list_.InitAndDisableFeature( - contextual_tasks::kContextualTasksLazyFetchClusterInfo); auto query_controller_config_params = std::make_unique< contextual_search::ContextualSearchContextController::ConfigParams>(); @@ -296,7 +292,6 @@ raw_ptr<MockQueryController> query_controller_; raw_ptr<contextual_search::ContextualSearchService> service_; raw_ptr<MockContextualSearchMetricsRecorder> metrics_recorder_; - base::test::ScopedFeatureList scoped_feature_list_; }; TEST_F(ContextualSearchboxHandlerTest, SessionStarted) { @@ -575,17 +570,6 @@ } TEST_F(ContextualSearchboxHandlerTest, SubmitQuery) { - // Wait until the state changes to kClusterInfoReceived. - base::RunLoop run_loop; - query_controller().set_on_query_controller_state_changed_callback( - base::BindLambdaForTesting( - [&](ComposeboxQueryController::QueryControllerState state) { - if (state == ComposeboxQueryController::QueryControllerState:: - kClusterInfoReceived) { - run_loop.Quit(); - } - })); - std::vector<SessionState> session_states; auto* metrics_recorder_ptr = GetMetricsRecorderPtr(); ASSERT_THAT(metrics_recorder_ptr, testing::NotNull()); @@ -615,7 +599,6 @@ .Times(0); handler().NotifySessionStarted(); - run_loop.Run(); SubmitQueryAndWaitForNavigation(); @@ -645,16 +628,6 @@ TEST_F(ContextualSearchboxHandlerTest, SubmitQuery_DelayUpload) { // Arrange - // Wait until the state changes to kClusterInfoReceived. - base::RunLoop run_loop; - query_controller().set_on_query_controller_state_changed_callback( - base::BindLambdaForTesting( - [&](ComposeboxQueryController::QueryControllerState state) { - if (state == ComposeboxQueryController::QueryControllerState:: - kClusterInfoReceived) { - run_loop.Quit(); - } - })); std::vector<SessionState> session_states; auto* metrics_recorder_ptr = GetMetricsRecorderPtr(); @@ -695,7 +668,6 @@ .Times(1); handler().NotifySessionStarted(); - run_loop.Run(); // Act SubmitQueryAndWaitForNavigation();
diff --git a/chrome/browser/ui/webui/searchbox/contextual_searchbox_test_utils.cc b/chrome/browser/ui/webui/searchbox/contextual_searchbox_test_utils.cc index 087f610..fa01baa 100644 --- a/chrome/browser/ui/webui/searchbox/contextual_searchbox_test_utils.cc +++ b/chrome/browser/ui/webui/searchbox/contextual_searchbox_test_utils.cc
@@ -111,6 +111,7 @@ mime_type = contextual_input->primary_content_type.value(); } AddFileInfoForTesting(file_token, mime_type); + TriggerFetchClusterInfo(); // Post a task to notify success asynchronously. This ensures that the // frontend receives the Mojo response containing the fileToken *before* the
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 78b2999..12936b3 100644 --- a/chrome/browser/ui/webui/searchbox/contextual_searchbox_test_utils.h +++ b/chrome/browser/ui/webui/searchbox/contextual_searchbox_test_utils.h
@@ -102,6 +102,10 @@ TestComposeboxQueryController::InitializeIfNeeded(); } + void TriggerFetchClusterInfoBase() { + TestComposeboxQueryController::TriggerFetchClusterInfo(); + } + void CreateSearchUrlBase(std::unique_ptr<CreateSearchUrlRequestInfo> search_url_request_info, base::OnceCallback<void(GURL)> callback) {
diff --git a/chrome/browser/ui/webui/searchbox/webui_omnibox_handler.cc b/chrome/browser/ui/webui/searchbox/webui_omnibox_handler.cc index ab0500af..6abc5792 100644 --- a/chrome/browser/ui/webui/searchbox/webui_omnibox_handler.cc +++ b/chrome/browser/ui/webui/searchbox/webui_omnibox_handler.cc
@@ -223,10 +223,6 @@ void WebuiOmniboxHandler::StepSelection( OmniboxPopupSelection::Direction direction, OmniboxPopupSelection::Step step) { - if (!IsRemoteBound()) { - return; - } - searchbox::mojom::SelectionStep mojom_step; switch (step) { case OmniboxPopupSelection::Step::kWholeLine: { @@ -253,18 +249,10 @@ void WebuiOmniboxHandler::OpenCurrentSelection( WindowOpenDisposition disposition) { - if (!IsRemoteBound()) { - return; - } - page_->OpenCurrentSelection(disposition); } void WebuiOmniboxHandler::SetAimButtonVisible(bool visible) { - if (!IsRemoteBound()) { - return; - } - page_->SetAimButtonVisible(visible); } @@ -309,11 +297,6 @@ // *every* keystroke in the Omnibox. void WebuiOmniboxHandler::OnStart(AutocompleteController* controller, const AutocompleteInput& input) { - // Ignore the call until the page remote is bound and ready to receive calls. - if (!IsRemoteBound()) { - return; - } - const AutocompleteProviderClient* client = autocomplete_controller()->autocomplete_provider_client(); // Check if there are zero suggest (either on NTP or on web) or the @@ -326,16 +309,12 @@ void WebuiOmniboxHandler::OnResultChanged(AutocompleteController* controller, bool default_match_changed) { - const bool ready = IsRemoteBound(); + // TODO: (crbug.com/506266490) - Clean up these metrics since it is no longer + // relevant to track after moving to factory pattern for searchbox::mojom. if (metrics_reporter_ && !metrics_reporter_->HasLocalMark("FirstAccess")) { metrics_reporter_->Mark("FirstAccess"); base::UmaHistogramBoolean( - "Omnibox.Popup.WebUI.PageRemoteIsBoundOnFirstCall", ready); - } - - // Ignore the call until the page remote is bound and ready to receive calls. - if (!ready) { - return; + "Omnibox.Popup.WebUI.PageRemoteIsBoundOnFirstCall", true); } if (metrics_reporter_ && !metrics_reporter_->HasLocalMark("ResultChanged")) { @@ -347,18 +326,6 @@ void WebuiOmniboxHandler::OnSelectionChanged( OmniboxPopupSelection old_selection, OmniboxPopupSelection selection) { - const bool ready = IsRemoteBound(); - if (metrics_reporter_ && !metrics_reporter_->HasLocalMark("FirstAccess")) { - metrics_reporter_->Mark("FirstAccess"); - base::UmaHistogramBoolean("Omnibox.Popup.WebUI.PageIsReadyOnFirstCall", - ready); - } - - // Ignore the call until the page remote is bound and ready to receive calls. - if (!ready) { - return; - } - page_->UpdateSelection( searchbox::mojom::OmniboxPopupSelection::New( old_selection.line, ConvertLineState(old_selection.state), @@ -369,11 +336,6 @@ } void WebuiOmniboxHandler::OnKeywordStateChanged(bool is_keyword_selected) { - // Ignore the call until the page remote is bound and ready to receive calls. - if (!IsRemoteBound()) { - return; - } - page_->SetKeywordSelected(is_keyword_selected); } @@ -455,11 +417,6 @@ } void WebuiOmniboxHandler::OnContentSharingPolicyChanged() { - // Ignore the call until the page remote is bound and ready to receive calls. - if (!IsRemoteBound()) { - return; - } - page_->UpdateContentSharingPolicy( contextual_search::ContextualSearchService::IsContextSharingEnabled( profile_->GetPrefs())); @@ -468,18 +425,14 @@ void WebuiOmniboxHandler::OnAimPopupEligibilityChanged() { InitializeInputStateModel(); - if (IsRemoteBound()) { - page_->UpdateAimPopupEligibility( - omnibox::IsAimPopupEnabled(profile_) && - profile_->GetPrefs()->GetBoolean(omnibox::kShowAiModeOmniboxButton)); - } + page_->UpdateAimPopupEligibility( + omnibox::IsAimPopupEnabled(profile_) && + profile_->GetPrefs()->GetBoolean(omnibox::kShowAiModeOmniboxButton)); } void WebuiOmniboxHandler::OnNavigationFinished( content::NavigationHandle* navigation_handle) { if (navigation_handle->HasCommitted() && navigation_handle->IsInMainFrame()) { - if (IsRemoteBound()) { - page_->OnTabStripChanged(); - } + page_->OnTabStripChanged(); } }
diff --git a/chrome/browser/webauthn/enclave_authenticator_browsertest.cc b/chrome/browser/webauthn/enclave_authenticator_browsertest.cc index 1e0131d..d658f8d 100644 --- a/chrome/browser/webauthn/enclave_authenticator_browsertest.cc +++ b/chrome/browser/webauthn/enclave_authenticator_browsertest.cc
@@ -18,6 +18,7 @@ #include "base/check.h" #include "base/check_op.h" #include "base/containers/span.h" +#include "base/containers/to_vector.h" #include "base/functional/bind.h" #include "base/functional/callback.h" #include "base/logging.h" @@ -4741,6 +4742,41 @@ testing::HasSubstr("\"largeBlob\": \"[redacted]\"")); } +// Regression test for crbug.com/505059790. +// Simulate MagicArch returning keys for the wrong user. This used to crash, now +// it should result in a GPM error. +IN_PROC_BROWSER_TEST_F(EnclaveAuthenticatorBrowserTest, + RecoverSecurityDomainGaiaMismatchedFailure) { + SetTrustedVaultRecoverable(); + EnableUVKeySupport(); + + content::WebContents* web_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + content::DOMMessageQueue message_queue(web_contents); + + content::ExecuteScriptAsync(web_contents, kMakeCredentialUvRequired); + delegate_observer()->WaitForUI(); + + model_observer()->SetStepToObserve( + AuthenticatorRequestDialogModel::Step::kGPMTrustThisComputerCreation); + model_observer()->WaitForStep(); + + model_observer()->SetStepToObserve( + AuthenticatorRequestDialogModel::Step::kGPMRecoverSecurityDomain); + dialog_model()->OnGPMTrustThisComputer(); + model_observer()->WaitForStep(); + + model_observer()->SetStepToObserve( + AuthenticatorRequestDialogModel::Step::kGPMError); + auto store_keys_lock = enclave_manager().GetStoreKeysLock(); + enclave_manager().StoreKeys( + GaiaId("mismatched_gaia_id"), + {trusted_vault::TrustedVaultKeyAndVersion( + base::ToVector(kSecurityDomainSecret), kSecretVersion)}, + std::nullopt); + model_observer()->WaitForStep(); +} + } // namespace #endif // !defined(MEMORY_SANITIZER)
diff --git a/chrome/browser/webauthn/enclave_manager.cc b/chrome/browser/webauthn/enclave_manager.cc index 900869c..2e3af0ce 100644 --- a/chrome/browser/webauthn/enclave_manager.cc +++ b/chrome/browser/webauthn/enclave_manager.cc
@@ -4008,7 +4008,7 @@ store_keys_count_++; for (Observer& observer : observer_list_) { - observer.OnKeysStored(); + observer.OnKeysStored(gaia_id); } }
diff --git a/chrome/browser/webauthn/enclave_manager_interface.h b/chrome/browser/webauthn/enclave_manager_interface.h index 4e9885d..58d6555 100644 --- a/chrome/browser/webauthn/enclave_manager_interface.h +++ b/chrome/browser/webauthn/enclave_manager_interface.h
@@ -11,6 +11,7 @@ #include "components/trusted_vault/trusted_vault_connection.h" class EnclaveManager; +class GaiaId; class EnclaveManagerInterface : public KeyedService { public: @@ -56,9 +57,11 @@ class Observer : public base::CheckedObserver { public: - // OnKeyStores is called when MagicArch provides keys to the EnclaveManager - // by calling `StoreKeys`. - virtual void OnKeysStored() {} + // `OnKeysStored` is called when MagicArch provides keys to the + // EnclaveManager by calling `StoreKeys`. `gaia_id` is the account + // identifier for the keys that were stored. Clients should verify this + // matches the account they expect. + virtual void OnKeysStored(const GaiaId& gaia_id) {} // `OnStateUpdated` is called from `EnclaveManager::Stopped()` - indicating // that the state machine reached its final state (so the state of the
diff --git a/chrome/browser/webauthn/enclave_manager_unittest.cc b/chrome/browser/webauthn/enclave_manager_unittest.cc index 27bd988..b5de420f 100644 --- a/chrome/browser/webauthn/enclave_manager_unittest.cc +++ b/chrome/browser/webauthn/enclave_manager_unittest.cc
@@ -313,7 +313,10 @@ return ret; } - void OnKeysStored() override { stored_count_++; } + void OnKeysStored(const GaiaId& gaia_id) override { + stored_count_++; + last_stored_gaia_id_ = gaia_id; + } void OnStateUpdated() override { notified_about_state_update_count_++; } void OnOutOfContextRecoveryCompletion( EnclaveManager::OutOfContextRecoveryOutcome outcome) override {} @@ -521,6 +524,7 @@ base::test::TaskEnvironment task_env_; unsigned stored_count_ = 0; + GaiaId last_stored_gaia_id_; unsigned notified_about_state_update_count_ = 0; const TempDir temp_dir_; const std::pair<base::Process, uint16_t> process_and_port_; @@ -575,6 +579,7 @@ ASSERT_TRUE(manager_.is_idle()); ASSERT_TRUE(manager_.has_pending_keys()); EXPECT_EQ(stored_count_, 1u); + EXPECT_EQ(last_stored_gaia_id_, gaia_id_); BoolFuture add_future; ASSERT_TRUE(manager_.AddDeviceToAccount( @@ -2170,6 +2175,7 @@ {trusted_vault::TrustedVaultKeyAndVersion(std::move(key), kSecretVersion)}, /*user_action_trigger=*/std::nullopt); + EXPECT_EQ(last_stored_gaia_id_, GaiaId("Not the primary account")); BoolFuture add_future; ASSERT_TRUE(manager_.AddDeviceToAccount(
diff --git a/chrome/browser/webauthn/gpm_enclave_controller.cc b/chrome/browser/webauthn/gpm_enclave_controller.cc index 30e24cd..4249c159 100644 --- a/chrome/browser/webauthn/gpm_enclave_controller.cc +++ b/chrome/browser/webauthn/gpm_enclave_controller.cc
@@ -770,7 +770,7 @@ } } -void GPMEnclaveController::OnKeysStored() { +void GPMEnclaveController::OnKeysStored(const GaiaId& gaia_id) { if (recovered_with_icloud_keychain_) { // iCloud keychain recovery. device::enclave::RecordEvent( @@ -787,7 +787,16 @@ // during a request at a different step on another tab. In case of // successful key retrieval in another tab, we conclude that the state of // the GPM Enclave Controller has become stale. - is_state_stale_ = true; + if (gaia_id == user_gaia_id_) { + is_state_stale_ = true; + } + return; + } + + if (gaia_id != user_gaia_id_) { + FIDO_LOG(ERROR) << "Keys stored for wrong account: " << gaia_id.ToString() + << ", expected: " << user_gaia_id_.ToString(); + OnEnclaveError(); return; }
diff --git a/chrome/browser/webauthn/gpm_enclave_controller.h b/chrome/browser/webauthn/gpm_enclave_controller.h index 3f9eeb01..f532e96 100644 --- a/chrome/browser/webauthn/gpm_enclave_controller.h +++ b/chrome/browser/webauthn/gpm_enclave_controller.h
@@ -240,7 +240,7 @@ void SetActive(EnclaveEnabledStatus enclave_enabled_status); // EnclaveManager::Observer: - void OnKeysStored() override; + void OnKeysStored(const GaiaId& gaia_id) override; void OnOutOfContextRecoveryCompletion( EnclaveManager::OutOfContextRecoveryOutcome outcome) override;
diff --git a/chrome/build/android-arm64.orderfile.txt b/chrome/build/android-arm64.orderfile.txt index 19789010..b52857f 100644 --- a/chrome/build/android-arm64.orderfile.txt +++ b/chrome/build/android-arm64.orderfile.txt
@@ -1 +1 @@ -jWIdkzb_3jrzvhc8W2L2ONDQi6jrtziYV-M226LX0BEC +nWIr0bHMzscc9AZaGNlEG1riBx92buOLkbZUEuqdcMUC
diff --git a/chrome/build/android-desktop-x64.pgo.txt b/chrome/build/android-desktop-x64.pgo.txt index 9a47e22..3bfd5dc 100644 --- a/chrome/build/android-desktop-x64.pgo.txt +++ b/chrome/build/android-desktop-x64.pgo.txt
@@ -1 +1 @@ -chrome-android-desktop-x64-main-1778068761-fd3825fb7c0f86de03ef1337d757e10ab4a54763-35ad87ab9022b5a221d5bd0bdf69171b24ba7ac2.profdata +chrome-android-desktop-x64-main-1778090318-601071ab2d6c1f42cc17f9729caf6f7cb4911285-178022ee00468618adbea61447948623999521e9.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt index 66eb3b1a..2b565d4 100644 --- a/chrome/build/mac-arm.pgo.txt +++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@ -chrome-mac-arm-main-1778082944-e270cd0856bccfb05873eb37813b976e806825ab-4d5927348adc85a0147377b6aeeae26136d33661.profdata +chrome-mac-arm-main-1778097520-0a43edc839c22432bd61c235c4a56edd4c9ea89c-8f93d740dd5c563fc7b2407adc40b3c043818765.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt index 64c51b3..1b88c9c 100644 --- a/chrome/build/mac.pgo.txt +++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@ -chrome-mac-main-1778068761-5d1653f044c9c3da44c06a80457d1eb66e5d5f8d-35ad87ab9022b5a221d5bd0bdf69171b24ba7ac2.profdata +chrome-mac-main-1778090318-b254dbea686aee318faac2e4069a27b26e5f6acd-178022ee00468618adbea61447948623999521e9.profdata
diff --git a/chrome/build/win-arm64.pgo.txt b/chrome/build/win-arm64.pgo.txt index 5319e3a..d9cde23c 100644 --- a/chrome/build/win-arm64.pgo.txt +++ b/chrome/build/win-arm64.pgo.txt
@@ -1 +1 @@ -chrome-win-arm64-main-1778045275-db0dd9cb07d498da5918d57ffab58c79cff59459-d08251e8b5287a0995aa47c33a982b860e8a6537.profdata +chrome-win-arm64-main-1778090318-ab3b5b38294f907cfaedb70082c2e3118304eadb-178022ee00468618adbea61447948623999521e9.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index e104248a..8cce878a 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-main-1778068761-acc5a4ba566b3d1915edc7fd65d38a66119fbd39-35ad87ab9022b5a221d5bd0bdf69171b24ba7ac2.profdata +chrome-win32-main-1778090318-30ef2bc2cad0204ead0069943678e7a90bc91536-178022ee00468618adbea61447948623999521e9.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index 0f80081..4f05299 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-main-1778068761-35c65ca4c15bd85b572525f40c249cd0964477f0-35ad87ab9022b5a221d5bd0bdf69171b24ba7ac2.profdata +chrome-win64-main-1778090318-23eed8cf437a5ca4df21f29eae20d8936b42b0da-178022ee00468618adbea61447948623999521e9.profdata
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc index 0996404d..0ddae44f 100644 --- a/chrome/common/chrome_features.cc +++ b/chrome/common/chrome_features.cc
@@ -207,6 +207,8 @@ #endif BASE_FEATURE(kGlicExperimentalTriggering, base::FEATURE_DISABLED_BY_DEFAULT); +BASE_FEATURE(kGlicExperimentalTriggeringOptInBypass, + base::FEATURE_DISABLED_BY_DEFAULT); const base::FeatureParam<base::TimeDelta> kGlicActorPageToolTimeout{ &kGlicActor, "glic-actor-page-tool-timeout", base::Seconds(30)};
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h index f80409e..a219ba4 100644 --- a/chrome/common/chrome_features.h +++ b/chrome/common/chrome_features.h
@@ -158,6 +158,8 @@ COMPONENT_EXPORT(CHROME_FEATURES) BASE_DECLARE_FEATURE(kGlicExperimentalTriggering); COMPONENT_EXPORT(CHROME_FEATURES) +BASE_DECLARE_FEATURE(kGlicExperimentalTriggeringOptInBypass); +COMPONENT_EXPORT(CHROME_FEATURES) extern const base::FeatureParam<base::TimeDelta> kGlicActorPageToolTimeout; COMPONENT_EXPORT(CHROME_FEATURES) extern const base::FeatureParam<base::TimeDelta> kGlicActorClickDelay;
diff --git a/chrome/renderer/safe_browsing/phishing_classifier_delegate_browsertest.cc b/chrome/renderer/safe_browsing/phishing_classifier_delegate_browsertest.cc index 7831741..6530ce0 100644 --- a/chrome/renderer/safe_browsing/phishing_classifier_delegate_browsertest.cc +++ b/chrome/renderer/safe_browsing/phishing_classifier_delegate_browsertest.cc
@@ -18,6 +18,7 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" #include "base/test/gmock_callback_support.h" +#include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" #include "chrome/test/base/chrome_render_view_test.h" #include "chrome/test/base/chrome_unit_test_suite.h" @@ -277,19 +278,21 @@ Mock::VerifyAndClearExpectations(classifier_); } - // Now load a new toplevel page, which should trigger another classification. + // Now load a new toplevel page, which is completely different to the browser + // side request URL. EXPECT_CALL(*classifier_, CancelPendingClassification()); GURL new_url("http://host2.com"); LoadHTMLWithUrlOverride("dummy2", new_url.spec().c_str()); Mock::VerifyAndClearExpectations(classifier_); - OnStartPhishingDetection(new_url); - { base::RunLoop run_loop; EXPECT_CALL(*classifier_, BeginClassification(_)) .WillOnce(base::test::RunOnceClosure(run_loop.QuitClosure())); delegate_->PageCaptured(false); + // Satisfy condition to start classification from both browser and renderer. + OnStartPhishingDetection(new_url); + delegate_->PageCaptured(false); run_loop.Run(); Mock::VerifyAndClearExpectations(classifier_); } @@ -768,6 +771,33 @@ EXPECT_CALL(*classifier_, CancelPendingClassification()); } +TEST_P(PhishingClassifierDelegateTest, + NewPageLoadWhileBrowserRequestWaitsForLoad) { + base::HistogramTester histograms; + SetScorer(/*model_version=*/1); + ASSERT_TRUE(classifier_->is_ready()); + GURL url("http://host.test/index.html"); + + // 1. Start phishing detection (browser request). + OnStartPhishingDetection(url); + + // 2. Navigate away before PageCaptured is called (renderer_layout_finished_ + // is false). Simulate navigation to a new page. + EXPECT_CALL(*classifier_, CancelPendingClassification()); + GURL new_url("http://host2.test"); + LoadHTMLWithUrlOverride("<html><body>new page</body></html>", + new_url.spec().c_str()); + + histograms.ExpectBucketCount( + "SBClientPhishing.Classifier.Event", + static_cast<int>(SBPhishingClassifierEvent:: + kNewPageLoadWhileBrowserRequestWaitsForLoad), + 1); + + // The delegate will cancel pending classification on destruction. + EXPECT_CALL(*classifier_, CancelPendingClassification()); +} + INSTANTIATE_TEST_SUITE_P(All, PhishingClassifierDelegateTest, ::testing::Values(-1.0, 0.0, 0.5));
diff --git a/chrome/test/data/webui/chromeos/boca_ui/BUILD.gn b/chrome/test/data/webui/chromeos/boca_ui/BUILD.gn index 78aff97..ac54cdf 100644 --- a/chrome/test/data/webui/chromeos/boca_ui/BUILD.gn +++ b/chrome/test/data/webui/chromeos/boca_ui/BUILD.gn
@@ -24,6 +24,7 @@ "consumer_main_page_test.ts", "feature_flag_test.ts", "producer_main_page_test.ts", + "receiver_test.ts", ] ts_definitions = []
diff --git a/chrome/test/data/webui/chromeos/boca_ui/boca_app_browsertest.cc b/chrome/test/data/webui/chromeos/boca_ui/boca_app_browsertest.cc index 17ba43b..ba3cfb1 100644 --- a/chrome/test/data/webui/chromeos/boca_ui/boca_app_browsertest.cc +++ b/chrome/test/data/webui/chromeos/boca_ui/boca_app_browsertest.cc
@@ -39,6 +39,10 @@ "mocha.run()"); } +IN_PROC_BROWSER_TEST_F(BocaAppBrowserProducerTest, TestReceiver) { + RunTestWithoutTestLoader("chromeos/boca_ui/receiver_test.js", "mocha.run()"); +} + class BocaAppBrowserConsumerTest : public WebUIMochaBrowserTest { public: BocaAppBrowserConsumerTest() {
diff --git a/chrome/test/data/webui/chromeos/boca_ui/client_delegate_impl_test.ts b/chrome/test/data/webui/chromeos/boca_ui/client_delegate_impl_test.ts index 9ae29bd..f48e75c 100644 --- a/chrome/test/data/webui/chromeos/boca_ui/client_delegate_impl_test.ts +++ b/chrome/test/data/webui/chromeos/boca_ui/client_delegate_impl_test.ts
@@ -2,14 +2,16 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import {UrlType} from 'chrome-untrusted://boca-app/app/boca_app.js'; import {ClientDelegateFactory, getNetworkInfoMojomToUI, getSessionConfigMojomToUI, getStudentActivityMojomToUI} from 'chrome-untrusted://boca-app/app/client_delegate.js'; import type {AddStudentsError, Assignment, BocaValidPref, CaptionConfig, Config, Course, CreateSessionError, EndViewScreenSessionError, Identity, OnTaskConfig, Permission, PermissionSetting, RemoveStudentError, RenotifyStudentError, SessionResult, SetViewScreenSessionActiveError, UpdateSessionError, ViewStudentScreenError, Window} from 'chrome-untrusted://boca-app/mojom/boca.mojom-webui.js'; -import {PageHandlerRemote, SubmitAccessCodeError} from 'chrome-untrusted://boca-app/mojom/boca.mojom-webui.js'; +import {PageHandlerRemote, SubmitAccessCodeError, UrlType as UrlTypeMojo} from 'chrome-untrusted://boca-app/mojom/boca.mojom-webui.js'; import type {TimeDelta} from 'chrome-untrusted://resources/mojo/mojo/public/mojom/base/time.mojom-webui.js'; import type {Value} from 'chrome-untrusted://resources/mojo/mojo/public/mojom/base/values.mojom-webui.js'; import {assertDeepEquals, assertTrue} from 'chrome-untrusted://webui-test/chai_assert.js'; class MockRemoteHandler extends PageHandlerRemote { + urlTypeMojo: UrlTypeMojo|null = null; override getWindowsTabsList(): Promise<{windowList: Window[]}> { return Promise.resolve({ windowList: [ @@ -21,19 +23,31 @@ title: 'title1', url: 'http://foo1', favicon: 'dataurl1', + urlType: null, }, { + id: null, title: 'title2', url: 'http://foo2', favicon: 'dataurl2', + urlType: null, + }, + { + id: 2, + title: 'Special Url', + url: 'http://special', + favicon: 'dataurl3', + urlType: this.urlTypeMojo, }, ], }, { tabList: [{ + id: null, title: 'title3', url: 'http://foo3', favicon: 'dataurl3', + urlType: null, }], }, ] as Window[], @@ -122,6 +136,7 @@ url: 'http://google.com/', title: 'google', favicon: 'data/image', + urlType: null, }, navigationType: 0, }, @@ -131,9 +146,20 @@ url: 'http://youtube.com/', title: 'youtube', favicon: 'data/image', + urlType: null, }, navigationType: 1, }, + { + tab: { + id: null, + url: 'http://specialurl.com/', + title: 'special url', + favicon: 'data/image', + urlType: this.urlTypeMojo, + }, + navigationType: 0, + }, ], }, captionConfig: { @@ -192,6 +218,7 @@ url: 'http://google.com/', title: 'google', favicon: 'data/image', + urlType: null, }, navigationType: 0, }, @@ -201,9 +228,20 @@ url: 'http://youtube.com/', title: 'youtube', favicon: 'data/image', + urlType: null, }, navigationType: 1, }, + { + tab: { + id: null, + url: 'http://specialurl.com/', + title: 'special url', + favicon: 'data/image', + urlType: this.urlTypeMojo, + }, + navigationType: 0, + }, ], }, captionConfig: { @@ -231,6 +269,7 @@ url: 'http://google.com/', title: 'google', favicon: 'data/image', + urlType: null, }, navigationType: 0, }, @@ -240,9 +279,20 @@ url: 'http://youtube.com/', title: 'youtube', favicon: 'data/image', + urlType: null, }, navigationType: 1, }, + { + tab: { + id: null, + url: 'http://specialurl.com/', + title: 'special url', + favicon: 'data/image', + urlType: this.urlTypeMojo, + }, + navigationType: 0, + }, ], }, config); @@ -364,51 +414,78 @@ suite('ClientDelegateTest', function() { let clientDelegateImpl: ClientDelegateFactory; + let remoteHandler: MockRemoteHandler; + const urlTypeTestCases = [ + { + name: 'Gemini Regular', + urlTypeMojo: UrlTypeMojo.kGeminiRegular, + urlTypeUi: UrlType.GEMINI_REGULAR, + }, + { + name: 'Gemini Guided Learning', + urlTypeMojo: UrlTypeMojo.kGeminiGuidedLearning, + urlTypeUi: UrlType.GEMINI_GUIDED_LEARNING, + }, + ]; setup(function() { - clientDelegateImpl = new ClientDelegateFactory(new MockRemoteHandler()); + remoteHandler = new MockRemoteHandler(); + clientDelegateImpl = new ClientDelegateFactory(remoteHandler); }); - test( - 'client delegate should properly translate mojom layer data for windows' + - 'list', - async () => { - const result = - await clientDelegateImpl.getInstance().getWindowsTabsList(); - assertDeepEquals( - [ - { - windowName: 'window1', - tabList: [ - { - id: 1, - title: 'title1', - url: 'http://foo1', - favicon: 'dataurl1', - }, - { - id: undefined, - title: 'title2', - url: 'http://foo2', - favicon: 'dataurl2', - }, - ], - }, - { - // Default window name should be empty - windowName: '', - tabList: [ - { - id: undefined, - title: 'title3', - url: 'http://foo3', - favicon: 'dataurl3', - }, - ], - }, - ], - result); - }); + urlTypeTestCases.forEach((testCase) => { + test( + `client delegate should properly translate mojom layer data for ` + + `windows list with urlType: ${testCase.name}`, + async () => { + remoteHandler.urlTypeMojo = testCase.urlTypeMojo; + const result = + await clientDelegateImpl.getInstance().getWindowsTabsList(); + assertDeepEquals( + [ + { + windowName: 'window1', + tabList: [ + { + id: 1, + title: 'title1', + url: 'http://foo1', + favicon: 'dataurl1', + urlType: undefined, + }, + { + id: undefined, + title: 'title2', + url: 'http://foo2', + favicon: 'dataurl2', + urlType: undefined, + }, + { + id: 2, + title: 'Special Url', + url: 'http://special', + favicon: 'dataurl3', + urlType: testCase.urlTypeUi, + }, + ], + }, + { + // Default window name should be empty + windowName: '', + tabList: [ + { + id: undefined, + title: 'title3', + url: 'http://foo3', + favicon: 'dataurl3', + urlType: undefined, + }, + ], + }, + ], + result); + }); + }); test( 'client delegate should properly translate mojom layer data for course' + @@ -471,83 +548,28 @@ result); }); - test( - 'client delegate should translate data for creating session', - async () => { - const result = await clientDelegateImpl.getInstance().createSession({ - sessionDurationInMinutes: 120, - students: [ - {id: '1', name: 'cat', email: 'cat@gmail.com', photoUrl: 'cdn1'}, - {id: '2', name: 'dog', email: 'dog@gmail.com', photoUrl: 'cdn2'}, - ], - studentsJoinViaCode: [], - teacher: undefined, - accessCode: undefined, - sessionStartTime: undefined, - onTaskConfig: { - isLocked: true, - isPaused: true, - tabs: [ - { - tab: { - title: 'google', - url: 'http://google.com/', - favicon: 'data/image', - }, - navigationType: 0, - }, - { - tab: { - title: 'youtube', - url: 'http://youtube.com/', - favicon: 'data/image', - }, - navigationType: 1, - }, - ], - }, - captionConfig: { - sessionCaptionEnabled: true, - localCaptionEnabled: true, - sessionTranslationEnabled: true, - }, - }); - assertDeepEquals(1, result); - }); - - test('client delegate should properly translate get session', async () => { - const result = await clientDelegateImpl.getInstance().getSession(); - assertDeepEquals( - { - sessionConfig: { - sessionDurationInMinutes: 2, - sessionStartTime: new Date(1000000), - teacher: { - id: '0', - name: 'teacher', - email: 'teacher@gmail.com', - photoUrl: 'cdn0', - }, + urlTypeTestCases.forEach((testCase) => { + test( + `client delegate should translate data for creating session with ` + + `urlType: ${testCase.name}`, + async () => { + remoteHandler.urlTypeMojo = testCase.urlTypeMojo; + const result = await clientDelegateImpl.getInstance().createSession({ + sessionDurationInMinutes: 120, students: [ {id: '1', name: 'cat', email: 'cat@gmail.com', photoUrl: 'cdn1'}, {id: '2', name: 'dog', email: 'dog@gmail.com', photoUrl: 'cdn2'}, ], - studentsJoinViaCode: [ - { - id: '3', - name: 'cat1', - email: 'cat1@gmail.com', - photoUrl: 'cdn3', - }, - ], - accessCode: 'testCode', + studentsJoinViaCode: [], + teacher: undefined, + accessCode: undefined, + sessionStartTime: undefined, onTaskConfig: { isLocked: true, isPaused: true, tabs: [ { tab: { - id: 1, title: 'google', url: 'http://google.com/', favicon: 'data/image', @@ -556,13 +578,21 @@ }, { tab: { - id: undefined, title: 'youtube', url: 'http://youtube.com/', favicon: 'data/image', }, navigationType: 1, }, + { + tab: { + url: 'http://specialurl.com/', + title: 'special url', + favicon: 'data/image', + urlType: testCase.urlTypeUi, + }, + navigationType: 0, + }, ], }, captionConfig: { @@ -570,10 +600,98 @@ localCaptionEnabled: true, sessionTranslationEnabled: true, }, - }, - activity: [], - }, - result); + }); + assertDeepEquals(1, result); + }); + }); + + urlTypeTestCases.forEach((testCase) => { + test( + `client delegate should properly translate get session with urlType: ${ + testCase.name}`, + async () => { + remoteHandler.urlTypeMojo = testCase.urlTypeMojo; + const result = await clientDelegateImpl.getInstance().getSession(); + assertDeepEquals( + { + sessionConfig: { + sessionDurationInMinutes: 2, + sessionStartTime: new Date(1000000), + teacher: { + id: '0', + name: 'teacher', + email: 'teacher@gmail.com', + photoUrl: 'cdn0', + }, + students: [ + { + id: '1', + name: 'cat', + email: 'cat@gmail.com', + photoUrl: 'cdn1', + }, + { + id: '2', + name: 'dog', + email: 'dog@gmail.com', + photoUrl: 'cdn2', + }, + ], + studentsJoinViaCode: [ + { + id: '3', + name: 'cat1', + email: 'cat1@gmail.com', + photoUrl: 'cdn3', + }, + ], + accessCode: 'testCode', + onTaskConfig: { + isLocked: true, + isPaused: true, + tabs: [ + { + tab: { + id: 1, + title: 'google', + url: 'http://google.com/', + favicon: 'data/image', + urlType: undefined, + }, + navigationType: 0, + }, + { + tab: { + id: undefined, + title: 'youtube', + url: 'http://youtube.com/', + favicon: 'data/image', + urlType: undefined, + }, + navigationType: 1, + }, + { + tab: { + id: undefined, + url: 'http://specialurl.com/', + title: 'special url', + favicon: 'data/image', + urlType: testCase.urlTypeUi, + }, + navigationType: 0, + }, + ], + }, + captionConfig: { + sessionCaptionEnabled: true, + localCaptionEnabled: true, + sessionTranslationEnabled: true, + }, + }, + activity: [], + }, + result); + }); }); test( @@ -629,34 +747,47 @@ result); }); - test( - 'client delegate should translate data for update on task config', - async () => { - const result = - await clientDelegateImpl.getInstance().updateOnTaskConfig({ - isLocked: true, - isPaused: true, - tabs: [ - { - tab: { - title: 'google', - url: 'http://google.com/', - favicon: 'data/image', + urlTypeTestCases.forEach((testCase) => { + test( + `client delegate should translate data for update on task config ` + + `with urlType: ${testCase.name}`, + async () => { + remoteHandler.urlTypeMojo = testCase.urlTypeMojo; + const result = + await clientDelegateImpl.getInstance().updateOnTaskConfig({ + isLocked: true, + isPaused: true, + tabs: [ + { + tab: { + title: 'google', + url: 'http://google.com/', + favicon: 'data/image', + }, + navigationType: 0, }, - navigationType: 0, - }, - { - tab: { - title: 'youtube', - url: 'http://youtube.com/', - favicon: 'data/image', + { + tab: { + title: 'youtube', + url: 'http://youtube.com/', + favicon: 'data/image', + }, + navigationType: 1, }, - navigationType: 1, - }, - ], - }); - assertTrue(result); - }); + { + tab: { + title: 'special url', + url: 'http://specialurl.com/', + favicon: 'data/image', + urlType: testCase.urlTypeUi, + }, + navigationType: 0, + }, + ], + }); + assertTrue(result); + }); + }); test('client delegate should translate data for caption config', async () => { const result = await clientDelegateImpl.getInstance().updateCaptionConfig({
diff --git a/chrome/test/data/webui/chromeos/boca_ui/receiver_test.ts b/chrome/test/data/webui/chromeos/boca_ui/receiver_test.ts new file mode 100644 index 0000000..74fd414a --- /dev/null +++ b/chrome/test/data/webui/chromeos/boca_ui/receiver_test.ts
@@ -0,0 +1,153 @@ +// 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 type {ClientApi, SessionConfig} from 'chrome-untrusted://boca-app/app/boca_app.js'; +import {UrlType} from 'chrome-untrusted://boca-app/app/boca_app.js'; +import {callbackRouter} from 'chrome-untrusted://boca-app/app/mojo_api_bootstrap.js'; +import type {ConfigResult} from 'chrome-untrusted://boca-app/mojom/boca.mojom-webui.js'; +import {UrlType as UrlTypeMojo} from 'chrome-untrusted://boca-app/mojom/boca.mojom-webui.js'; +import {assertDeepEquals} from 'chrome-untrusted://webui-test/chai_assert.js'; + +/** + * Waits for the boca-app element to be added to the DOM. + */ +async function waitForApp(): Promise<ClientApi> { + const app = document.querySelector('boca-app'); + if (app) { + return app as unknown as ClientApi; + } + return new Promise(resolve => { + const observer = new MutationObserver((_, obs) => { + const app = document.querySelector('boca-app'); + if (app) { + obs.disconnect(); + resolve(app as unknown as ClientApi); + } + }); + observer.observe(document.body, {childList: true}); + }); +} + +suite('ReceiverTest', function() { + let app: ClientApi; + + const urlTypeTestCases = [ + { + name: 'Gemini Regular', + urlTypeMojo: UrlTypeMojo.kGeminiRegular, + urlTypeUi: UrlType.GEMINI_REGULAR, + }, + { + name: 'Gemini Guided Learning', + urlTypeMojo: UrlTypeMojo.kGeminiGuidedLearning, + urlTypeUi: UrlType.GEMINI_GUIDED_LEARNING, + }, + ]; + + setup(async () => { + app = await waitForApp(); + }); + + urlTypeTestCases.forEach((testCase) => { + test( + `should correctly update session config with urlType: ${testCase.name}`, + async () => { + let actualConfig: SessionConfig|null = null; + app.onSessionConfigUpdated = (config: SessionConfig|null) => { + actualConfig = config; + }; + + const sessionConfig: ConfigResult = { + config: { + sessionDuration: { + microseconds: 120000000n, + }, + sessionStartTime: null, + teacher: null, + students: [], + studentsJoinViaCode: [], + accessCode: null, + captionConfig: { + sessionCaptionEnabled: true, + localCaptionEnabled: true, + sessionTranslationEnabled: true, + }, + onTaskConfig: { + isLocked: true, + isPaused: true, + tabs: [ + { + tab: { + id: 1, + title: 'special url', + url: 'http://specialurl.com/', + favicon: 'data/image', + urlType: testCase.urlTypeMojo, + }, + navigationType: 0, + }, + { + tab: { + id: 2, + title: 'regular url', + url: 'http://regularurl.com/', + favicon: 'data/image', + urlType: null, + }, + navigationType: 1, + }, + ], + }, + }, + }; + + const callbackRouterRemote = + callbackRouter.$.bindNewPipeAndPassRemote(); + callbackRouterRemote.onSessionConfigUpdated(sessionConfig); + await callbackRouterRemote.$.flushForTesting(); + + assertDeepEquals( + { + sessionDurationInMinutes: 2, + sessionStartTime: undefined, + teacher: undefined, + students: [], + studentsJoinViaCode: [], + accessCode: '', + captionConfig: { + sessionCaptionEnabled: true, + localCaptionEnabled: true, + sessionTranslationEnabled: true, + }, + onTaskConfig: { + isLocked: true, + isPaused: true, + tabs: [ + { + tab: { + id: 1, + title: 'special url', + url: 'http://specialurl.com/', + favicon: 'data/image', + urlType: testCase.urlTypeUi, + }, + navigationType: 0, + }, + { + tab: { + id: 2, + title: 'regular url', + url: 'http://regularurl.com/', + favicon: 'data/image', + urlType: undefined, + }, + navigationType: 1, + }, + ], + }, + }, + actualConfig); + }); + }); +});
diff --git a/chrome/test/data/webui/contextual_tasks/BUILD.gn b/chrome/test/data/webui/contextual_tasks/BUILD.gn index 6aa0f10..a869acc9 100644 --- a/chrome/test/data/webui/contextual_tasks/BUILD.gn +++ b/chrome/test/data/webui/contextual_tasks/BUILD.gn
@@ -57,7 +57,7 @@ ] ts_definitions = [ "//tools/typescript/definitions/chrome_event.d.ts", - "//tools/typescript/definitions/metrics_private.d.ts", + "//tools/typescript/definitions/chrome_histograms.d.ts", "//tools/typescript/definitions/web_request.d.ts", "//tools/typescript/definitions/webview_tag.d.ts", ]
diff --git a/chrome/test/data/webui/contextual_tasks/app_test.ts b/chrome/test/data/webui/contextual_tasks/app_test.ts index 14bcfbf..cd29051 100644 --- a/chrome/test/data/webui/contextual_tasks/app_test.ts +++ b/chrome/test/data/webui/contextual_tasks/app_test.ts
@@ -386,7 +386,7 @@ /*setupProxy=*/ undefined, /*waitForInitialLoadStart=*/ false); - assertTrue(appElement.hasAttribute('is-ai-page_')); + assertFalse(appElement.hasAttribute('is-ai-page_')); proxy.callbackRouterRemote.onAiPageStatusChanged(false); await proxy.callbackRouterRemote.$.flushForTesting();
diff --git a/chrome/test/data/webui/glic/browser_tests/glic_api_browsertest.ts b/chrome/test/data/webui/glic/browser_tests/glic_api_browsertest.ts index e7498c52..8e31858c 100644 --- a/chrome/test/data/webui/glic/browser_tests/glic_api_browsertest.ts +++ b/chrome/test/data/webui/glic/browser_tests/glic_api_browsertest.ts
@@ -893,48 +893,6 @@ assertEquals(screenshot.mimeType, 'image/jpeg'); } - async testDefaultTabContextApiIsUndefinedWhenFeatureDisabled() { - assertTrue(this.host.getDefaultTabContextPermissionState === undefined); - } - - async testGetDefaultTabContextPermissionState() { - assertDefined(this.host.getDefaultTabContextPermissionState); - const defaultTabContextState = - observeSequence(this.host.getDefaultTabContextPermissionState()); - assertTrue(await defaultTabContextState.next() as boolean); - await this.advanceToNextStep(); - assertFalse(await defaultTabContextState.next() as boolean); - } - - async testPinOnBind() { - assertDefined(this.host.getDefaultTabContextPermissionState); - const defaultTabContextState = - observeSequence(this.host.getDefaultTabContextPermissionState()); - assertTrue(await defaultTabContextState.next() as boolean); - assertDefined(this.host.getPinnedTabs); - const pinnedTabsUpdates = observeSequence(this.host.getPinnedTabs()); - - // The active tab should be automatically pinned on bind. - const pinnedTabs = - await pinnedTabsUpdates.waitFor(tabs => tabs.length === 1); - const activeTabId = this.getActiveTabId(); - assertEquals(pinnedTabs[0]!.tabId, activeTabId); - } - - async testNoPinOnBindWhenSettingOff() { - assertDefined(this.host.getPinnedTabs); - const pinnedTabsUpdates = observeSequence(this.host.getPinnedTabs()); - - // The initial value is an empty array. - const initialTabs = await pinnedTabsUpdates.next(); - assertEquals(0, initialTabs.length); - - // Wait briefly to ensure no unexpected updates arrive. - await sleep(200); - assertTrue( - pinnedTabsUpdates.isEmpty(), - 'Pinned tabs should remain empty when auto-pinning is disabled.'); - } async testGetOsHotkeyState() { assertDefined(this.host.getOsHotkeyState);
diff --git a/chrome/test/data/webui/glic/browser_tests/new_glic_api_browsertest.ts b/chrome/test/data/webui/glic/browser_tests/new_glic_api_browsertest.ts index 0ace17a..e60635e 100644 --- a/chrome/test/data/webui/glic/browser_tests/new_glic_api_browsertest.ts +++ b/chrome/test/data/webui/glic/browser_tests/new_glic_api_browsertest.ts
@@ -6,7 +6,7 @@ import type {AdditionalContext, ExperimentalTriggeringUpdate, GlicBrowserHost, GlicWebClient, InvokeOptions, Observable, Observable2, OpenPanelInfo, PageMetadata, PanelOpeningData, PanelState, TabData} from '/glic/glic_api/glic_api.js'; import {Subject} from '/glic/observable.js'; -import {ApiTestError, ApiTestFixtureBase, assertDefined, assertEquals, assertRejects, assertTrue, assertUndefined, checkDefined, mapObservable, observeSequence, runUntil, sleep, testMain, waitFor, WebClient} from './browser_test_base.js'; +import {ApiTestError, ApiTestFixtureBase, assertDefined, assertEquals, assertFalse, assertRejects, assertTrue, assertUndefined, checkDefined, mapObservable, observeSequence, runUntil, sleep, testMain, waitFor, WebClient} from './browser_test_base.js'; class ApiTests extends ApiTestFixtureBase { @@ -18,6 +18,52 @@ async testReloadWebUi() {} + async testDefaultTabContextApiIsUndefinedWhenFeatureDisabled() { + assertTrue(this.host.getDefaultTabContextPermissionState === undefined); + } + + async testGetDefaultTabContextPermissionState() { + assertDefined(this.host.getDefaultTabContextPermissionState); + const defaultTabContextState = + observeSequence(this.host.getDefaultTabContextPermissionState()); + assertTrue(await defaultTabContextState.next() as boolean); + await this.advanceToNextStep(); + assertFalse(await defaultTabContextState.next() as boolean); + } + + async testPinOnBind() { + assertDefined(this.host.getDefaultTabContextPermissionState); + assertDefined(this.host.getFocusedTabStateV2); + const defaultTabContextState = + observeSequence(this.host.getDefaultTabContextPermissionState()); + assertTrue(await defaultTabContextState.next() as boolean); + assertDefined(this.host.getPinnedTabs); + const pinnedTabsUpdates = observeSequence(this.host.getPinnedTabs()); + + // The active tab should be automatically pinned on bind. + const pinnedTabs = + await pinnedTabsUpdates.waitFor(tabs => tabs.length === 1); + const focus = + await observeSequence(this.host.getFocusedTabStateV2()).next(); + const activeTabId = checkDefined(focus.hasFocus?.tabData.tabId); + assertEquals(pinnedTabs[0]!.tabId, activeTabId); + } + + async testNoPinOnBindWhenSettingOff() { + assertDefined(this.host.getPinnedTabs); + const pinnedTabsUpdates = observeSequence(this.host.getPinnedTabs()); + + // The initial value is an empty array. + const initialTabs = await pinnedTabsUpdates.next(); + assertEquals(0, initialTabs.length); + + // Wait briefly to ensure no unexpected updates arrive. + await sleep(200); + assertTrue( + pinnedTabsUpdates.isEmpty(), + 'Pinned tabs should remain empty when auto-pinning is disabled.'); + } + async testInvocationSource() { const expectedSource = this.testParams as number; await observeSequence(this.client.panelOpenData)
diff --git a/chrome/test/data/webui/settings/settings_browsertest.cc b/chrome/test/data/webui/settings/settings_browsertest.cc index 4d08a41..0ecb239d 100644 --- a/chrome/test/data/webui/settings/settings_browsertest.cc +++ b/chrome/test/data/webui/settings/settings_browsertest.cc
@@ -1967,7 +1967,8 @@ // Disabling on debug due to flaky timeout on Win7 Tests (dbg)(1) bot. // https://crbug.com/41378604 - later for other platforms in crbug.com/40106090. -#if !defined(NDEBUG) +// TODO(https://crbug.com/510377224): Re-enable test on windows +#if !defined(NDEBUG) || BUILDFLAG(IS_WIN) #define MAYBE_SiteDetails DISABLED_SiteDetails #else #define MAYBE_SiteDetails SiteDetails
diff --git a/chrome/test/interaction/interactive_browser_test_interactive_uitest.cc b/chrome/test/interaction/interactive_browser_test_interactive_uitest.cc index 647b1fb..bbc32aec 100644 --- a/chrome/test/interaction/interactive_browser_test_interactive_uitest.cc +++ b/chrome/test/interaction/interactive_browser_test_interactive_uitest.cc
@@ -745,9 +745,7 @@ auto bubble_view = std::make_unique<HoverDetectionBubbleView>(anchor_view); bubble_view_ = bubble_view.get(); bubble_widget_ = - base::WrapUnique(views::BubbleDialogDelegate::CreateBubbleDeprecated( - std::move(bubble_view), - views::Widget::InitParams::CLIENT_OWNS_WIDGET)); + views::BubbleDialogDelegate::CreateBubble(std::move(bubble_view)); bubble_widget_->Show(); bubble_view_->SizeToContents(); }
diff --git a/chromecast/browser/cast_web_view_default.cc b/chromecast/browser/cast_web_view_default.cc index 7e1601b4..e3cdc0da 100644 --- a/chromecast/browser/cast_web_view_default.cc +++ b/chromecast/browser/cast_web_view_default.cc
@@ -175,8 +175,9 @@ DCHECK_EQ(source, web_contents_.get()); // We don't want to create another web_contents. Load url only when source is // specified. - auto navigation_handle = source->GetController().LoadURL( - params.url, params.referrer, params.transition, params.extra_headers); + content::NavigationController::LoadURLParams load_params(params); + auto navigation_handle = + source->GetController().LoadURLWithParams(load_params); if (navigation_handle_callback && navigation_handle) { std::move(navigation_handle_callback).Run(*navigation_handle);
diff --git a/chromecast/device/bluetooth/le/remote_device_impl.cc b/chromecast/device/bluetooth/le/remote_device_impl.cc index caa8be1..570c7cee 100644 --- a/chromecast/device/bluetooth/le/remote_device_impl.cc +++ b/chromecast/device/bluetooth/le/remote_device_impl.cc
@@ -499,6 +499,12 @@ const std::vector<bluetooth_v2_shlib::Gatt::Service>& services) { DCHECK(io_task_runner_->BelongsToCurrentThread()); for (const auto& service : services) { + auto it = uuid_to_service_.find(service.uuid); + if (it != uuid_to_service_.end()) { + for (auto& characteristic : it->second->GetCharacteristics()) { + handle_to_characteristic_.erase(characteristic->handle()); + } + } uuid_to_service_[service.uuid] = new RemoteServiceImpl( this, gatt_client_manager_, service, io_task_runner_); }
diff --git a/chromecast/media/audio/interleaved_channel_mixer.cc b/chromecast/media/audio/interleaved_channel_mixer.cc index 5f58c972..637d50c 100644 --- a/chromecast/media/audio/interleaved_channel_mixer.cc +++ b/chromecast/media/audio/interleaved_channel_mixer.cc
@@ -22,7 +22,8 @@ output_layout_(output_layout), output_channel_count_(output_channel_count), max_frames_(max_frames) { - if (input_layout_ == output_layout_) { + if (input_layout_ == output_layout_ && + input_channel_count_ == output_channel_count_) { return; } @@ -44,7 +45,8 @@ InterleavedChannelMixer::~InterleavedChannelMixer() = default; float* InterleavedChannelMixer::Transform(const float* input, int num_frames) { - if (input_layout_ == output_layout_) { + if (input_layout_ == output_layout_ && + input_channel_count_ == output_channel_count_) { return const_cast<float*>(input); }
diff --git a/chromecast/media/cma/backend/mixer/mixer_input_connection.cc b/chromecast/media/cma/backend/mixer/mixer_input_connection.cc index 17637e8..062f3677 100644 --- a/chromecast/media/cma/backend/mixer/mixer_input_connection.cc +++ b/chromecast/media/cma/backend/mixer/mixer_input_connection.cc
@@ -17,6 +17,7 @@ #include "base/functional/bind.h" #include "base/location.h" #include "base/logging.h" +#include "base/numerics/checked_math.h" #include "base/task/sequenced_task_runner.h" #include "base/task/single_thread_task_runner.h" #include "base/time/time.h" @@ -421,6 +422,18 @@ DCHECK(socket_); CHECK_GT(num_channels_, 0); CHECK_GT(input_samples_per_second_, 0); + if (channel_layout_ != ::media::CHANNEL_LAYOUT_DISCRETE && + ::media::ChannelLayoutToChannelCount(channel_layout_) != num_channels_) { + LOG(ERROR) << "Invalid channel layout/count: " << channel_layout_ << " / " + << num_channels_; + // Setting state_ to kRemoved or setting a flag might be needed. + // Instead we can just CHECK, but it might be untrusted renderer input. + // However, since it's a constructor, we can just let it fail gracefully + // later or here we just set a flag. Or we can just CHECK to fail safe if + // the renderer is compromised anyway. + CHECK_EQ(::media::ChannelLayoutToChannelCount(channel_layout_), + num_channels_); + } DCHECK_LE(start_threshold_frames_, max_queued_frames_); socket_->SetDelegate(this); @@ -449,8 +462,17 @@ DCHECK_GT(frame_count, 0); buffer_pool_frames_ = frame_count; - int converted_buffer_size = - kAudioMessageHeaderSize + num_channels_ * sizeof(float) * frame_count; + base::CheckedNumeric<int> size(frame_count); + size *= sizeof(float); + size *= num_channels_; + size += kAudioMessageHeaderSize; + + if (!size.IsValid()) { + LOG(ERROR) << "Buffer size is invalid."; + OnConnectionError(); + return; + } + int converted_buffer_size = size.ValueOrDie(); buffer_pool_ = base::MakeRefCounted<IOBufferPool>( converted_buffer_size, std::numeric_limits<size_t>::max(), true /* threadsafe */);
diff --git a/chromeos/ash/components/boca/session_api/constants.h b/chromeos/ash/components/boca/session_api/constants.h index 6353368..75f7fff3 100644 --- a/chromeos/ash/components/boca/session_api/constants.h +++ b/chromeos/ash/components/boca/session_api/constants.h
@@ -99,6 +99,7 @@ inline constexpr char kUrl[] = "url"; inline constexpr char kTitle[] = "title"; inline constexpr char kFavIcon[] = "faviconUrl"; +inline constexpr char kUrlType[] = "urlType"; inline constexpr char kContentConfigs[] = "contentConfigs"; inline constexpr char kActiveBundle[] = "activeBundle"; inline constexpr char kLocked[] = "locked";
diff --git a/chromeos/ash/components/boca/session_api/create_session_request_unittest.cc b/chromeos/ash/components/boca/session_api/create_session_request_unittest.cc index 8fc5b512..fb6f63f 100644 --- a/chromeos/ash/components/boca/session_api/create_session_request_unittest.cc +++ b/chromeos/ash/components/boca/session_api/create_session_request_unittest.cc
@@ -8,6 +8,7 @@ #include <string_view> #include "base/functional/bind.h" +#include "base/json/json_reader.h" #include "base/test/task_environment.h" #include "base/test/test_future.h" #include "base/time/time.h" @@ -136,8 +137,33 @@ MockRequestHandler& request_handler() { return request_handler_; } google_apis::RequestSender* request_sender() { return request_sender_.get(); } + void ExpectSuccessfulRequest(net::test_server::HttpRequest* http_request) { + EXPECT_CALL(request_handler(), HandleRequest(_)) + .WillOnce( + DoAll(SaveArg<0>(http_request), + Return(MockRequestHandler::CreateSuccessfulResponse()))); + } + + std::unique_ptr<CreateSessionRequest> CreateRequest( + CreateSessionCallback callback, + std::optional<::boca::UserIdentity> teacher = std::nullopt) { + ::boca::UserIdentity default_teacher; + default_teacher.set_gaia_id("1"); + ::boca::UserIdentity actual_teacher = teacher.value_or(default_teacher); + base::TimeDelta session_duration = base::Seconds(120); + auto request = std::make_unique<CreateSessionRequest>( + request_sender(), "https://test", actual_teacher, session_duration, + ::boca::Session::SessionState::Session_SessionState_ACTIVE, + std::move(callback)); + request->OverrideURLForTesting(test_server_.base_url().spec()); + return request; + } + protected: - // net::test_server::HttpRequest http_request; + using CreateSessionResult = + base::expected<std::unique_ptr<::boca::Session>, + std::pair<google_apis::ApiErrorCode, std::string>>; + net::EmbeddedTestServer test_server_; private: @@ -145,33 +171,20 @@ base::test::TaskEnvironment::MainThreadType::IO}; std::unique_ptr<google_apis::RequestSender> request_sender_; testing::StrictMock<MockRequestHandler> request_handler_; - std::unique_ptr<GaiaUrlsOverriderForTesting> urls_overrider_; scoped_refptr<network::TestSharedURLLoaderFactory> test_shared_loader_factory_; }; TEST_F(SessionApiRequestsTest, CreateSessionWithFullInputAndSucceed) { net::test_server::HttpRequest http_request; - EXPECT_CALL(request_handler(), HandleRequest(_)) - .WillOnce(DoAll(SaveArg<0>(&http_request), - Return(MockRequestHandler::CreateSuccessfulResponse()))); + ExpectSuccessfulRequest(&http_request); ::boca::UserIdentity teacher; teacher.set_gaia_id("1"); teacher.set_email("teacher@gmail.com"); teacher.set_full_name("teacher"); - base::TimeDelta session_duration = base::Seconds(120); - base::test::TestFuture< - base::expected<std::unique_ptr<::boca::Session>, - std::pair<google_apis::ApiErrorCode, std::string>>> - future; + base::test::TestFuture<CreateSessionResult> future; - std::unique_ptr<CreateSessionRequest> request = - std::make_unique<CreateSessionRequest>( - request_sender(), "https://test", teacher, session_duration, - ::boca::Session::SessionState::Session_SessionState_ACTIVE, - future.GetCallback()); - - request->OverrideURLForTesting(test_server_.base_url().spec()); + auto request = CreateRequest(future.GetCallback(), teacher); auto roster = std::make_unique<::boca::Roster>(); auto* student_groups = roster->mutable_student_groups()->Add(); @@ -258,27 +271,10 @@ TEST_F(SessionApiRequestsTest, CreateSessionWithCriticalInputAndSucceed) { net::test_server::HttpRequest http_request; - EXPECT_CALL(request_handler(), HandleRequest(_)) - .WillOnce(DoAll(SaveArg<0>(&http_request), - Return(MockRequestHandler::CreateSuccessfulResponse()))); + ExpectSuccessfulRequest(&http_request); + base::test::TestFuture<CreateSessionResult> future; - GaiaId gaia_id("1"); - base::TimeDelta session_duration = base::Seconds(120); - - base::test::TestFuture< - base::expected<std::unique_ptr<::boca::Session>, - std::pair<google_apis::ApiErrorCode, std::string>>> - future; - - ::boca::UserIdentity teacher; - teacher.set_gaia_id("1"); - std::unique_ptr<CreateSessionRequest> request = - std::make_unique<CreateSessionRequest>( - request_sender(), "https://test", teacher, session_duration, - ::boca::Session::SessionState::Session_SessionState_ACTIVE, - future.GetCallback()); - - request->OverrideURLForTesting(test_server_.base_url().spec()); + auto request = CreateRequest(future.GetCallback()); request_sender()->StartRequestWithAuthRetry(std::move(request)); @@ -303,22 +299,9 @@ .WillOnce(DoAll(SaveArg<0>(&http_request), Return(MockRequestHandler::CreateFailedResponse()))); - GaiaId gaia_id("1"); - base::TimeDelta session_duration = base::Seconds(120); + base::test::TestFuture<CreateSessionResult> future; - base::test::TestFuture< - base::expected<std::unique_ptr<::boca::Session>, - std::pair<google_apis::ApiErrorCode, std::string>>> - future; - ::boca::UserIdentity teacher; - teacher.set_gaia_id("1"); - std::unique_ptr<CreateSessionRequest> request = - std::make_unique<CreateSessionRequest>( - request_sender(), "https://test", teacher, session_duration, - ::boca::Session::SessionState::Session_SessionState_ACTIVE, - future.GetCallback()); - - request->OverrideURLForTesting(test_server_.base_url().spec()); + auto request = CreateRequest(future.GetCallback()); request_sender()->StartRequestWithAuthRetry(std::move(request)); @@ -345,22 +328,9 @@ DoAll(SaveArg<0>(&http_request), Return(MockRequestHandler::CreateMaxStudentsFailedResponse()))); - GaiaId gaia_id("1"); - base::TimeDelta session_duration = base::Seconds(120); + base::test::TestFuture<CreateSessionResult> future; - base::test::TestFuture< - base::expected<std::unique_ptr<::boca::Session>, - std::pair<google_apis::ApiErrorCode, std::string>>> - future; - ::boca::UserIdentity teacher; - teacher.set_gaia_id("1"); - std::unique_ptr<CreateSessionRequest> request = - std::make_unique<CreateSessionRequest>( - request_sender(), "https://test", teacher, session_duration, - ::boca::Session::SessionState::Session_SessionState_ACTIVE, - future.GetCallback()); - - request->OverrideURLForTesting(test_server_.base_url().spec()); + auto request = CreateRequest(future.GetCallback()); request_sender()->StartRequestWithAuthRetry(std::move(request)); @@ -372,4 +342,71 @@ EXPECT_EQ(kMaxStudentsExceededErrorMessage, error_msg); } +struct CreateSessionUrlTypeTestParam { + std::string test_name; + ::boca::UrlType url_type; +}; + +class CreateSessionUrlTypeTest + : public SessionApiRequestsTest, + public testing::WithParamInterface<CreateSessionUrlTypeTestParam> {}; + +TEST_P(CreateSessionUrlTypeTest, CreateSessionWithUrlTypeAndSucceed) { + net::test_server::HttpRequest http_request; + ExpectSuccessfulRequest(&http_request); + base::test::TestFuture<CreateSessionResult> future; + + auto request = CreateRequest(future.GetCallback()); + + auto on_task_config = std::make_unique<::boca::OnTaskConfig>(); + auto* active_bundle = on_task_config->mutable_active_bundle(); + active_bundle->set_locked(true); + + auto* content_config_1 = active_bundle->mutable_content_configs()->Add(); + content_config_1->set_title("google"); + content_config_1->set_url("https://google.com"); + content_config_1->set_favicon_url("data:image/123"); + content_config_1->mutable_locked_navigation_options()->set_navigation_type( + ::boca::LockedNavigationOptions_NavigationType:: + LockedNavigationOptions_NavigationType_OPEN_NAVIGATION); + + auto* content_config_2 = active_bundle->mutable_content_configs()->Add(); + content_config_2->set_title("special"); + content_config_2->set_url("https://specialurl.com"); + content_config_2->set_favicon_url("data:image/123"); + content_config_2->mutable_locked_navigation_options()->set_navigation_type( + ::boca::LockedNavigationOptions_NavigationType:: + LockedNavigationOptions_NavigationType_BLOCK_NAVIGATION); + content_config_2->set_url_type(GetParam().url_type); + + request->set_on_task_config(std::move(on_task_config)); + + request_sender()->StartRequestWithAuthRetry(std::move(request)); + + ASSERT_TRUE(future.Wait()); + std::optional<base::Value> actual_root = + base::JSONReader::Read(http_request.content, base::JSON_PARSE_RFC); + ASSERT_TRUE(actual_root.has_value() && actual_root->is_dict()); + + auto* content_configs = actual_root->GetDict().FindListByDottedPath( + "studentGroupConfigs.main.onTaskConfig.activeBundle.contentConfigs"); + ASSERT_TRUE(content_configs); + ASSERT_EQ(content_configs->size(), 2u); + + auto url_type_val = (*content_configs)[1].GetIfDict()->FindInt("urlType"); + ASSERT_TRUE(url_type_val.has_value()); + EXPECT_EQ(url_type_val.value(), GetParam().url_type); +} + +INSTANTIATE_TEST_SUITE_P( + CreateSessionUrlTypeTests, + CreateSessionUrlTypeTest, + testing::Values( + CreateSessionUrlTypeTestParam{"GeminiRegular", + ::boca::URL_TYPE_GEMINI_REGULAR}, + CreateSessionUrlTypeTestParam{"GeminiGuidedLearning", + ::boca::URL_TYPE_GEMINI_GUIDED_LEARNING}), + [](const testing::TestParamInfo<CreateSessionUrlTypeTest::ParamType>& + info) { return info.param.test_name; }); + } // namespace ash::boca
diff --git a/chromeos/ash/components/boca/session_api/session_parser.cc b/chromeos/ash/components/boca/session_api/session_parser.cc index 724402e..af9e5c6 100644 --- a/chromeos/ash/components/boca/session_api/session_parser.cc +++ b/chromeos/ash/components/boca/session_api/session_parser.cc
@@ -6,6 +6,7 @@ #include "ash/constants/ash_features.h" #include "base/strings/string_number_conversions.h" +#include "chromeos/ash/components/boca/proto/bundle.pb.h" #include "chromeos/ash/components/boca/proto/session.pb.h" #include "chromeos/ash/components/boca/session_api/constants.h" #include "chromeos/ash/components/boca/session_api/json_proto_converters.h" @@ -483,6 +484,9 @@ item.Set(kUrl, content.url()); item.Set(kTitle, content.title()); item.Set(kFavIcon, content.favicon_url()); + if (content.url_type() != ::boca::URL_TYPE_UNSPECIFIED) { + item.Set(kUrlType, content.url_type()); + } if (content.has_locked_navigation_options()) { base::DictValue navigation_type; navigation_type.Set(
diff --git a/chromeos/ash/components/boca/session_api/update_session_config_request_unittest.cc b/chromeos/ash/components/boca/session_api/update_session_config_request_unittest.cc index b4006086..4e36ec04 100644 --- a/chromeos/ash/components/boca/session_api/update_session_config_request_unittest.cc +++ b/chromeos/ash/components/boca/session_api/update_session_config_request_unittest.cc
@@ -94,6 +94,25 @@ MockRequestHandler& request_handler() { return request_handler_; } google_apis::RequestSender* request_sender() { return request_sender_.get(); } + void ExpectSuccessfulRequest(net::test_server::HttpRequest* http_request) { + EXPECT_CALL(request_handler(), HandleRequest(_)) + .WillOnce( + DoAll(SaveArg<0>(http_request), + Return(MockRequestHandler::CreateSuccessfulResponse()))); + } + + std::unique_ptr<UpdateSessionConfigRequest> CreateRequest( + UpdateSessionConfigCallback callback) { + ::boca::UserIdentity teacher; + teacher.set_gaia_id("1"); + const char session_id[] = "sessionId"; + auto request = std::make_unique<UpdateSessionConfigRequest>( + request_sender(), "https://test", teacher, session_id, + std::move(callback)); + request->OverrideURLForTesting(test_server_.base_url().spec()); + return request; + } + protected: // net::test_server::HttpRequest http_request; net::EmbeddedTestServer test_server_; @@ -103,7 +122,6 @@ base::test::TaskEnvironment::MainThreadType::IO}; std::unique_ptr<google_apis::RequestSender> request_sender_; testing::StrictMock<MockRequestHandler> request_handler_; - std::unique_ptr<GaiaUrlsOverriderForTesting> urls_overrider_; scoped_refptr<network::TestSharedURLLoaderFactory> test_shared_loader_factory_; }; @@ -111,21 +129,11 @@ TEST_F(UpdateSessionConfigTest, UpdateSessionConfigWithBothOnTaskAndCaptionConfigAndSucceed) { net::test_server::HttpRequest http_request; - EXPECT_CALL(request_handler(), HandleRequest(_)) - .WillOnce(DoAll(SaveArg<0>(&http_request), - Return(MockRequestHandler::CreateSuccessfulResponse()))); - ::boca::UserIdentity teacher; - teacher.set_gaia_id("1"); - const char session_id[] = "sessionId"; + ExpectSuccessfulRequest(&http_request); base::test::TestFuture<base::expected<bool, google_apis::ApiErrorCode>> future; - std::unique_ptr<UpdateSessionConfigRequest> request = - std::make_unique<UpdateSessionConfigRequest>( - request_sender(), "https://test", teacher, session_id, - future.GetCallback()); - - request->OverrideURLForTesting(test_server_.base_url().spec()); + auto request = CreateRequest(future.GetCallback()); ::boca::OnTaskConfig on_task_config; auto* active_bundle = on_task_config.mutable_active_bundle(); @@ -216,21 +224,11 @@ TEST_F(UpdateSessionConfigTest, UpdateSessionConfigWithOnTaskConfigAndSucceed) { net::test_server::HttpRequest http_request; - EXPECT_CALL(request_handler(), HandleRequest(_)) - .WillOnce(DoAll(SaveArg<0>(&http_request), - Return(MockRequestHandler::CreateSuccessfulResponse()))); - ::boca::UserIdentity teacher; - teacher.set_gaia_id("1"); - const char session_id[] = "sessionId"; + ExpectSuccessfulRequest(&http_request); base::test::TestFuture<base::expected<bool, google_apis::ApiErrorCode>> future; - std::unique_ptr<UpdateSessionConfigRequest> request = - std::make_unique<UpdateSessionConfigRequest>( - request_sender(), "https://test", teacher, session_id, - future.GetCallback()); - - request->OverrideURLForTesting(test_server_.base_url().spec()); + auto request = CreateRequest(future.GetCallback()); ::boca::OnTaskConfig on_task_config; auto* active_bundle = on_task_config.mutable_active_bundle(); @@ -313,21 +311,11 @@ TEST_F(UpdateSessionConfigTest, UpdateSessionConfigWithCaptionConfigAndSucceed) { net::test_server::HttpRequest http_request; - EXPECT_CALL(request_handler(), HandleRequest(_)) - .WillOnce(DoAll(SaveArg<0>(&http_request), - Return(MockRequestHandler::CreateSuccessfulResponse()))); - ::boca::UserIdentity teacher; - teacher.set_gaia_id("1"); - const char session_id[] = "sessionId"; + ExpectSuccessfulRequest(&http_request); base::test::TestFuture<base::expected<bool, google_apis::ApiErrorCode>> future; - std::unique_ptr<UpdateSessionConfigRequest> request = - std::make_unique<UpdateSessionConfigRequest>( - request_sender(), "https://test", teacher, session_id, - future.GetCallback()); - - request->OverrideURLForTesting(test_server_.base_url().spec()); + auto request = CreateRequest(future.GetCallback()); ::boca::CaptionsConfig captions_config; captions_config.set_captions_enabled(true); @@ -372,17 +360,10 @@ TEST_F(UpdateSessionConfigTest, UpdateSessionConfigWithNoConfigFail) { net::test_server::HttpRequest http_request; - ::boca::UserIdentity teacher; - teacher.set_gaia_id("1"); - const char session_id[] = "sessionId"; base::test::TestFuture<base::expected<bool, google_apis::ApiErrorCode>> future; - std::unique_ptr<UpdateSessionConfigRequest> request = - std::make_unique<UpdateSessionConfigRequest>( - request_sender(), "https://test", teacher, session_id, - future.GetCallback()); - request->OverrideURLForTesting(test_server_.base_url().spec()); + auto request = CreateRequest(future.GetCallback()); request_sender()->StartRequestWithAuthRetry(std::move(request)); ASSERT_TRUE(future.Wait()); @@ -390,4 +371,75 @@ EXPECT_TRUE(result.error()); } +struct UpdateSessionConfigUrlTypeTestParam { + std::string test_name; + ::boca::UrlType url_type; +}; + +class UpdateSessionConfigUrlTypeTest + : public UpdateSessionConfigTest, + public testing::WithParamInterface<UpdateSessionConfigUrlTypeTestParam> { +}; + +TEST_P(UpdateSessionConfigUrlTypeTest, + UpdateSessionConfigWithUrlTypeAndSucceed) { + net::test_server::HttpRequest http_request; + ExpectSuccessfulRequest(&http_request); + base::test::TestFuture<base::expected<bool, google_apis::ApiErrorCode>> + future; + + auto request = CreateRequest(future.GetCallback()); + + ::boca::OnTaskConfig on_task_config; + auto* active_bundle = on_task_config.mutable_active_bundle(); + active_bundle->set_locked(true); + + auto* content_config_1 = active_bundle->mutable_content_configs()->Add(); + content_config_1->set_title("google"); + content_config_1->set_url("https://google.com"); + content_config_1->set_favicon_url("data:image/123"); + content_config_1->mutable_locked_navigation_options()->set_navigation_type( + ::boca::LockedNavigationOptions_NavigationType:: + LockedNavigationOptions_NavigationType_OPEN_NAVIGATION); + + auto* content_config_2 = active_bundle->mutable_content_configs()->Add(); + content_config_2->set_title("special"); + content_config_2->set_url("https://specialurl.com"); + content_config_2->set_favicon_url("data:image/123"); + content_config_2->mutable_locked_navigation_options()->set_navigation_type( + ::boca::LockedNavigationOptions_NavigationType:: + LockedNavigationOptions_NavigationType_BLOCK_NAVIGATION); + content_config_2->set_url_type(GetParam().url_type); + + request->set_on_task_config(std::move(on_task_config)); + request->set_group_ids({"1", "2"}); + + request_sender()->StartRequestWithAuthRetry(std::move(request)); + + ASSERT_TRUE(future.Wait()); + std::optional<base::Value> actual_root = + base::JSONReader::Read(http_request.content, base::JSON_PARSE_RFC); + ASSERT_TRUE(actual_root.has_value() && actual_root->is_dict()); + + auto* content_configs = actual_root->GetDict().FindListByDottedPath( + "sessionConfig.onTaskConfig.activeBundle.contentConfigs"); + ASSERT_TRUE(content_configs); + ASSERT_EQ(content_configs->size(), 2u); + + auto url_type_val = (*content_configs)[1].GetIfDict()->FindInt("urlType"); + ASSERT_TRUE(url_type_val.has_value()); + EXPECT_EQ(url_type_val.value(), GetParam().url_type); +} + +INSTANTIATE_TEST_SUITE_P( + UpdateSessionConfigUrlTypeTests, + UpdateSessionConfigUrlTypeTest, + testing::Values( + UpdateSessionConfigUrlTypeTestParam{"GeminiRegular", + ::boca::URL_TYPE_GEMINI_REGULAR}, + UpdateSessionConfigUrlTypeTestParam{ + "GeminiGuidedLearning", ::boca::URL_TYPE_GEMINI_GUIDED_LEARNING}), + [](const testing::TestParamInfo<UpdateSessionConfigUrlTypeTest::ParamType>& + info) { return info.param.test_name; }); + } // namespace ash::boca
diff --git a/chromeos/ash/experiences/arc/compat_mode/resize_toggle_menu.cc b/chromeos/ash/experiences/arc/compat_mode/resize_toggle_menu.cc index 42db408..9398066 100644 --- a/chromeos/ash/experiences/arc/compat_mode/resize_toggle_menu.cc +++ b/chromeos/ash/experiences/arc/compat_mode/resize_toggle_menu.cc
@@ -190,14 +190,13 @@ window_observation_.Observe(window); - bubble_delegate_ = MakeBubbleDelegate( - widget_, GetAnchorRect(), - base::BindRepeating(&ResizeToggleMenu::ApplyResizeCompatMode, - base::Unretained(this))); - bubble_widget_ = base::WrapUnique<views::Widget>( - views::BubbleDialogDelegate::CreateBubbleDeprecated( - bubble_delegate_.get(), - views::Widget::InitParams::CLIENT_OWNS_WIDGET)); + std::unique_ptr<views::BubbleDialogDelegate> bubble_delegate = + MakeBubbleDelegate( + widget_, GetAnchorRect(), + base::BindRepeating(&ResizeToggleMenu::ApplyResizeCompatMode, + base::Unretained(this))); + bubble_widget_ = + views::BubbleDialogDelegate::CreateBubble(std::move(bubble_delegate)); widget_observations_.AddObservation(widget_.get()); widget_observations_.AddObservation(bubble_widget_.get()); OverlayDialog::Show(widget_->GetNativeWindow(), @@ -359,7 +358,7 @@ } bool ResizeToggleMenu::IsBubbleShown() const { - return bubble_delegate_ && bubble_delegate_->GetWidget(); + return bubble_widget_ && !bubble_widget_->IsClosed(); } void ResizeToggleMenu::CloseBubble() {
diff --git a/chromeos/ash/experiences/arc/compat_mode/resize_toggle_menu.h b/chromeos/ash/experiences/arc/compat_mode/resize_toggle_menu.h index 5d4c2ab..860d3f8 100644 --- a/chromeos/ash/experiences/arc/compat_mode/resize_toggle_menu.h +++ b/chromeos/ash/experiences/arc/compat_mode/resize_toggle_menu.h
@@ -118,7 +118,6 @@ base::CancelableOnceClosure auto_close_closure_; - std::unique_ptr<views::BubbleDialogDelegate> bubble_delegate_; std::unique_ptr<views::Widget> bubble_widget_; // Store only for testing.
diff --git a/clank b/clank index 4a1e60d..5683fd1 160000 --- a/clank +++ b/clank
@@ -1 +1 @@ -Subproject commit 4a1e60d516065bfec4001af37a85676174ece923 +Subproject commit 5683fd1a4e5efcee66a6c524d3a100ff831280f3
diff --git a/clusterfuzz-data b/clusterfuzz-data index 1629185..96aa078 160000 --- a/clusterfuzz-data +++ b/clusterfuzz-data
@@ -1 +1 @@ -Subproject commit 16291853b71303fe621459f0c280e2ba1257d529 +Subproject commit 96aa078abb0c3d3ba923776bd47f489e4e675a35
diff --git a/components/autofill/core/browser/data_manager/payments/payments_data_manager.cc b/components/autofill/core/browser/data_manager/payments/payments_data_manager.cc index d177a2d..ce2d7b6 100644 --- a/components/autofill/core/browser/data_manager/payments/payments_data_manager.cc +++ b/components/autofill/core/browser/data_manager/payments/payments_data_manager.cc
@@ -254,10 +254,10 @@ if (IsAutofillPaymentMethodsEnabled()) { autofill_metrics::LogIsAutofillPaymentsCvcStorageEnabledAtStartup( IsPaymentCvcStorageEnabled()); -#if !BUILDFLAG(IS_IOS) - autofill_metrics::LogIsCreditCardBenefitsEnabledAtStartup( - prefs::IsPaymentCardBenefitsEnabled(pref_service_)); -#endif // !BUILDFLAG(IS_IOS) + if (IsCardBenefitsSyncEnabled()) { + autofill_metrics::LogIsCreditCardBenefitsEnabledAtStartup( + prefs::IsPaymentCardBenefitsEnabled(pref_service_)); + } } else { autofill_metrics::LogAutofillPaymentMethodsDisabledReasonAtStartup( *pref_service_);
diff --git a/components/browser_ui/media/android/BUILD.gn b/components/browser_ui/media/android/BUILD.gn index 338d6f1..091b515 100644 --- a/components/browser_ui/media/android/BUILD.gn +++ b/components/browser_ui/media/android/BUILD.gn
@@ -32,6 +32,7 @@ deps = [ ":java_resources", "//base:base_java", + "//build/android:build_java", "//components/browser_ui/notifications/android:java", "//components/cached_flags:java", "//components/favicon/android:java",
diff --git a/components/browser_ui/media/android/java/src/org/chromium/components/browser_ui/media/MediaSessionHelper.java b/components/browser_ui/media/android/java/src/org/chromium/components/browser_ui/media/MediaSessionHelper.java index f8afa41..8759ecc 100644 --- a/components/browser_ui/media/android/java/src/org/chromium/components/browser_ui/media/MediaSessionHelper.java +++ b/components/browser_ui/media/android/java/src/org/chromium/components/browser_ui/media/MediaSessionHelper.java
@@ -20,9 +20,11 @@ import androidx.annotation.VisibleForTesting; import org.chromium.base.ContextUtils; +import org.chromium.base.ResettersForTesting; import org.chromium.base.ScreenStateReceiver; import org.chromium.base.SysUtils; import org.chromium.base.TimeUtils; +import org.chromium.build.BuildConfig; import org.chromium.build.annotations.EnsuresNonNullIf; import org.chromium.build.annotations.NullMarked; import org.chromium.build.annotations.Nullable; @@ -90,6 +92,12 @@ // static getter {@link MediaSession#fromWebContents()}. @VisibleForTesting public static @Nullable MediaSession sOverriddenMediaSession; + public static @Nullable MediaSessionHelper sInstanceForTesting; + + public ScreenStateReceiver.ScreenStateObserver getScreenStateObserverForTesting() { + return mScreenStateObserver; + } + // To track deep sleep duration between screen off and screen on. private long mDeepSleepTimeAtScreenOffMs = INVALID_DEEP_SLEEP_TIME; private boolean mIsPaused; @@ -497,6 +505,11 @@ } ScreenStateReceiver.addObserver(mScreenStateObserver); + + if (BuildConfig.IS_FOR_TEST) { + sInstanceForTesting = this; + ResettersForTesting.register(() -> sInstanceForTesting = null); + } } /**
diff --git a/components/browser_ui/strings/android/browser_ui_strings.grd b/components/browser_ui/strings/android/browser_ui_strings.grd index 9f604774..a62cae3f 100644 --- a/components/browser_ui/strings/android/browser_ui_strings.grd +++ b/components/browser_ui/strings/android/browser_ui_strings.grd
@@ -1318,15 +1318,6 @@ <message name="IDS_EDUCATIONAL_TIP_HISTORY_SYNC_BUTTON_LETS_GO" desc="Text on the clickable button on the history sync promo that invites users to turn on history sync in the educational tip module on NTP."> Let’s go </message> - <message name="IDS_EDUCATIONAL_TIP_TIPS_NOTIFICATIONS_TITLE" desc="Title of the tips notifications promo that invites users to turn on tips notifications in the educational tip module on NTP."> - Get Chrome tips notifications - </message> - <message name="IDS_EDUCATIONAL_TIP_TIPS_NOTIFICATIONS_DESCRIPTION" desc="Description of the tips notifications promo that invites users to turn on tips notifications in the educational tip module on NTP."> - Turn on notifications for useful tips to help you get the best of Chrome - </message> - <message name="IDS_EDUCATIONAL_TIP_TIPS_NOTIFICATIONS_BUTTON" desc="Text on the clickable button on the tips notifications promo that invites users to turn on tips notifications in the educational tip module on NTP."> - Notify me - </message> <!-- Setup List strings -->
diff --git a/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_EDUCATIONAL_TIP_TIPS_NOTIFICATIONS_BUTTON.png.sha1 b/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_EDUCATIONAL_TIP_TIPS_NOTIFICATIONS_BUTTON.png.sha1 deleted file mode 100644 index 1612d5ac..0000000 --- a/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_EDUCATIONAL_TIP_TIPS_NOTIFICATIONS_BUTTON.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -715b91c636d947d2369b1444aee1ca031e15c711 \ No newline at end of file
diff --git a/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_EDUCATIONAL_TIP_TIPS_NOTIFICATIONS_DESCRIPTION.png.sha1 b/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_EDUCATIONAL_TIP_TIPS_NOTIFICATIONS_DESCRIPTION.png.sha1 deleted file mode 100644 index 1612d5ac..0000000 --- a/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_EDUCATIONAL_TIP_TIPS_NOTIFICATIONS_DESCRIPTION.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -715b91c636d947d2369b1444aee1ca031e15c711 \ No newline at end of file
diff --git a/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_EDUCATIONAL_TIP_TIPS_NOTIFICATIONS_TITLE.png.sha1 b/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_EDUCATIONAL_TIP_TIPS_NOTIFICATIONS_TITLE.png.sha1 deleted file mode 100644 index 3148cc2..0000000 --- a/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_EDUCATIONAL_TIP_TIPS_NOTIFICATIONS_TITLE.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -f58d3126662ee43f427039f517b90ba69b23aee5 \ No newline at end of file
diff --git a/components/contextual_search/internal/composebox_query_controller_unittest.cc b/components/contextual_search/internal/composebox_query_controller_unittest.cc index 44cc5ad..1c047acd 100644 --- a/components/contextual_search/internal/composebox_query_controller_unittest.cc +++ b/components/contextual_search/internal/composebox_query_controller_unittest.cc
@@ -154,10 +154,6 @@ } else { disabled_features.push_back(lens::features::kLensSendRawFileMediaTypes); } - // TODO(crbug.com/503732217): Fix tests to support lazy fetching of cluster - // info and enable this feature by default in tests. - disabled_features.push_back( - contextual_tasks::kContextualTasksLazyFetchClusterInfo); scoped_feature_list_.InitWithFeatures(enabled_features, disabled_features); // Create the config params. @@ -229,8 +225,6 @@ int fetch_request_count = 1) { EXPECT_EQ(QueryControllerState::kAwaitingClusterInfoResponse, controller_state_future_.Take()); - EXPECT_EQ(QueryControllerState::kAwaitingClusterInfoResponse, - controller().query_controller_state()); EXPECT_EQ(expected_state, controller_state_future_.Take()); EXPECT_EQ(expected_state, controller().query_controller_state()); @@ -350,10 +344,9 @@ } } - // Initialize controller, ensuring cluster info is set up. + // Initialize controller. void StartSession() { controller().InitializeIfNeeded(); - WaitForClusterInfo(); } base::UnguessableToken UploadSimpleTestAttachment(lens::MimeType mime_type) { @@ -398,6 +391,11 @@ EXPECT_TRUE(false) << "Unsupported Lens MIME Type"; } + if (controller().query_controller_state() != + QueryControllerState::kClusterInfoReceived) { + WaitForClusterInfo(); + } + // Assert: Validate file upload request and status changes. EXPECT_TRUE(controller().GetFileInfoForTesting(file_token)); return file_token; @@ -626,12 +624,13 @@ TEST_F(ComposeboxQueryControllerTest, InitializeIfNeededIssuesClusterInfoRequestWithOAuth) { - // Arrange: Make primary account available. + // Make primary account available. identity_test_env()->MakePrimaryAccountAvailable( kTestUser, signin::ConsentLevel::kSignin); // Act: Start the session. controller().InitializeIfNeeded(); + controller().TriggerFetchClusterInfo(); identity_test_env()->WaitForAccessTokenRequestIfNecessaryAndRespondWithToken( access_token_info().token, access_token_info().expiration_time, access_token_info().id_token); @@ -642,11 +641,12 @@ TEST_F(ComposeboxQueryControllerTest, InitializeIfNeededIssuesClusterInfoRequestFailure) { - // Arrange: Simulate an error in the cluster info request. + // Simulate an error in the cluster info request. controller().set_next_cluster_info_request_should_return_error(true); // Act: Start the session. controller().InitializeIfNeeded(); + controller().TriggerFetchClusterInfo(); // Assert: Validate cluster info request and state changes. WaitForClusterInfo( @@ -656,6 +656,8 @@ TEST_F(ComposeboxQueryControllerTest, SetIsBackgroundedSuspendsPolling) { // Act: Initialize session and immediately background. controller().InitializeIfNeeded(); + controller().TriggerFetchClusterInfo(); + EXPECT_EQ(QueryControllerState::kAwaitingClusterInfoResponse, controller().query_controller_state()); @@ -682,6 +684,7 @@ TEST_F(ComposeboxQueryControllerTest, SetIsBackgroundedAfterSuccessBreaksLoop) { // Act: Initialize and wait for success. controller().InitializeIfNeeded(); + controller().TriggerFetchClusterInfo(); WaitForClusterInfo(); // Moves to kClusterInfoReceived controller().SetIsBackgrounded(true); @@ -730,6 +733,7 @@ // Act: Start the session. controller().InitializeIfNeeded(); + controller().TriggerFetchClusterInfo(); // Assert: Validate cluster info request and state changes. // InitializeIfNeeded sets state to kAwaitingClusterInfoResponse then // kClusterInfoInvalid. @@ -787,6 +791,7 @@ // Act: Start the session. controller().InitializeIfNeeded(); + controller().TriggerFetchClusterInfo(); // Assert: Validate cluster info request and state changes. WaitForClusterInfo( @@ -824,6 +829,7 @@ // Start the session again. // Since retries were reset, a new fetch should be issued and fail. controller().InitializeIfNeeded(); + controller().TriggerFetchClusterInfo(); // Assert: Validate cluster info request and state changes. WaitForClusterInfo( @@ -835,9 +841,6 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Arrange: Simulate a failure in the file upload request. controller().set_next_file_upload_request_should_return_error(true); @@ -846,6 +849,9 @@ StartPdfFileUploadFlow(file_token, /*file_data=*/std::vector<uint8_t>()); + // Assert: Validate cluster info request and state changes. + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload( file_token, lens::MimeType::kPdf, @@ -868,9 +874,6 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - EXPECT_FALSE(controller().has_stashed_search_url_request()); EXPECT_EQ(controller().get_num_context_uploading(), 0); EXPECT_FALSE(controller().is_any_context_uploading()); @@ -887,6 +890,8 @@ StartImageFileUploadFlow(file_token_3, image_bytes, image_options); StartImageFileUploadFlow(file_token_4, GetSimpleJPGBytes(), image_options); + WaitForClusterInfo(); + EXPECT_FALSE(controller().has_stashed_search_url_request()); EXPECT_EQ(controller().get_num_context_uploading(), 4); EXPECT_TRUE(controller().is_any_context_uploading()); @@ -971,9 +976,6 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - EXPECT_FALSE(controller().has_stashed_search_url_request()); EXPECT_EQ(controller().get_num_context_uploading(), 0); EXPECT_FALSE(controller().is_any_context_uploading()); @@ -985,6 +987,8 @@ StartImageFileUploadFlow(file_token, GetSimpleJPGBytes(), image_options); + WaitForClusterInfo(); + EXPECT_FALSE(controller().has_stashed_search_url_request()); EXPECT_EQ(controller().get_num_context_uploading(), 1); EXPECT_TRUE(controller().is_any_context_uploading()); @@ -1047,9 +1051,6 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - EXPECT_FALSE(controller().has_stashed_search_url_request()); EXPECT_EQ(controller().get_num_context_uploading(), 0); EXPECT_FALSE(controller().is_any_context_uploading()); @@ -1061,6 +1062,9 @@ StartImageFileUploadFlow(file_token, GetSimpleJPGBytes(), image_options); + // Assert: Validate cluster info request and state changes. + WaitForClusterInfo(); + EXPECT_FALSE(controller().has_stashed_search_url_request()); EXPECT_EQ(controller().get_num_context_uploading(), 1); EXPECT_TRUE(controller().is_any_context_uploading()); @@ -1105,10 +1109,6 @@ // proceed and generate a URL. Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Verify the controller is in the awaiting state. - EXPECT_EQ(QueryControllerState::kAwaitingClusterInfoResponse, - controller().query_controller_state()); - // Act: Start the file upload flow to ensure we attempt a multimodal request. const base::UnguessableToken file_token = base::UnguessableToken::Create(); StartPdfFileUploadFlow(file_token, @@ -1153,10 +1153,6 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Verify the controller is in the awaiting state. - EXPECT_EQ(QueryControllerState::kAwaitingClusterInfoResponse, - controller().query_controller_state()); - const base::UnguessableToken file_token = base::UnguessableToken::Create(); const base::UnguessableToken file_token_2 = base::UnguessableToken::Create(); @@ -1213,10 +1209,6 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Verify the controller is in the awaiting state. - EXPECT_EQ(QueryControllerState::kAwaitingClusterInfoResponse, - controller().query_controller_state()); - const base::UnguessableToken file_token = base::UnguessableToken::Create(); const base::UnguessableToken file_token_2 = base::UnguessableToken::Create(); @@ -1300,9 +1292,6 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - EXPECT_FALSE(controller().has_stashed_search_url_request()); EXPECT_EQ(controller().get_num_context_uploading(), 0); EXPECT_FALSE(controller().is_any_context_uploading()); @@ -1316,6 +1305,9 @@ StartImageFileUploadFlow(file_token, image_bytes, image_options); StartImageFileUploadFlow(file_token_2, image_bytes, image_options); + // Assert: Validate cluster info request and state changes. + WaitForClusterInfo(); + EXPECT_FALSE(controller().has_stashed_search_url_request()); EXPECT_EQ(controller().get_num_context_uploading(), 2); EXPECT_TRUE(controller().is_any_context_uploading()); @@ -1415,9 +1407,6 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the file upload flow. const base::UnguessableToken file_token = base::UnguessableToken::Create(); std::vector<uint8_t> image_bytes = CreateJPGBytes(100, 100); @@ -1427,6 +1416,9 @@ .compression_quality = 30}; StartImageFileUploadFlow(file_token, image_bytes, image_options); + // Assert: Validate cluster info request and state changes. + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload(file_token, lens::MimeType::kImage); // Validate the file upload request payload. @@ -1505,9 +1497,6 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the file upload flow. const base::UnguessableToken file_token = base::UnguessableToken::Create(); std::unique_ptr<lens::ContextualInputData> input_data = @@ -1528,6 +1517,8 @@ controller().StartFileUploadFlow(file_token, std::move(input_data), image_options); + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload(file_token, lens::MimeType::kImage); @@ -1558,14 +1549,14 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the file upload flow. const base::UnguessableToken file_token = base::UnguessableToken::Create(); StartPdfFileUploadFlow(file_token, /*file_data=*/std::vector<uint8_t>()); + // Assert: Validate cluster info request and state changes. + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload(file_token, lens::MimeType::kPdf); @@ -1601,9 +1592,6 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the file upload flow. const base::UnguessableToken file_token = base::UnguessableToken::Create(); std::unique_ptr<lens::ContextualInputData> input_data = @@ -1617,6 +1605,8 @@ controller().StartFileUploadFlow(file_token, std::move(input_data), /*image_options=*/std::nullopt); + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload(file_token, lens::MimeType::kPdf); @@ -1638,15 +1628,14 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the file upload flow. const base::UnguessableToken file_token = base::UnguessableToken::Create(); int64_t context_id = 12345; StartPdfFileUploadFlow(file_token, /*file_data=*/std::vector<uint8_t>(), context_id); + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload(file_token, lens::MimeType::kPdf); // Validate the file upload request payload. @@ -1747,15 +1736,14 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the file upload flow. const base::UnguessableToken file_token = base::UnguessableToken::Create(); int64_t context_id = 12345; StartPdfFileUploadFlow(file_token, /*file_data=*/std::vector<uint8_t>(), context_id); + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload(file_token, lens::MimeType::kPdf); @@ -1799,14 +1787,14 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the first file upload flow. const base::UnguessableToken file_token_1 = base::UnguessableToken::Create(); int64_t context_id = 12345; StartPdfFileUploadFlow(file_token_1, /*file_data=*/std::vector<uint8_t>(), context_id); + + WaitForClusterInfo(); + WaitForFileUpload(file_token_1, lens::MimeType::kPdf); // Check first file info. @@ -1856,9 +1844,6 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the file upload flow. const base::UnguessableToken file_token = base::UnguessableToken::Create(); std::vector<uint8_t> image_bytes = std::vector<uint8_t>(); @@ -1868,6 +1853,8 @@ .compression_quality = 30}; StartImageFileUploadFlow(file_token, image_bytes, image_options); + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload(file_token, lens::MimeType::kImage, ContextUploadStatus::kValidationFailed, @@ -1884,9 +1871,6 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the file upload flow. auto file_token = base::UnguessableToken::Create(); auto input_data = std::make_unique<lens::ContextualInputData>(); @@ -1906,6 +1890,8 @@ controller().StartFileUploadFlow(file_token, std::move(input_data), image_options); + WaitForClusterInfo(); + // Assert: The file upload should fail with kImageProcessingError due to the // empty viewport screenshot, and the file info should be removed from the // controller. @@ -1917,9 +1903,6 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the file upload flow. const base::UnguessableToken file_token = base::UnguessableToken::Create(); std::unique_ptr<lens::ContextualInputData> input_data = @@ -1933,6 +1916,8 @@ controller().StartFileUploadFlow(file_token, std::move(input_data), /*image_options=*/std::nullopt); + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload(file_token, lens::MimeType::kPdf); @@ -1953,9 +1938,6 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the file upload flow. const base::UnguessableToken file_token = base::UnguessableToken::Create(); std::unique_ptr<lens::ContextualInputData> input_data = @@ -1971,6 +1953,8 @@ controller().StartFileUploadFlow(file_token, std::move(input_data), /*image_options=*/std::nullopt); + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload(file_token, lens::MimeType::kPdf); @@ -1993,14 +1977,14 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the file upload flow. const base::UnguessableToken file_token = base::UnguessableToken::Create(); StartPdfFileUploadFlow(file_token, /*file_data=*/std::vector<uint8_t>()); + // Assert: Validate cluster info request and state changes. + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload(file_token, lens::MimeType::kPdf); // Validate the file upload request payload. @@ -2087,9 +2071,6 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the file upload flow. const base::UnguessableToken file_token = base::UnguessableToken::Create(); std::unique_ptr<lens::ContextualInputData> input_data = @@ -2103,6 +2084,8 @@ controller().StartFileUploadFlow(file_token, std::move(input_data), /*image_options=*/std::nullopt); + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload(file_token, lens::MimeType::kPdf); @@ -2116,9 +2099,6 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the file upload flow with multiple context inputs and page // context params. GURL page_url = GURL("https://www.test.com"); @@ -2137,6 +2117,8 @@ controller().StartFileUploadFlow(file_token, std::move(input_data), /*image_options=*/std::nullopt); + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload(file_token, lens::MimeType::kPdf); // Validate the file upload request payload. @@ -2257,9 +2239,6 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the file upload flow with multiple context inputs and page // context params. GURL page_url = GURL("https://www.test.com"); @@ -2285,6 +2264,8 @@ controller().StartFileUploadFlow(file_token, std::move(input_data), image_options); + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload(file_token, lens::MimeType::kPdf); @@ -2374,7 +2355,6 @@ TEST_F(ComposeboxQueryControllerTest, CreateSearchUrlWithInvocationSource) { CreateController(/*send_lns_surface=*/false); controller().InitializeIfNeeded(); - WaitForClusterInfo(); std::unique_ptr<CreateSearchUrlRequestInfo> search_url_request_info = std::make_unique<CreateSearchUrlRequestInfo>(); @@ -2398,9 +2378,6 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the file upload flow with multiple context inputs and page // context params. GURL page_url = GURL("https://www.test.com"); @@ -2556,9 +2533,6 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the file upload flow with context inputs and page context // params. GURL page_url = GURL("https://www.test.com"); @@ -2583,6 +2557,8 @@ controller().StartFileUploadFlow(file_token, std::move(input_data), image_options); + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload(file_token, lens::MimeType::kAnnotatedPageContent); @@ -2741,9 +2717,6 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the file upload flow with viewport and pdf context inputs. GURL page_url = GURL("https://www.test.com"); std::string page_title = "Test Page"; @@ -2768,6 +2741,8 @@ controller().StartFileUploadFlow(file_token, std::move(input_data), image_options); + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload(file_token, lens::MimeType::kPdf); @@ -2789,9 +2764,6 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the file upload flow with context inputs and page context // params. GURL page_url = GURL("https://www.test.com"); @@ -2809,19 +2781,19 @@ controller().StartFileUploadFlow(file_token, std::move(input_data), std::nullopt); + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload(file_token, lens::MimeType::kAnnotatedPageContent, ContextUploadStatus::kValidationFailed, - ContextUploadErrorType::kBrowserProcessingError); + ContextUploadErrorType::kBrowserProcessingError, + /*expect_suggest_signals_ready=*/false); } TEST_F(ComposeboxQueryControllerTest, UploadInvalidMimeTypeFileRequestFailure) { // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the file upload flow. const base::UnguessableToken file_token = base::UnguessableToken::Create(); @@ -2833,19 +2805,19 @@ controller().StartFileUploadFlow(file_token, std::move(input_data), /*image_options=*/std::nullopt); + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload(file_token, mime_type, ContextUploadStatus::kValidationFailed, - ContextUploadErrorType::kBrowserProcessingError); + ContextUploadErrorType::kBrowserProcessingError, + /*expect_suggest_signals_ready=*/false); } TEST_F(ComposeboxQueryControllerTest, UploadUnknownMimeTypeFileRequestSuccess) { // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the file upload flow. const base::UnguessableToken file_token = base::UnguessableToken::Create(); std::unique_ptr<lens::ContextualInputData> input_data = @@ -2858,6 +2830,8 @@ controller().StartFileUploadFlow(file_token, std::move(input_data), /*image_options=*/std::nullopt); + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload(file_token, lens::MimeType::kUnknown); @@ -2892,6 +2866,8 @@ // Act: Start the session. controller().InitializeIfNeeded(); + controller().TriggerFetchClusterInfo(); + identity_test_env()->WaitForAccessTokenRequestIfNecessaryAndRespondWithToken( access_token_info().token, access_token_info().expiration_time, access_token_info().id_token); @@ -2918,14 +2894,14 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the file upload flow. const base::UnguessableToken file_token = base::UnguessableToken::Create(); StartPdfFileUploadFlow(file_token, /*file_data=*/std::vector<uint8_t>()); + // Assert: Validate cluster info request and state changes. + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload(file_token, lens::MimeType::kPdf); @@ -3045,10 +3021,6 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Verify the controller is in the awaiting state. - EXPECT_EQ(QueryControllerState::kAwaitingClusterInfoResponse, - controller().query_controller_state()); - // Act: Start the file upload flow to ensure we attempt a multimodal request. const base::UnguessableToken file_token = base::UnguessableToken::Create(); StartPdfFileUploadFlow(file_token, @@ -3097,10 +3069,6 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Verify the controller is in the awaiting state. - EXPECT_EQ(QueryControllerState::kAwaitingClusterInfoResponse, - controller().query_controller_state()); - // Act: Start the file upload flow to ensure we attempt a multimodal request. const base::UnguessableToken file_token = base::UnguessableToken::Create(); StartPdfFileUploadFlow(file_token, @@ -3146,10 +3114,6 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Verify the controller is in the awaiting state. - EXPECT_EQ(QueryControllerState::kAwaitingClusterInfoResponse, - controller().query_controller_state()); - // Act: Generate the destination URL for the query. std::unique_ptr<CreateSearchUrlRequestInfo> search_url_request_info = std::make_unique<CreateSearchUrlRequestInfo>(); @@ -3183,6 +3147,7 @@ // Act: Start the session. controller().InitializeIfNeeded(); + controller().TriggerFetchClusterInfo(); // Assert: Validate cluster info request and state changes. WaitForClusterInfo(QueryControllerState::kClusterInfoInvalid); @@ -3227,9 +3192,6 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Generate the destination URL for the query. std::unique_ptr<CreateSearchUrlRequestInfo> search_url_request_info = std::make_unique<CreateSearchUrlRequestInfo>(); @@ -3270,14 +3232,13 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the file upload flow. const base::UnguessableToken file_token = base::UnguessableToken::Create(); StartPdfFileUploadFlow(file_token, /*file_data=*/std::vector<uint8_t>()); + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload(file_token, lens::MimeType::kPdf); @@ -3338,13 +3299,11 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the file upload flow. const base::UnguessableToken file_token = base::UnguessableToken::Create(); StartPdfFileUploadFlow(file_token, /*file_data=*/std::vector<uint8_t>()); + WaitForClusterInfo(); // Assert: Validate file upload request and status changes. WaitForFileUpload(file_token, lens::MimeType::kPdf); @@ -3385,9 +3344,6 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Create the ClientToAimRequest with specific tool and model modes. std::unique_ptr<CreateClientToAimRequestInfo> client_to_aim_request_info = std::make_unique<CreateClientToAimRequestInfo>(); @@ -3432,9 +3388,6 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Create the ClientToAimRequest. std::unique_ptr<CreateClientToAimRequestInfo> client_to_aim_request_info = std::make_unique<CreateClientToAimRequestInfo>(); @@ -3466,9 +3419,6 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Create the ClientToAimRequest. std::unique_ptr<CreateClientToAimRequestInfo> client_to_aim_request_info = std::make_unique<CreateClientToAimRequestInfo>(); @@ -3507,14 +3457,13 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the file upload flow. const base::UnguessableToken file_token = base::UnguessableToken::Create(); StartPdfFileUploadFlow(file_token, /*file_data=*/std::vector<uint8_t>()); + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload(file_token, lens::MimeType::kPdf); @@ -3596,14 +3545,13 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the file upload flow. const base::UnguessableToken file_token = base::UnguessableToken::Create(); StartPdfFileUploadFlow(file_token, /*file_data=*/std::vector<uint8_t>()); + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload(file_token, lens::MimeType::kPdf); @@ -3676,14 +3624,13 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the file upload flow. const base::UnguessableToken file_token = base::UnguessableToken::Create(); StartPdfFileUploadFlow(file_token, /*file_data=*/std::vector<uint8_t>()); + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload(file_token, lens::MimeType::kPdf); @@ -3778,9 +3725,6 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the file upload flow. const base::UnguessableToken file_token = base::UnguessableToken::Create(); std::vector<uint8_t> image_bytes = CreateJPGBytes(100, 100); @@ -3790,6 +3734,8 @@ .compression_quality = 30}; StartImageFileUploadFlow(file_token, image_bytes, image_options); + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload(file_token, lens::MimeType::kImage); @@ -3850,9 +3796,6 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the image file upload flow. // Simulating user uploading an image via context menu. const base::UnguessableToken file_token = base::UnguessableToken::Create(); @@ -3863,6 +3806,8 @@ .compression_quality = 30}; StartImageFileUploadFlow(file_token, image_bytes, image_options); + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload(file_token, lens::MimeType::kImage); @@ -3907,14 +3852,13 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the first file upload flow - PDF. // Simulating user uploading a pdf via context menu. const base::UnguessableToken pdf_token = base::UnguessableToken::Create(); StartPdfFileUploadFlow(pdf_token, /*file_data=*/std::vector<uint8_t>()); + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload(pdf_token, lens::MimeType::kPdf); @@ -4004,9 +3948,6 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Ensure that future cluster info requests fail. controller().set_next_cluster_info_request_should_return_error(true); @@ -4015,8 +3956,14 @@ StartPdfFileUploadFlow(file_token, /*file_data=*/std::vector<uint8_t>()); + WaitForClusterInfo(QueryControllerState::kClusterInfoInvalid); + // Assert: Validate file upload request and status changes. - WaitForFileUpload(file_token, lens::MimeType::kPdf); + WaitForFileUpload(file_token, lens::MimeType::kPdf, + ContextUploadStatus::kUploadFailed, + ContextUploadErrorType::kServerError, + /*expect_suggest_signals_ready=*/false, + /*expect_upload_started=*/false); // Wait 1 hour. task_environment().FastForwardBy(base::Hours(1)); @@ -4174,14 +4121,13 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the file upload flow. const base::UnguessableToken file_token = base::UnguessableToken::Create(); StartPdfFileUploadFlow(file_token, /*file_data=*/std::vector<uint8_t>()); + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload(file_token, lens::MimeType::kPdf); @@ -4211,9 +4157,6 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the file upload flow. const base::UnguessableToken file_token = base::UnguessableToken::Create(); std::unique_ptr<lens::ContextualInputData> input_data = @@ -4227,6 +4170,9 @@ controller().StartFileUploadFlow(file_token, std::move(input_data), /*image_options=*/std::nullopt); + // Assert: Validate cluster info request and state changes. + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload(file_token, lens::MimeType::kUnknown); @@ -4256,14 +4202,13 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the file upload flow. const base::UnguessableToken file_token = base::UnguessableToken::Create(); StartPdfFileUploadFlow(file_token, /*file_data=*/std::vector<uint8_t>()); + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload(file_token, lens::MimeType::kPdf); @@ -4293,14 +4238,13 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the file upload flow. const base::UnguessableToken file_token = base::UnguessableToken::Create(); StartPdfFileUploadFlow(file_token, /*file_data=*/std::vector<uint8_t>()); + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload(file_token, lens::MimeType::kPdf); @@ -4331,15 +4275,14 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the first file upload flow. const base::UnguessableToken first_file_token = base::UnguessableToken::Create(); StartPdfFileUploadFlow(first_file_token, /*file_data=*/std::vector<uint8_t>()); + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload(first_file_token, lens::MimeType::kPdf); @@ -4522,9 +4465,6 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Arrange: Create a fake response with text. lens::LensOverlayServerResponse file_upload_response; file_upload_response.mutable_objects_response() @@ -4538,6 +4478,8 @@ const base::UnguessableToken file_token = base::UnguessableToken::Create(); StartPdfFileUploadFlow(file_token, /*file_data=*/std::vector<uint8_t>()); + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload(file_token, lens::MimeType::kPdf); @@ -4624,6 +4566,9 @@ input_data->is_page_context_eligible = true; controller().StartFileUploadFlow(file_token, std::move(input_data), std::nullopt); + + WaitForClusterInfo(); + WaitForFileUpload(file_token, lens::MimeType::kAnnotatedPageContent); // Act: Create suggest inputs. @@ -4642,14 +4587,13 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the file upload flow. const base::UnguessableToken file_token = base::UnguessableToken::Create(); StartPdfFileUploadFlow(file_token, /*file_data=*/std::vector<uint8_t>()); + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload(file_token, lens::MimeType::kPdf); @@ -4676,12 +4620,14 @@ TEST_F(ComposeboxQueryControllerTest, HandleInteractionResponse) { // Act: Start the session. controller().InitializeIfNeeded(); - WaitForClusterInfo(); // Act: Start the file upload flow. const base::UnguessableToken file_token = base::UnguessableToken::Create(); StartPdfFileUploadFlow(file_token, /*file_data=*/std::vector<uint8_t>()); + + WaitForClusterInfo(); + WaitForFileUpload(file_token, lens::MimeType::kPdf); // Arrange: Set up the fake interaction response. @@ -4732,9 +4678,6 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the file upload flow. const base::UnguessableToken file_token = base::UnguessableToken::Create(); std::vector<uint8_t> image_bytes = CreateJPGBytes(100, 100); @@ -4744,6 +4687,8 @@ .compression_quality = 30}; StartImageFileUploadFlow(file_token, image_bytes, image_options); + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload(file_token, lens::MimeType::kImage); @@ -4772,12 +4717,14 @@ CreateClientToAimRequest_ForceIncludeInteractionData_HasInteraction) { // Act: Start the session. controller().InitializeIfNeeded(); - WaitForClusterInfo(); // Act: Start the file upload flow (PDF). const base::UnguessableToken file_token = base::UnguessableToken::Create(); StartPdfFileUploadFlow(file_token, /*file_data=*/std::vector<uint8_t>()); + + WaitForClusterInfo(); + WaitForFileUpload(file_token, lens::MimeType::kPdf); // Act: Send interaction request via CreateSearchUrl. @@ -4847,12 +4794,14 @@ CreateClientToAimRequest_ForceIncludeInteractionData_SetsMediaTypeToImage) { // Act: Start the session. controller().InitializeIfNeeded(); - WaitForClusterInfo(); // Act: Start the file upload flow (PDF). const base::UnguessableToken file_token = base::UnguessableToken::Create(); StartPdfFileUploadFlow(file_token, /*file_data=*/std::vector<uint8_t>()); + + WaitForClusterInfo(); + WaitForFileUpload(file_token, lens::MimeType::kPdf); // Act: Send interaction request via CreateSearchUrl. @@ -4918,12 +4867,14 @@ CreateClientToAimRequest_ForceIncludeInteractionData_NoInteraction) { // Act: Start the session. controller().InitializeIfNeeded(); - WaitForClusterInfo(); // Act: Start the file upload flow (PDF). const base::UnguessableToken file_token = base::UnguessableToken::Create(); StartPdfFileUploadFlow(file_token, /*file_data=*/std::vector<uint8_t>()); + + WaitForClusterInfo(); + WaitForFileUpload(file_token, lens::MimeType::kPdf); // Create ClientToAimRequest with force = true, but no interaction request @@ -4954,7 +4905,6 @@ CreateClientToAimRequest_RegionInteractionAttachesOnlyToOverlayToken) { // Act: Start the session. controller().InitializeIfNeeded(); - WaitForClusterInfo(); // Act: Start the file upload flow for an Overlay token. const base::UnguessableToken overlay_token = base::UnguessableToken::Create(); @@ -4963,6 +4913,9 @@ overlay_input->primary_content_type = lens::MimeType::kUnknown; controller().StartFileUploadFlow(overlay_token, std::move(overlay_input), std::nullopt); + + WaitForClusterInfo(); + WaitForFileUpload(overlay_token, lens::MimeType::kUnknown); // Act: Start the file upload flow for a PDF tab. @@ -5038,12 +4991,14 @@ TEST_F(ComposeboxQueryControllerTest, CreateClientToAimRequest_NoInteraction) { // Act: Start the session. controller().InitializeIfNeeded(); - WaitForClusterInfo(); // Act: Start the file upload flow (PDF). const base::UnguessableToken file_token = base::UnguessableToken::Create(); StartPdfFileUploadFlow(file_token, /*file_data=*/std::vector<uint8_t>()); + + WaitForClusterInfo(); + WaitForFileUpload(file_token, lens::MimeType::kPdf); // Create ClientToAimRequest with force = false. @@ -5070,12 +5025,14 @@ TEST_F(ComposeboxQueryControllerTest, CreateSearchUrl_IncludesAddedInputs) { // Act: Start the session. controller().InitializeIfNeeded(); - WaitForClusterInfo(); // Act: Start the file upload flow (PDF). const base::UnguessableToken file_token = base::UnguessableToken::Create(); StartPdfFileUploadFlow(file_token, /*file_data=*/std::vector<uint8_t>()); + + WaitForClusterInfo(); + WaitForFileUpload(file_token, lens::MimeType::kPdf); // Act: Create search URL. @@ -5105,7 +5062,6 @@ TEST_F(ComposeboxQueryControllerTest, CreateSearchUrl_IncludesUnresolvedUrl) { // Act: Start the session. controller().InitializeIfNeeded(); - WaitForClusterInfo(); // Act: Start the file upload flow (URL). const base::UnguessableToken file_token = base::UnguessableToken::Create(); @@ -5116,6 +5072,8 @@ controller().StartFileUploadFlow(file_token, std::move(input_data), /*image_options=*/std::nullopt); + WaitForClusterInfo(); + WaitForFileUpload(file_token, lens::MimeType::kUnknown); // Act: Create search URL. @@ -5153,12 +5111,14 @@ UnresolvedUrl_GeneratesNewUuidAndContextId) { // Act: Start the session. controller().InitializeIfNeeded(); - WaitForClusterInfo(); // Act: Start the file upload flow (PDF). const base::UnguessableToken file_token_1 = base::UnguessableToken::Create(); StartPdfFileUploadFlow(file_token_1, /*file_data=*/std::vector<uint8_t>()); + + WaitForClusterInfo(); + WaitForFileUpload(file_token_1, lens::MimeType::kPdf); // Act: Start the file upload flow (URL). @@ -5192,7 +5152,6 @@ CreateSearchUrl_IncludesMultipleUnresolvedUrls) { // Act: Start the session. controller().InitializeIfNeeded(); - WaitForClusterInfo(); // Act: Start the file upload flow (URL 1). const base::UnguessableToken file_token_1 = base::UnguessableToken::Create(); @@ -5203,6 +5162,8 @@ controller().StartFileUploadFlow(file_token_1, std::move(input_data_1), /*image_options=*/std::nullopt); + WaitForClusterInfo(); + WaitForFileUpload(file_token_1, lens::MimeType::kUnknown); // Act: Start the file upload flow (URL 2). @@ -5258,12 +5219,14 @@ CreateSearchUrl_IncludesTabAndUnresolvedUrl) { // Act: Start the session. controller().InitializeIfNeeded(); - WaitForClusterInfo(); // Act: Start the file upload flow (PDF). const base::UnguessableToken file_token_1 = base::UnguessableToken::Create(); StartPdfFileUploadFlow(file_token_1, /*file_data=*/std::vector<uint8_t>()); + + WaitForClusterInfo(); + WaitForFileUpload(file_token_1, lens::MimeType::kPdf); // Act: Start the file upload flow (URL). @@ -5309,7 +5272,6 @@ CreateClientToAimRequest_IncludesUnresolvedUrl) { // Act: Start the session. controller().InitializeIfNeeded(); - WaitForClusterInfo(); // Act: Start the file upload flow (URL). const base::UnguessableToken file_token = base::UnguessableToken::Create(); @@ -5320,6 +5282,8 @@ controller().StartFileUploadFlow(file_token, std::move(input_data), /*image_options=*/std::nullopt); + WaitForClusterInfo(); + WaitForFileUpload(file_token, lens::MimeType::kUnknown); // Create ClientToAimRequest. @@ -5357,7 +5321,6 @@ CreateSearchUrl_ImageUpload_DoesNotIncludeAddedInputs) { // Act: Start the session. controller().InitializeIfNeeded(); - WaitForClusterInfo(); // Act: Start the file upload flow (JPG). const base::UnguessableToken file_token = base::UnguessableToken::Create(); @@ -5367,6 +5330,9 @@ .max_width = 1000, .compression_quality = 30}; StartImageFileUploadFlow(file_token, image_bytes, image_options); + + WaitForClusterInfo(); + WaitForFileUpload(file_token, lens::MimeType::kImage); // Act: Create search URL. @@ -5392,12 +5358,14 @@ CreateSearchUrl_StandardSearch_DoesNotIncludeAaiOrAmc) { // Act: Start the session. controller().InitializeIfNeeded(); - WaitForClusterInfo(); // Act: Start the file upload flow (PDF). const base::UnguessableToken file_token = base::UnguessableToken::Create(); StartPdfFileUploadFlow(file_token, /*file_data=*/std::vector<uint8_t>()); + + WaitForClusterInfo(); + WaitForFileUpload(file_token, lens::MimeType::kPdf); // Act: Create search URL. @@ -5429,12 +5397,14 @@ CreateClientToAimRequest_IncludesAddedInputs) { // Act: Start the session. controller().InitializeIfNeeded(); - WaitForClusterInfo(); // Act: Start the file upload flow (PDF). const base::UnguessableToken file_token = base::UnguessableToken::Create(); StartPdfFileUploadFlow(file_token, /*file_data=*/std::vector<uint8_t>()); + + WaitForClusterInfo(); + WaitForFileUpload(file_token, lens::MimeType::kPdf); // Create ClientToAimRequest. @@ -5461,14 +5431,13 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the file upload flow. const base::UnguessableToken file_token = base::UnguessableToken::Create(); StartPdfFileUploadFlow(file_token, /*file_data=*/std::vector<uint8_t>()); + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload(file_token, lens::MimeType::kPdf); @@ -5507,14 +5476,14 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the file upload flow. const base::UnguessableToken file_token = base::UnguessableToken::Create(); StartPdfFileUploadFlow(file_token, /*file_data=*/std::vector<uint8_t>()); + // Assert: Validate cluster info request and state changes. + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload(file_token, lens::MimeType::kPdf); @@ -5554,14 +5523,13 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the file upload flow. const base::UnguessableToken file_token = base::UnguessableToken::Create(); StartPdfFileUploadFlow(file_token, /*file_data=*/std::vector<uint8_t>()); + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload(file_token, lens::MimeType::kPdf); @@ -5589,14 +5557,13 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the file upload flow. const base::UnguessableToken file_token = base::UnguessableToken::Create(); StartPdfFileUploadFlow(file_token, /*file_data=*/std::vector<uint8_t>()); + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload(file_token, lens::MimeType::kPdf); @@ -5636,7 +5603,6 @@ CreateSearchUrl_IncludesAddedInputs_ForFileWithoutRequestId) { // Act: Start the session. controller().InitializeIfNeeded(); - WaitForClusterInfo(); // Act: Start the file upload flow. // TODO(crbug.com/483174088): Replace this with a call to a new testing method @@ -5645,6 +5611,9 @@ const base::UnguessableToken file_token = base::UnguessableToken::Create(); StartPdfFileUploadFlow(file_token, /*file_data=*/std::vector<uint8_t>()); + + WaitForClusterInfo(); + WaitForFileUpload(file_token, lens::MimeType::kPdf); // Act: Clear the request id from the file info. @@ -5685,7 +5654,6 @@ CreateClientToAimRequest_IncludesAddedInputs_ForFileWithoutRequestId) { // Act: Start the session. controller().InitializeIfNeeded(); - WaitForClusterInfo(); // Act: Start the file upload flow. // TODO(crbug.com/483174088): Replace this with a call to a new testing method @@ -5694,6 +5662,9 @@ const base::UnguessableToken file_token = base::UnguessableToken::Create(); StartPdfFileUploadFlow(file_token, /*file_data=*/std::vector<uint8_t>()); + + WaitForClusterInfo(); + WaitForFileUpload(file_token, lens::MimeType::kPdf); // Act: Clear the request id from the file info. @@ -5726,9 +5697,6 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the modality chip upload flow. const base::UnguessableToken file_token = base::UnguessableToken::Create(); lens::ModalityChipProps modality_chip_props; @@ -5738,6 +5706,8 @@ StartModalityChipUploadFlow(file_token, modality_chip_props); + WaitForClusterInfo(); + // Assert: Validate file upload status changes. // Modality chips don't have kProcessing or kUploadStarted states because // they are considered already uploaded from the server. @@ -5763,7 +5733,6 @@ TEST_F(ComposeboxQueryControllerTest, CreateSearchUrl_IncludesModalityChip) { // Act: Start the session. controller().InitializeIfNeeded(); - WaitForClusterInfo(); // Act: Start the modality chip upload flow. const base::UnguessableToken file_token = base::UnguessableToken::Create(); @@ -5771,6 +5740,9 @@ modality_chip_props.mutable_added_input()->mutable_lens_file()->set_vsrid( "test_vsrid"); StartModalityChipUploadFlow(file_token, modality_chip_props); + + WaitForClusterInfo(); + context_upload_status_future_.Take(); // Act: Create search URL. @@ -5800,7 +5772,6 @@ CreateClientToAimRequest_WithModalityChipVsrid_SetsRequestIdAndNotVit) { // Act: Start the session. controller().InitializeIfNeeded(); - WaitForClusterInfo(); // Create a LensOverlayRequestId and encode it as vsrid. lens::LensOverlayRequestId request_id; @@ -5816,6 +5787,9 @@ modality_chip_props.mutable_added_input()->mutable_lens_file()->set_vsrid( vsrid); StartModalityChipUploadFlow(file_token, modality_chip_props); + + WaitForClusterInfo(); + context_upload_status_future_.Take(); // Create ClientToAimRequest. @@ -5845,7 +5819,6 @@ CreateClientToAimRequest_WithModalityChipVsrid_SetsRequestIdAndVit) { // Act: Start the session. controller().InitializeIfNeeded(); - WaitForClusterInfo(); // Create a LensOverlayRequestId and encode it as vsrid. lens::LensOverlayRequestId request_id; @@ -5860,6 +5833,9 @@ modality_chip_props.mutable_added_input()->mutable_lens_file()->set_vsrid( vsrid); StartModalityChipUploadFlow(file_token, modality_chip_props); + + WaitForClusterInfo(); + context_upload_status_future_.Take(); // Create ClientToAimRequest. @@ -5889,7 +5865,6 @@ CreateClientToAimRequest_IncludesModalityChip) { // Act: Start the session. controller().InitializeIfNeeded(); - WaitForClusterInfo(); // Act: Start the modality chip upload flow. const base::UnguessableToken file_token = base::UnguessableToken::Create(); @@ -5897,6 +5872,9 @@ modality_chip_props.mutable_added_input()->mutable_lens_file()->set_vsrid( "test_vsrid"); StartModalityChipUploadFlow(file_token, modality_chip_props); + + WaitForClusterInfo(); + context_upload_status_future_.Take(); // Create ClientToAimRequest. @@ -5921,7 +5899,6 @@ CreateSearchUrl_DoesNotIncludeAddedInputs_WhenLensUsageIntentIsFalse) { // Act: Start the session. controller().InitializeIfNeeded(); - WaitForClusterInfo(); // Act: Start the file upload flow (PDF). const base::UnguessableToken file_token = base::UnguessableToken::Create(); @@ -5936,6 +5913,8 @@ controller().StartFileUploadFlow(file_token, std::move(input_data), /*image_options=*/std::nullopt); + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload(file_token, lens::MimeType::kPdf); @@ -5967,7 +5946,6 @@ CreateClientToAimRequest_DoesNotIncludeAddedInputs_WhenLensUsageIntentIsFalse) { // Act: Start the session. controller().InitializeIfNeeded(); - WaitForClusterInfo(); // Act: Start the file upload flow (PDF). const base::UnguessableToken file_token = base::UnguessableToken::Create(); @@ -5982,6 +5960,8 @@ controller().StartFileUploadFlow(file_token, std::move(input_data), /*image_options=*/std::nullopt); + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload(file_token, lens::MimeType::kPdf); @@ -6044,14 +6024,13 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the file upload flow. const base::UnguessableToken file_token = base::UnguessableToken::Create(); StartPdfFileUploadFlow(file_token, /*file_data=*/std::vector<uint8_t>()); + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload(file_token, lens::MimeType::kPdf); @@ -6080,14 +6059,13 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the file upload flow. const base::UnguessableToken file_token = base::UnguessableToken::Create(); StartPdfFileUploadFlow(file_token, /*file_data=*/std::vector<uint8_t>()); + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload(file_token, lens::MimeType::kPdf); @@ -6120,14 +6098,13 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the file upload flow. const base::UnguessableToken file_token = base::UnguessableToken::Create(); StartPdfFileUploadFlow(file_token, /*file_data=*/std::vector<uint8_t>()); + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload(file_token, lens::MimeType::kPdf); @@ -6162,14 +6139,13 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the file upload flow. const base::UnguessableToken file_token = base::UnguessableToken::Create(); StartPdfFileUploadFlow(file_token, /*file_data=*/std::vector<uint8_t>()); + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload(file_token, lens::MimeType::kPdf); @@ -6203,7 +6179,6 @@ CreateAddedInputs_IncludesFilesWithoutLensUsageIntent) { // Act: Start the session. controller().InitializeIfNeeded(); - WaitForClusterInfo(); // Act: Start the file upload flow (PDF) without Lens usage intent. const base::UnguessableToken file_token = base::UnguessableToken::Create(); @@ -6217,6 +6192,7 @@ controller().StartFileUploadFlow(file_token, std::move(input_data), /*image_options=*/std::nullopt); + WaitForClusterInfo(); // Assert: Validate file upload request and status changes. WaitForFileUpload(file_token, lens::MimeType::kPdf); @@ -6241,7 +6217,6 @@ TEST_F(ComposeboxQueryControllerTest, CreateAddedInputs_UnresolvedUrlUpload) { // Act: Start the session. controller().InitializeIfNeeded(); - WaitForClusterInfo(); // Act: Start the file upload flow (URL). const base::UnguessableToken file_token = base::UnguessableToken::Create(); @@ -6254,6 +6229,8 @@ controller().StartFileUploadFlow(file_token, std::move(input_data), /*image_options=*/std::nullopt); + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload(file_token, lens::MimeType::kUnknown); @@ -6284,9 +6261,6 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the file upload flow. const base::UnguessableToken file_token = base::UnguessableToken::Create(); std::unique_ptr<lens::ContextualInputData> input_data = @@ -6300,6 +6274,8 @@ controller().StartFileUploadFlow(file_token, std::move(input_data), /*image_options=*/std::nullopt); + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. WaitForFileUpload(file_token, lens::MimeType::kPdf); @@ -6334,9 +6310,6 @@ // Act: Start the session. controller().InitializeIfNeeded(); - // Assert: Validate cluster info request and state changes. - WaitForClusterInfo(); - // Act: Start the file upload flow with ONLY viewport screenshot. const base::UnguessableToken file_token = base::UnguessableToken::Create(); std::unique_ptr<lens::ContextualInputData> input_data = @@ -6357,6 +6330,8 @@ controller().StartFileUploadFlow(file_token, std::move(input_data), image_options); + WaitForClusterInfo(); + // Assert: Validate file upload request and status changes. // Since there is no context input, only the viewport image should be // uploaded. @@ -6416,7 +6391,6 @@ /*enable_send_raw_file_media_types=*/true); controller().InitializeIfNeeded(); - WaitForClusterInfo(); const base::UnguessableToken file_token = base::UnguessableToken::Create(); std::unique_ptr<lens::ContextualInputData> input_data = @@ -6430,6 +6404,8 @@ controller().StartFileUploadFlow(file_token, std::move(input_data), /*image_options=*/std::nullopt); + WaitForClusterInfo(); + WaitForFileUpload(file_token, lens::MimeType::kPdf); #if BUILDFLAG(IS_IOS)
diff --git a/components/exo/shell_surface_base.cc b/components/exo/shell_surface_base.cc index 3d5a198..3e0e82a 100644 --- a/components/exo/shell_surface_base.cc +++ b/components/exo/shell_surface_base.cc
@@ -339,6 +339,10 @@ return true; } + if (shell_surface_->IsPointWithinOverlay(local_point)) { + return true; + } + aura::Window::ConvertPointToTarget(window, surface->window(), &local_point); return surface->HitTest(local_point); } @@ -1131,6 +1135,19 @@ UpdateResizability(); } +bool ShellSurfaceBase::IsPointWithinOverlay(const gfx::Point& point) const { + if (!HasOverlay()) { + return false; + } + + gfx::Point point_in_overlay = point; + aura::Window::ConvertPointToTarget(widget_->GetNativeWindow(), + overlay_widget_->GetNativeWindow(), + &point_in_overlay); + + return overlay_widget_->GetNativeWindow()->ContainsPoint(point_in_overlay); +} + //////////////////////////////////////////////////////////////////////////////// // SurfaceDelegate overrides:
diff --git a/components/exo/shell_surface_base.h b/components/exo/shell_surface_base.h index f8e668d..90b3b9b4 100644 --- a/components/exo/shell_surface_base.h +++ b/components/exo/shell_surface_base.h
@@ -234,6 +234,11 @@ bool HasOverlay() const { return !!overlay_widget_; } + // Returns true if the given |point| is within the bounds of the overlay + // widget. |point| is expected to be in the coordinate space of the + // ShellSurfaceBase's window. + bool IsPointWithinOverlay(const gfx::Point& point) const; + // Set specific orientation lock for this surface. When this surface is in // foreground and the display can be rotated (e.g. tablet mode), apply the // behavior defined by |orientation_lock|. See more details in
diff --git a/components/exo/shell_surface_unittest.cc b/components/exo/shell_surface_unittest.cc index 1947a083..29105f0 100644 --- a/components/exo/shell_surface_unittest.cc +++ b/components/exo/shell_surface_unittest.cc
@@ -3599,6 +3599,136 @@ } } +TEST_F(ShellSurfaceTest, OverlayEventTargeting) { + auto shell_surface = test::ShellSurfaceBuilder({100, 100}) + .SetFrame(SurfaceFrameType::NORMAL) + .BuildShellSurface(); + shell_surface->GetWidget()->GetNativeWindow()->SetProperty( + aura::client::kSkipImeProcessing, true); + + EXPECT_FALSE(shell_surface->HasOverlay()); + + aura::Window* window = shell_surface->GetWidget()->GetNativeWindow(); + aura::Window* parent_window = window->parent(); + aura::WindowTargeter parent_targeter; + int frame_height = views::GetCaptionButtonLayoutSize( + views::CaptionButtonLayoutSize::kNonBrowserCaption) + .height(); + + // Test case 1: Overlay does NOT overlap the frame. + { + ShellSurfaceBase::OverlayParams params(std::make_unique<views::View>()); + params.overlaps_frame = false; + shell_surface->AddOverlay(std::move(params)); + + EXPECT_TRUE(shell_surface->HasOverlay()); + + // Point inside the frame (above the overlay). + gfx::Point point_in_frame(10, frame_height - 1); + gfx::Point point_in_parent_frame = point_in_frame; + aura::Window::ConvertPointToTarget(window, parent_window, + &point_in_parent_frame); + + ui::MouseEvent event_in_frame(ui::EventType::kMousePressed, + point_in_parent_frame, point_in_parent_frame, + base::TimeTicks::Now(), 0, 0); + ui::EventTarget* target_in_frame = + parent_targeter.FindTargetForEvent(parent_window, &event_in_frame); + EXPECT_TRUE(target_in_frame); + + // The event should NOT be targeted to the overlay widget's window. + EXPECT_FALSE(shell_surface->overlay_widget_for_testing() + ->GetNativeWindow() + ->Contains(static_cast<aura::Window*>(target_in_frame))); + + // Point inside the overlay (near the bottom). + gfx::Point point_in_overlay(10, 100 - 5); + gfx::Point point_in_parent_overlay = point_in_overlay; + aura::Window::ConvertPointToTarget(window, parent_window, + &point_in_parent_overlay); + + ui::MouseEvent event_in_overlay( + ui::EventType::kMousePressed, point_in_parent_overlay, + point_in_parent_overlay, base::TimeTicks::Now(), 0, 0); + ui::EventTarget* target_in_overlay = + parent_targeter.FindTargetForEvent(parent_window, &event_in_overlay); + EXPECT_TRUE(target_in_overlay); + // The event should be targeted exactly to the overlay widget's window. + EXPECT_EQ(shell_surface->overlay_widget_for_testing()->GetNativeWindow(), + static_cast<aura::Window*>(target_in_overlay)); + + shell_surface->RemoveOverlay(); + } + + // Test case 2: Overlay overlaps the frame. + { + ShellSurfaceBase::OverlayParams params(std::make_unique<views::View>()); + params.overlaps_frame = true; + shell_surface->AddOverlay(std::move(params)); + EXPECT_TRUE(shell_surface->HasOverlay()); + + // Point inside the frame (which is now covered by the overlay). + gfx::Point point_in_frame(10, frame_height - 1); + gfx::Point point_in_parent_frame = point_in_frame; + aura::Window::ConvertPointToTarget(window, parent_window, + &point_in_parent_frame); + + ui::MouseEvent event_in_frame(ui::EventType::kMousePressed, + point_in_parent_frame, point_in_parent_frame, + base::TimeTicks::Now(), 0, 0); + ui::EventTarget* target_in_frame = + parent_targeter.FindTargetForEvent(parent_window, &event_in_frame); + EXPECT_TRUE(target_in_frame); + // The event SHOULD be targeted exactly to the overlay widget's window. + EXPECT_EQ(shell_surface->overlay_widget_for_testing()->GetNativeWindow(), + static_cast<aura::Window*>(target_in_frame)); + + shell_surface->RemoveOverlay(); + } +} + +TEST_F(ShellSurfaceTest, OverlayEventTargetingWithEmptyRootSurface) { + // Create a shell surface with a 1x1 root surface to simulate the + // ArcGhostWindowView scenario where the Wayland surface hasn't fully + // initialized but the overlay is shown. + auto shell_surface = test::ShellSurfaceBuilder({1, 1}) + .SetMinimumSize(gfx::Size(100, 100)) + .SetFrame(SurfaceFrameType::NORMAL) + .BuildShellSurface(); + shell_surface->GetWidget()->GetNativeWindow()->SetProperty( + aura::client::kSkipImeProcessing, true); + + aura::Window* window = shell_surface->GetWidget()->GetNativeWindow(); + aura::Window* parent_window = window->parent(); + aura::WindowTargeter parent_targeter; + + ShellSurfaceBase::OverlayParams params(std::make_unique<views::View>()); + params.overlaps_frame = false; + shell_surface->AddOverlay(std::move(params)); + EXPECT_TRUE(shell_surface->HasOverlay()); + + // Point inside the overlay, but way outside the 1x1 root surface. + // The overlay's bounds are based on the widget's bounds (100x100), not the + // root surface's bounds (1x1). + gfx::Point point_in_overlay(50, 50); + gfx::Point point_in_parent_overlay = point_in_overlay; + aura::Window::ConvertPointToTarget(window, parent_window, + &point_in_parent_overlay); + + ui::MouseEvent event_in_overlay( + ui::EventType::kMousePressed, point_in_parent_overlay, + point_in_parent_overlay, base::TimeTicks::Now(), 0, 0); + ui::EventTarget* target_in_overlay = + parent_targeter.FindTargetForEvent(parent_window, &event_in_overlay); + EXPECT_TRUE(target_in_overlay); + + // The event should be targeted exactly to the overlay widget's window, + // even though the root surface bounds are 1x1, because the overlay bounds + // are based on the widget bounds. + EXPECT_EQ(shell_surface->overlay_widget_for_testing()->GetNativeWindow(), + static_cast<aura::Window*>(target_in_overlay)); +} + TEST_F(ShellSurfaceTest, Overlay) { auto shell_surface = test::ShellSurfaceBuilder({100, 100}).BuildShellSurface();
diff --git a/components/infobars/android/java/src/org/chromium/components/infobars/InfoBar.java b/components/infobars/android/java/src/org/chromium/components/infobars/InfoBar.java index e68ad32..a65a88d 100644 --- a/components/infobars/android/java/src/org/chromium/components/infobars/InfoBar.java +++ b/components/infobars/android/java/src/org/chromium/components/infobars/InfoBar.java
@@ -196,7 +196,7 @@ if (mView == null) return ""; CharSequence title = null; - TextView messageView = (TextView) mView.findViewById(R.id.infobar_message); + TextView messageView = mView.findViewById(R.id.infobar_message); if (messageView != null) { title = messageView.getText(); }
diff --git a/components/infobars/android/java/src/org/chromium/components/infobars/InfoBarControlLayout.java b/components/infobars/android/java/src/org/chromium/components/infobars/InfoBarControlLayout.java index a3de104..0b04b7a 100644 --- a/components/infobars/android/java/src/org/chromium/components/infobars/InfoBarControlLayout.java +++ b/components/infobars/android/java/src/org/chromium/components/infobars/InfoBarControlLayout.java
@@ -342,10 +342,10 @@ inflateLayout(getContext(), R.layout.infobar_control_icon_with_title, this); addView(layout, new ControlLayoutParams()); - ImageView iconView = (ImageView) layout.findViewById(R.id.control_title_icon); + ImageView iconView = layout.findViewById(R.id.control_title_icon); iconView.setImageResource(iconResourceId); - TextView titleView = (TextView) layout.findViewById(R.id.control_title); + TextView titleView = layout.findViewById(R.id.control_title); titleView.setText(titleMessage); titleView.setTextSize( TypedValue.COMPLEX_UNIT_PX, @@ -407,20 +407,20 @@ getContext(), R.layout.infobar_control_icon_with_description, this); addView(layout, new ControlLayoutParams()); - ImageView iconView = (ImageView) layout.findViewById(R.id.control_icon); + ImageView iconView = layout.findViewById(R.id.control_icon); iconView.setImageResource(iconResourceId); if (iconColorId != 0) { iconView.setColorFilter(getContext().getColor(iconColorId)); } // The primary message text is always displayed. - TextView primaryView = (TextView) layout.findViewById(R.id.control_message); + TextView primaryView = layout.findViewById(R.id.control_message); primaryView.setText(primaryMessage); primaryView.setTextSize( TypedValue.COMPLEX_UNIT_PX, getContext().getResources().getDimension(resourceId)); // The secondary message text is optional. - TextView secondaryView = (TextView) layout.findViewById(R.id.control_secondary_message); + TextView secondaryView = layout.findViewById(R.id.control_secondary_message); if (secondaryMessage == null) { layout.removeView(secondaryView); } else { @@ -460,20 +460,20 @@ getContext(), R.layout.infobar_control_icon_with_description, this); addView(layout, new ControlLayoutParams()); - ImageView iconView = (ImageView) layout.findViewById(R.id.control_icon); + ImageView iconView = layout.findViewById(R.id.control_icon); iconView.setImageBitmap(iconBitmap); if (iconColorId != 0) { iconView.setColorFilter(getContext().getColor(iconColorId)); } // The primary message text is always displayed. - TextView primaryView = (TextView) layout.findViewById(R.id.control_message); + TextView primaryView = layout.findViewById(R.id.control_message); primaryView.setText(primaryMessage); primaryView.setTextSize( TypedValue.COMPLEX_UNIT_PX, getContext().getResources().getDimension(resourceId)); // The secondary message text is optional. - TextView secondaryView = (TextView) layout.findViewById(R.id.control_secondary_message); + TextView secondaryView = layout.findViewById(R.id.control_secondary_message); if (secondaryMessage == null) { layout.removeView(secondaryView); } else { @@ -510,7 +510,7 @@ (LinearLayout) inflateLayout(getContext(), R.layout.infobar_control_toggle, this); addView(switchLayout, new ControlLayoutParams()); - ImageView iconView = (ImageView) switchLayout.findViewById(R.id.control_icon); + ImageView iconView = switchLayout.findViewById(R.id.control_icon); if (iconResourceId == 0) { switchLayout.removeView(iconView); } else { @@ -520,7 +520,7 @@ } } - TextView messageView = (TextView) switchLayout.findViewById(R.id.control_message); + TextView messageView = switchLayout.findViewById(R.id.control_message); messageView.setText(toggleMessage); SwitchCompat switchView =
diff --git a/components/media_router/browser/android/java/src/org/chromium/components/media_router/MediaRouteChooserDialogManager.java b/components/media_router/browser/android/java/src/org/chromium/components/media_router/MediaRouteChooserDialogManager.java index 06e2de1..a281afa 100644 --- a/components/media_router/browser/android/java/src/org/chromium/components/media_router/MediaRouteChooserDialogManager.java +++ b/components/media_router/browser/android/java/src/org/chromium/components/media_router/MediaRouteChooserDialogManager.java
@@ -93,7 +93,7 @@ public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - ListView listView = (ListView) findViewById(R.id.mr_chooser_list); + ListView listView = findViewById(R.id.mr_chooser_list); if (listView != null) { listView.setOnItemClickListener(Fragment.this::onItemClick); recordSinkCountWithDelay(); @@ -109,7 +109,7 @@ new Runnable() { @Override public void run() { - ListView listView = (ListView) findViewById(R.id.mr_chooser_list); + ListView listView = findViewById(R.id.mr_chooser_list); if (listView != null) { MediaRouteUmaRecorder.recordDeviceCountWithDelay( listView.getCount());
diff --git a/components/media_router/browser/android/java/src/org/chromium/components/media_router/caf/remoting/CafExpandedControllerActivity.java b/components/media_router/browser/android/java/src/org/chromium/components/media_router/caf/remoting/CafExpandedControllerActivity.java index c983fbc..3aa22e92 100644 --- a/components/media_router/browser/android/java/src/org/chromium/components/media_router/caf/remoting/CafExpandedControllerActivity.java +++ b/components/media_router/browser/android/java/src/org/chromium/components/media_router/caf/remoting/CafExpandedControllerActivity.java
@@ -139,7 +139,7 @@ // requestWindowFeature must be called before adding content. setContentView(R.layout.expanded_cast_controller); - ViewGroup rootView = (ViewGroup) findViewById(android.R.id.content); + ViewGroup rootView = findViewById(android.R.id.content); rootView.setBackgroundColor(Color.BLACK); // Create and initialize the media control UI.
diff --git a/components/metrics/daily_event.cc b/components/metrics/daily_event.cc index 6491fc8d..39bfca70 100644 --- a/components/metrics/daily_event.cc +++ b/components/metrics/daily_event.cc
@@ -100,6 +100,7 @@ void DailyEvent::OnInterval(base::Time now, IntervalType type) { DCHECK(!now.is_null()); + DCHECK(pref_service_); last_fired_ = now; pref_service_->SetInt64(pref_name_, last_fired_.since_origin().InMicroseconds());
diff --git a/components/metrics/daily_event.h b/components/metrics/daily_event.h index 85c8661..9d9c5aa 100644 --- a/components/metrics/daily_event.h +++ b/components/metrics/daily_event.h
@@ -88,10 +88,10 @@ // Handles an interval elapsing because of |type|. void OnInterval(base::Time now, IntervalType type); - // A weak pointer to the PrefService object to read and write preferences + // Non-owning pointer to the PrefService object to read and write preferences // from. Calling code should ensure this object continues to exist for the // lifetime of the DailyEvent object. - raw_ptr<PrefService, LeakedDanglingUntriaged> pref_service_; + raw_ptr<PrefService> pref_service_; // The name of the preference to store the last fired time in. // Calling code should ensure this outlives the DailyEvent.
diff --git a/components/metrics/daily_event_unittest.cc b/components/metrics/daily_event_unittest.cc index bf80a62..3d4ee63 100644 --- a/components/metrics/daily_event_unittest.cc +++ b/components/metrics/daily_event_unittest.cc
@@ -125,4 +125,22 @@ EXPECT_EQ(DailyEvent::IntervalType::DAY_ELAPSED, observer_->type()); } +// Regression test mimicking the OOMKillsMonitor singleton pattern where the +// DailyEvent is owned via unique_ptr and must be destroyed before PrefService. +TEST(DailyEventDanglingPtrTest, SingletonPatternReset) { + base::test::TaskEnvironment env; + auto prefs = std::make_unique<TestingPrefServiceSimple>(); + DailyEvent::RegisterPref(prefs->registry(), kTestPrefName); + + // Simulate singleton: DailyEvent on the heap, outliving PrefService. + auto event = + std::make_unique<DailyEvent>(prefs.get(), kTestPrefName, kTestMetricName); + event->CheckInterval(); + + // Reset (destroy) DailyEvent before PrefService destruction prevents + // dangling. + event.reset(); + prefs.reset(); +} + } // namespace metrics
diff --git a/components/optimization_guide/content/browser/page_content_proto_util.cc b/components/optimization_guide/content/browser/page_content_proto_util.cc index 8cefc4b..d31bde1 100644 --- a/components/optimization_guide/content/browser/page_content_proto_util.cc +++ b/components/optimization_guide/content/browser/page_content_proto_util.cc
@@ -892,12 +892,24 @@ } } +int GetAccessibilityFocusedNodeId( + const blink::mojom::AIPageContentFrameData& frame_data) { + if (!frame_data.frame_interaction_info) { + return kInvalidDOMNodeId; + } + + return frame_data.frame_interaction_info->accessibility_focused_dom_node_id + .value_or(kInvalidDOMNodeId); +} + void ConvertFrameData( const RenderFrameInfo& render_frame_info, const blink::mojom::AIPageContentFrameData& mojom_frame_data, optimization_guide::proto::FrameData* proto_frame_data, blink::mojom::PageMetadata& metadata, - FrameTokenSet& frame_token_set) { + FrameTokenSet& frame_token_set, + optimization_guide::proto::PageInteractionInfo* + proto_page_interaction_info) { ConvertFrameMetadata(GetURLForFrameMetadata(render_frame_info.url, render_frame_info.source_origin), mojom_frame_data, metadata); @@ -940,6 +952,19 @@ for (const auto& tool : mojom_frame_data.script_tools) { ConvertScriptTool(*tool, proto_frame_data->add_script_tools()); } + + // Accessibility focus is tracked globally in the browser, so it should be set + // in only one frame. In edge cases, e.g. race condition between updating + // accessibility focus and page content extraction in the renderer, we + // prioritize the main frame or the first traversed iframe. + optimization_guide::proto::DocumentIdentifier* + proto_accessibility_focused_frame = + proto_page_interaction_info->mutable_accessibility_focused_frame(); + if (proto_accessibility_focused_frame->serialized_token().empty() && + GetAccessibilityFocusedNodeId(mojom_frame_data) != kInvalidDOMNodeId) { + *proto_accessibility_focused_frame = + proto_frame_data->document_identifier(); + } } void ConvertRedactionReason( @@ -969,16 +994,6 @@ proto_iframe_data->mutable_redacted_frame_metadata()); } -int GetAccessibilityFocusedNodeId( - const blink::mojom::AIPageContentFrameData& frame_data) { - if (!frame_data.frame_interaction_info) { - return kInvalidDOMNodeId; - } - - return frame_data.frame_interaction_info->accessibility_focused_dom_node_id - .value_or(kInvalidDOMNodeId); -} - // Contains the information that remains the same throughout the tree // recursion for ConvertAIPageContentToProto. class Converter { @@ -1047,6 +1062,10 @@ "compromised renderer: iframe is not a child of the current frame"); } + optimization_guide::proto::PageInteractionInfo* + proto_page_interaction_info = + page_content_proto().mutable_page_interaction_info(); + auto* proto_iframe_data = proto_node->mutable_content_attributes()->mutable_iframe_data(); if (frame_token.Is<blink::RemoteFrameToken>()) { @@ -1086,16 +1105,18 @@ *page_content->frame_data->popup, *render_frame_info)); } + ConvertIframeData(*render_frame_info, iframe_data, + /*mojom_local_frame_data=*/ + *page_content->frame_data.get(), + proto_iframe_data, + proto_page_interaction_info); + RETURN_IF_ERROR(ConvertNode( render_frame_info->global_frame_token, *page_content->root_node, GetAccessibilityFocusedNodeId(*page_content->frame_data), proto_child_frame_node)); - ConvertIframeData(*render_frame_info, iframe_data, - /*mojom_local_frame_data=*/ - *page_content->frame_data.get(), - proto_iframe_data); return base::ok(); }, [&](const blink::mojom::RedactedFrameMetadataPtr& r) mutable @@ -1125,7 +1146,7 @@ ConvertIframeData(*render_frame_info, iframe_data, /*mojom_local_frame_data=*/ *iframe_data.content->get_local_frame_data(), - proto_iframe_data); + proto_iframe_data, proto_page_interaction_info); accessibility_focused_node_id_for_children = GetAccessibilityFocusedNodeId( *iframe_data.content->get_local_frame_data()); @@ -1258,10 +1279,12 @@ const RenderFrameInfo& render_frame_info, const blink::mojom::AIPageContentIframeData& mojom_iframe_data, const blink::mojom::AIPageContentFrameData& mojom_local_frame_data, - optimization_guide::proto::IframeData* proto_iframe_data) { + optimization_guide::proto::IframeData* proto_iframe_data, + optimization_guide::proto::PageInteractionInfo* + proto_page_interaction_info) { ConvertFrameData(render_frame_info, mojom_local_frame_data, proto_iframe_data->mutable_frame_data(), page_metadata(), - *frame_token_set_); + *frame_token_set_, proto_page_interaction_info); } // Password boxes are handled by AddRendererPasswordRedactionBoxes(). This @@ -1396,9 +1419,21 @@ return base::unexpected("could not find RenderFrameInfo for main frame"); } + optimization_guide::proto::PageInteractionInfo* proto_page_interaction_info = + page_content_result.proto.mutable_page_interaction_info(); + + // Explicitly set accessibility_focused_frame to an empty string as a + // negative signal. The presence of this field (even if empty) tells the + // server that we have already checked all frames for accessibility focus. If + // it were omitted, the consumers might fall back to an inefficient lookup to + // maintain backward compatibility. + proto_page_interaction_info->mutable_accessibility_focused_frame() + ->set_serialized_token(""); + ConvertFrameData(*render_frame_info, *main_frame_page_content->frame_data, page_content_result.proto.mutable_main_frame_data(), - *page_content_result.metadata, frame_token_set); + *page_content_result.metadata, frame_token_set, + proto_page_interaction_info); Converter converter(std::move(main_frame_options), page_content_map, get_render_frame_info, frame_token_set, @@ -1411,9 +1446,8 @@ page_content_result.proto.mutable_root_node())); if (main_frame_page_content->page_interaction_info) { - ConvertPageInteractionInfo( - *main_frame_page_content->page_interaction_info, - page_content_result.proto.mutable_page_interaction_info()); + ConvertPageInteractionInfo(*main_frame_page_content->page_interaction_info, + proto_page_interaction_info); } auto mode = optimization_guide::proto::ANNOTATED_PAGE_CONTENT_MODE_DEFAULT;
diff --git a/components/optimization_guide/content/browser/page_content_proto_util_unittest.cc b/components/optimization_guide/content/browser/page_content_proto_util_unittest.cc index 96d744f..273bf54 100644 --- a/components/optimization_guide/content/browser/page_content_proto_util_unittest.cc +++ b/components/optimization_guide/content/browser/page_content_proto_util_unittest.cc
@@ -1031,6 +1031,123 @@ EXPECT_EQ(page_interaction_info.mouse_position().y(), 20); } +TEST_F(PageContentProtoUtilTest, AccessibilityFocusedFrame_MainFrame) { + auto main_frame_token = CreateFrameToken(); + auto root_content = CreatePageContent(); + root_content->frame_data->frame_interaction_info + ->accessibility_focused_dom_node_id = 123; + + AIPageContentMap page_content_map; + page_content_map[main_frame_token] = std::move(root_content); + + auto get_render_frame_info = base::BindLambdaForTesting( + [&](int, blink::FrameToken token) -> std::optional<RenderFrameInfo> { + RenderFrameInfo render_frame_info; + render_frame_info.global_frame_token = main_frame_token; + render_frame_info.serialized_server_token = token.ToString(); + return render_frame_info; + }); + + AIPageContentResult page_content; + FrameTokenSet frame_token_set; + EXPECT_TRUE(ConvertAIPageContentToProto( + blink::mojom::AIPageContentOptions::New(), main_frame_token, + page_content_map, get_render_frame_info, frame_token_set, + page_content) + .has_value()); + + const auto& page_interaction_info = + page_content.proto.page_interaction_info(); + ASSERT_TRUE(page_interaction_info.has_accessibility_focused_frame()); + EXPECT_EQ( + page_interaction_info.accessibility_focused_frame().serialized_token(), + main_frame_token.frame_token.ToString()); +} + +TEST_F(PageContentProtoUtilTest, AccessibilityFocusedFrame_Iframe) { + auto main_frame_token = CreateFrameToken(); + auto root_content = CreatePageContent(); + root_content->root_node->children_nodes.emplace_back( + CreateContentNode(blink::mojom::AIPageContentAttributeType::kIframe)); + + auto iframe_token = CreateFrameToken(); + auto iframe_data = blink::mojom::AIPageContentIframeData::New(); + iframe_data->frame_token = iframe_token.frame_token; + auto iframe_page_content = CreatePageContent(); + iframe_page_content->frame_data->frame_interaction_info + ->accessibility_focused_dom_node_id = 123; + iframe_data->content = + blink::mojom::AIPageContentIframeContent::NewLocalFrameData( + std::move(iframe_page_content->frame_data)); + + root_content->root_node->children_nodes.back() + ->content_attributes->iframe_data = std::move(iframe_data); + + AIPageContentMap page_content_map; + page_content_map[main_frame_token] = std::move(root_content); + + auto get_render_frame_info = base::BindLambdaForTesting( + [&](int, blink::FrameToken token) -> std::optional<RenderFrameInfo> { + RenderFrameInfo render_frame_info; + if (token == main_frame_token.frame_token) { + render_frame_info.global_frame_token = main_frame_token; + } else { + render_frame_info.global_frame_token = iframe_token; + } + render_frame_info.source_origin = + url::Origin::Create(GURL("https://example.com")); + render_frame_info.url = GURL("https://example.com"); + render_frame_info.serialized_server_token = token.ToString(); + return render_frame_info; + }); + + AIPageContentResult page_content; + FrameTokenSet frame_token_set; + EXPECT_TRUE(ConvertAIPageContentToProto( + blink::mojom::AIPageContentOptions::New(), main_frame_token, + page_content_map, get_render_frame_info, frame_token_set, + page_content) + .has_value()); + + const auto& page_interaction_info = + page_content.proto.page_interaction_info(); + ASSERT_TRUE(page_interaction_info.has_accessibility_focused_frame()); + EXPECT_EQ( + page_interaction_info.accessibility_focused_frame().serialized_token(), + iframe_token.frame_token.ToString()); +} + +TEST_F(PageContentProtoUtilTest, AccessibilityFocusedFrame_None) { + auto main_frame_token = CreateFrameToken(); + auto root_content = CreatePageContent(); + + AIPageContentMap page_content_map; + page_content_map[main_frame_token] = std::move(root_content); + + auto get_render_frame_info = base::BindLambdaForTesting( + [&](int, blink::FrameToken token) -> std::optional<RenderFrameInfo> { + RenderFrameInfo render_frame_info; + render_frame_info.global_frame_token = main_frame_token; + render_frame_info.serialized_server_token = token.ToString(); + return render_frame_info; + }); + + AIPageContentResult page_content; + FrameTokenSet frame_token_set; + EXPECT_TRUE(ConvertAIPageContentToProto( + blink::mojom::AIPageContentOptions::New(), main_frame_token, + page_content_map, get_render_frame_info, frame_token_set, + page_content) + .has_value()); + + const auto& page_interaction_info = + page_content.proto.page_interaction_info(); + ASSERT_TRUE(page_interaction_info.has_accessibility_focused_frame()); + EXPECT_TRUE(page_interaction_info.accessibility_focused_frame() + .serialized_token() + .empty()); +} + TEST_F(PageContentProtoUtilTest, ConvertMainFrameInteractionInfo) { auto root_content = CreatePageContent();
diff --git a/components/optimization_guide/internal b/components/optimization_guide/internal index 5f94267..41b8d85 160000 --- a/components/optimization_guide/internal +++ b/components/optimization_guide/internal
@@ -1 +1 @@ -Subproject commit 5f94267a383c538ef982fce8044811c5a6cc33aa +Subproject commit 41b8d85727afeb00dbf4bad0f040b0e4e1374ec3
diff --git a/components/optimization_guide/proto/features/common_quality_data.proto b/components/optimization_guide/proto/features/common_quality_data.proto index a0d5cee..798a16f 100644 --- a/components/optimization_guide/proto/features/common_quality_data.proto +++ b/components/optimization_guide/proto/features/common_quality_data.proto
@@ -1323,6 +1323,9 @@ } } +// An origin is a combination of a protocol (scheme), host, and port. See +// https://web.dev/articles/same-site-same-origin. +// // Next ID: 4 message Origin { Protocol protocol = 1 [features = { field_presence: EXPLICIT }]; @@ -1333,6 +1336,10 @@ int32 port = 3 [features = { field_presence: EXPLICIT }]; } +// A site is a protocol (scheme) and an eTLD+1. Note that computing an eTLD+1 +// relies on the Public Suffix List and is not necessarily the same as the host +// in an origin. See https://web.dev/articles/same-site-same-origin. +// // Next ID: 3 message Site { Protocol protocol = 1 [features = { field_presence: EXPLICIT }];
diff --git a/components/optimization_guide/proto/features/password_change_submission.proto b/components/optimization_guide/proto/features/password_change_submission.proto index c0f722cf..2626d51 100644 --- a/components/optimization_guide/proto/features/password_change_submission.proto +++ b/components/optimization_guide/proto/features/password_change_submission.proto
@@ -348,6 +348,9 @@ // order to complete the flow, This was detected by the LLM. // This can be due to captcha, instructions sent by email, OTP or 2FA. USER_INTERVENTION_NEEDED = 14; + + // The step took too long to complete and an error was thrown. + TIME_OUT = 15; } }
diff --git a/components/page_content_annotations/content/page_context_fetcher.cc b/components/page_content_annotations/content/page_context_fetcher.cc index c54c7f8..2d4009f 100644 --- a/components/page_content_annotations/content/page_context_fetcher.cc +++ b/components/page_content_annotations/content/page_context_fetcher.cc
@@ -304,6 +304,9 @@ const SkBitmap& bitmap, const std::vector<gfx::Rect>& visible_bounding_boxes_for_redaction, SkColor4f redaction_color) { + base::UmaHistogramBoolean("Glic.PageContextFetcher.ScreenshotRedacted", + !visible_bounding_boxes_for_redaction.empty()); + if (visible_bounding_boxes_for_redaction.empty()) { return bitmap; }
diff --git a/components/page_content_annotations/content/page_context_fetcher_unittest.cc b/components/page_content_annotations/content/page_context_fetcher_unittest.cc index 9f9ebb8..c7e76de6 100644 --- a/components/page_content_annotations/content/page_context_fetcher_unittest.cc +++ b/components/page_content_annotations/content/page_context_fetcher_unittest.cc
@@ -7,6 +7,7 @@ #include <string> #include <vector> +#include "base/test/metrics/histogram_tester.h" #include "base/types/expected.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/core/SkBitmap.h" @@ -16,6 +17,7 @@ namespace page_content_annotations { TEST(PageContextFetcherTest, RedactScreenshotOnWorkerThread) { + base::HistogramTester histograms; SkBitmap bitmap; bitmap.allocN32Pixels(100, 100); bitmap.eraseColor(SK_ColorBLUE); @@ -38,9 +40,13 @@ // Check a pixel that SHOULD be redacted (becomes red). EXPECT_EQ(redacted->getColor(15, 15), SK_ColorRED); EXPECT_EQ(redacted->getColor(25, 25), SK_ColorRED); + + histograms.ExpectUniqueSample("Glic.PageContextFetcher.ScreenshotRedacted", + true, 1); } TEST(PageContextFetcherTest, RedactScreenshotOnWorkerThreadNoRedaction) { + base::HistogramTester histograms; SkBitmap bitmap; bitmap.allocN32Pixels(100, 100); bitmap.eraseColor(SK_ColorBLUE); @@ -57,6 +63,9 @@ // Verify the optimization: the original bitmap should be returned without // unnecessary copies when no redaction is performed. EXPECT_EQ(bitmap.getPixels(), redacted->getPixels()); + + histograms.ExpectUniqueSample("Glic.PageContextFetcher.ScreenshotRedacted", + false, 1); } } // namespace page_content_annotations
diff --git a/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier_delegate.cc b/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier_delegate.cc index c3ccea50..de9df34a 100644 --- a/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier_delegate.cc +++ b/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier_delegate.cc
@@ -171,6 +171,12 @@ void PhishingClassifierDelegate::DidCommitProvisionalLoad( ui::PageTransition transition) { blink::WebLocalFrame* frame = render_frame()->GetWebFrame(); + // A new page is starting to load, and if we had a browser request waiting, we + // log that if it never got the chance to classify. + if (is_phishing_detection_running_ && !is_classifying_) { + RecordEvent( + SBPhishingClassifierEvent::kNewPageLoadWhileBrowserRequestWaitsForLoad); + } // A new page is starting to load, so cancel classificaiton, and reset URL. CancelPendingClassification(CancelClassificationReason::kNavigateAway); renderer_layout_finished_ = false; @@ -194,6 +200,7 @@ RecordEvent( SBPhishingClassifierEvent::kPhishingClassifierPageFinishedLoading); + renderer_layout_finished_ = true; last_finished_load_url_ = render_frame()->GetWebFrame()->GetDocument().Url(); @@ -260,7 +267,6 @@ base::BindOnce(&PhishingClassifierDelegate::MaybeStartClassification, weak_factory_.GetWeakPtr()), base::Seconds(kCsdClassificationDelay.Get())); - } else { MaybeStartClassification(); } @@ -283,6 +289,8 @@ if (classifier_->is_ready()) { classifier_->CancelPendingClassification(); } + is_phishing_detection_running_ = false; + last_url_received_from_browser_ = GURL(); awaiting_retry_ = false; request_type_ = std::nullopt; } @@ -340,14 +348,23 @@ void PhishingClassifierDelegate::MaybeStartClassification() { // We can begin phishing classification when the following conditions are // met: - // 1. There's no current classification going on. - // 2. A Scorer has been created. - // 3. The browser has sent a StartPhishingDetection message for the + // 1. We still actually have a request to answer. + // 2. There's no current classification going on. + // 3. A Scorer has been created. + // 4. The browser has sent a StartPhishingDetection message for the // current toplevel URL. - // 4. The page has finished loading. - // 5. The load is a new navigation (not a session history navigation). - // 6. The toplevel URL has not already been classified. - // + // 5. The page has finished loading. + // 6. The load is a new navigation (not a session history navigation). + // 7. The toplevel URL has not already been classified. + + // It is possible that these two variables are reset when + // MaybeStartClassification() is called after a delay with the feature study + // ClientSideDetectionNewObservers. Check again that there is actually a + // request to respond to. + if (!is_phishing_detection_running_ || !renderer_layout_finished_) { + return; + } + // We shouldn't hit this ever, but for sanity check, we should return when // this hits. if (is_classifying_) {
diff --git a/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier_delegate.h b/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier_delegate.h index 16a35d0..be09d910 100644 --- a/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier_delegate.h +++ b/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier_delegate.h
@@ -59,7 +59,10 @@ // There is an ongoing classification at the time of classification start // request. kOngoingClassificationAtAnotherClassificationRequest = 12, - kMaxValue = kOngoingClassificationAtAnotherClassificationRequest, + // A new page has loaded while the browser request has been waiting for page + // to finish loading in order to start classification. + kNewPageLoadWhileBrowserRequestWaitsForLoad = 13, + kMaxValue = kNewPageLoadWhileBrowserRequestWaitsForLoad, }; class PhishingClassifierDelegate : public content::RenderFrameObserver,
diff --git a/components/surface_embed/browser/surface_embed_host.cc b/components/surface_embed/browser/surface_embed_host.cc index b6025da2..a81ef96 100644 --- a/components/surface_embed/browser/surface_embed_host.cc +++ b/components/surface_embed/browser/surface_embed_host.cc
@@ -207,6 +207,12 @@ DetachConnector(); } +void SurfaceEmbedHost::RequestFocus() { + if (surface_embed_) { + surface_embed_->RequestFocus(); + } +} + bool SurfaceEmbedHost::IsAttachedForTesting() const { return child_contents_ != nullptr; }
diff --git a/components/surface_embed/browser/surface_embed_host.h b/components/surface_embed/browser/surface_embed_host.h index 1300c06f..57e2f66 100644 --- a/components/surface_embed/browser/surface_embed_host.h +++ b/components/surface_embed/browser/surface_embed_host.h
@@ -63,6 +63,7 @@ const viz::LocalSurfaceId& local_surface_id) override; void ChildProcessGone() override; void DetachedByHost() override; + void RequestFocus() override; bool IsAttachedForTesting() const override; // TODO: Update surface_embed.mojom so that this is an override of a virtual
diff --git a/components/surface_embed/browser/surface_embed_plugin_browsertest.cc b/components/surface_embed/browser/surface_embed_plugin_browsertest.cc index a0857106a..1fb207f9 100644 --- a/components/surface_embed/browser/surface_embed_plugin_browsertest.cc +++ b/components/surface_embed/browser/surface_embed_plugin_browsertest.cc
@@ -41,6 +41,9 @@ constexpr std::string_view kBlueBoxUrl = "/surface_embed/blue_box.html"; constexpr std::string_view kRedBoxUrl = "/surface_embed/red_box.html"; +constexpr std::string_view kFocusHarnessUrl = + "/surface_embed/focus_harness.html"; +constexpr std::string_view kInnerPageUrl = "/surface_embed/inner_page.html"; constexpr size_t kSingleEmbedCount = 1; constexpr float kTestDeviceScaleFactor = 1.5f; @@ -629,4 +632,36 @@ VerifyRedPixelInBounds(embed_bounds); } +IN_PROC_BROWSER_TEST_F(SurfaceEmbedBrowserTest, FocusByClick) { + NavigateToTestUrl(kFocusHarnessUrl); + + auto child_contents = CreateChildWebContents(); + NavigateChildToUrl(child_contents.get(), kInnerPageUrl); + content::ReadyForInputObserver(web_contents()).Wait(); + + AttachChildToEmbedWithId(child_contents.get(), "my_embed"); + + // Click to focus outer1 in the outer page. + content::SimulateMouseClickOrTapElementWithId(web_contents(), "outer1"); + + EXPECT_EQ(true, content::EvalJsAfterLifecycleUpdate(web_contents(), "", + "document.hasFocus()")); + EXPECT_EQ("outer1", content::EvalJsAfterLifecycleUpdate( + web_contents(), "", "document.activeElement.id")); + + // Click an <input id="inner"> in the inner page. This should change focus to + // the embed element in the outer page. + content::SimulateMouseClickOrTapElementWithId(child_contents.get(), "inner"); + + EXPECT_EQ(true, content::EvalJsAfterLifecycleUpdate(web_contents(), "", + "document.hasFocus()")); + EXPECT_EQ("my_embed", content::EvalJsAfterLifecycleUpdate( + web_contents(), "", "document.activeElement.id")); + // TODO(crbug.com/508638062): add expectations for the following behavior. + // 1. the inner page should has page focus. + // 2. the inner page's "inner" element should be the active element. + // 3. the child WebContents should be the focused WebContents, and should + // receive keyboard events. +} + } // namespace surface_embed
diff --git a/components/surface_embed/common/surface_embed.mojom b/components/surface_embed/common/surface_embed.mojom index 8d2e01d..14edfa3 100644 --- a/components/surface_embed/common/surface_embed.mojom +++ b/components/surface_embed/common/surface_embed.mojom
@@ -25,6 +25,9 @@ // Called when the browser detects that the renderer process hosting the // child this is embedding has crashed. ChildProcessGone(); + + // Requests focus for the <embed> element. + RequestFocus(); }; // Implemented by SurfaceEmbedHost in the browser process.
diff --git a/components/surface_embed/renderer/surface_embed_web_plugin.cc b/components/surface_embed/renderer/surface_embed_web_plugin.cc index 772cb99..f9a21af 100644 --- a/components/surface_embed/renderer/surface_embed_web_plugin.cc +++ b/components/surface_embed/renderer/surface_embed_web_plugin.cc
@@ -15,6 +15,7 @@ #include "third_party/blink/public/platform/browser_interface_broker_proxy.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/public/web/web_document.h" +#include "third_party/blink/public/web/web_element.h" #include "third_party/blink/public/web/web_frame_widget.h" #include "third_party/blink/public/web/web_local_frame.h" #include "third_party/blink/public/web/web_plugin_container.h" @@ -357,6 +358,12 @@ container_->ScheduleAnimation(); } +void SurfaceEmbedWebPlugin::RequestFocus() { + if (container_) { + container_->GetElement().Focus(); + } +} + scoped_refptr<cc::DisplayItemList> SurfaceEmbedWebPlugin::PaintContentsToDisplayList() { blink::WebFrameWidget* ancestor_widget =
diff --git a/components/surface_embed/renderer/surface_embed_web_plugin.h b/components/surface_embed/renderer/surface_embed_web_plugin.h index aeb68f5..5af467d 100644 --- a/components/surface_embed/renderer/surface_embed_web_plugin.h +++ b/components/surface_embed/renderer/surface_embed_web_plugin.h
@@ -90,6 +90,7 @@ void UpdateLocalSurfaceIdFromChild( const ::viz::LocalSurfaceId& local_surface_id) override; void ChildProcessGone() override; + void RequestFocus() override; // cc::ContentLayerClient, used only if we're painting a sad plugin. scoped_refptr<cc::DisplayItemList> PaintContentsToDisplayList() override;
diff --git a/components/test/data/surface_embed/focus_harness.html b/components/test/data/surface_embed/focus_harness.html new file mode 100644 index 0000000..3678aee --- /dev/null +++ b/components/test/data/surface_embed/focus_harness.html
@@ -0,0 +1,33 @@ +<!DOCTYPE html> +<html> +<head> +<style> +body { + margin: 0; + padding: 0; +} +</style> +<script> + function createEmbed(contentId, embedId) { + const embed = document.createElement('embed'); + embed.setAttribute('data-content-id', contentId); + embed.setAttribute('type', 'application/x-chromium-surface-embed'); + embed.style.position = 'absolute'; + embed.style.left = '10px'; + embed.style.top = '50px'; + embed.style.width = '100px'; + embed.style.height = '100px'; + if (embedId !== undefined) { + embed.id = embedId; + } + + const outer2 = document.getElementById('outer2'); + document.body.insertBefore(embed, outer2); + } +</script> +</head> +<body> + <input id="outer1" style="position: absolute; top: 10px; left: 10px;"> + <input id="outer2" style="position: absolute; top: 170px; left: 10px;"> +</body> +</html>
diff --git a/components/test/data/surface_embed/inner_page.html b/components/test/data/surface_embed/inner_page.html new file mode 100644 index 0000000..2d70b35c --- /dev/null +++ b/components/test/data/surface_embed/inner_page.html
@@ -0,0 +1,17 @@ +<!DOCTYPE html> +<html> +<head> +<style> +html, body { + margin: 0; + padding: 0; + width: 100%; + height: 100%; + background-color: green; +} +</style> +</head> +<body> + <input id="inner" style="margin: 10px;"> +</body> +</html>
diff --git a/components/user_education/views/help_bubble_view.cc b/components/user_education/views/help_bubble_view.cc index 1853205..f1ff2db 100644 --- a/components/user_education/views/help_bubble_view.cc +++ b/components/user_education/views/help_bubble_view.cc
@@ -334,10 +334,10 @@ auto bubble = base::WrapUnique(new HelpBubbleView( delegate, anchor, std::move(params), std::move(event_relay))); auto* const bubble_ptr = bubble.get(); - auto* const widget = views::BubbleDialogDelegateView::CreateBubble( - std::move(bubble), views::Widget::InitParams::CLIENT_OWNS_WIDGET); + std::unique_ptr<views::Widget> widget = + views::BubbleDialogDelegate::CreateBubble(std::move(bubble)); bubble_ptr->InitializeAndShow(visible_arrow, show_active); - return HelpBubbleViewInfo(base::WrapUnique(widget), bubble_ptr); + return HelpBubbleViewInfo(std::move(widget), bubble_ptr); } HelpBubbleView::HelpBubbleView(
diff --git a/components/user_education/views/help_bubble_views_unittest.cc b/components/user_education/views/help_bubble_views_unittest.cc index af3514a..b617263 100644 --- a/components/user_education/views/help_bubble_views_unittest.cc +++ b/components/user_education/views/help_bubble_views_unittest.cc
@@ -93,10 +93,10 @@ auto bubble = std::make_unique<test::TestCustomHelpBubbleView>( anchor_view_, views::BubbleBorder::TOP_RIGHT); auto* const result = bubble.get(); - auto* const widget = views::BubbleDialogDelegateView::CreateBubble( - std::move(bubble), views::Widget::InitParams::CLIENT_OWNS_WIDGET); + std::unique_ptr<views::Widget> widget = + views::BubbleDialogDelegate::CreateBubble(std::move(bubble)); widget->Show(); - return HelpBubbleViewInfo(base::WrapUnique(widget), result); + return HelpBubbleViewInfo(std::move(widget), result); } views::View* anchor_view() const { return anchor_view_; }
diff --git a/components/web_modal/web_contents_modal_dialog_manager.cc b/components/web_modal/web_contents_modal_dialog_manager.cc index b897ea5..94340c80 100644 --- a/components/web_modal/web_contents_modal_dialog_manager.cc +++ b/components/web_modal/web_contents_modal_dialog_manager.cc
@@ -26,8 +26,22 @@ void WebContentsModalDialogManager::SetDelegate( WebContentsModalDialogManagerDelegate* d) { + // If the delegate hasn't changed, return early avoid redundant + // synchronization. + if (delegate_ == d) { + return; + } delegate_ = d; UpdateDialogHost(); + + // Synchronize the web contents blocked state with the new delegate. + // This ensures the new window's TabModel correctly reflects an active + // dialog after a tab is moved between windows. + // Only call this if a dialog is active, to avoid redundant focus changes + // when there are no dialogs. + if (delegate_ && IsDialogActive()) { + delegate_->SetWebContentsBlocked(web_contents(), true); + } } // TODO(gbillock): Maybe "ShowBubbleWithManager"?
diff --git a/components/web_modal/web_contents_modal_dialog_manager_unittest.cc b/components/web_modal/web_contents_modal_dialog_manager_unittest.cc index f2651df..a44dfab 100644 --- a/components/web_modal/web_contents_modal_dialog_manager_unittest.cc +++ b/components/web_modal/web_contents_modal_dialog_manager_unittest.cc
@@ -177,6 +177,35 @@ native_manager->StopTracking(); } +// Test that setting a new delegate correctly synchronizes the blocked state +// if a dialog is currently active. This is crucial for split-view window moves. +TEST_F(WebContentsModalDialogManagerTest, SetDelegateSyncsBlockedState) { + const gfx::NativeWindow dialog = MakeFakeDialog(); + + NativeManagerTracker tracker; + TestNativeWebContentsModalDialogManager* native_manager = + new TestNativeWebContentsModalDialogManager(dialog, manager, &tracker); + manager->ShowDialogWithManager(dialog, base::WrapUnique(native_manager)); + + EXPECT_TRUE(manager->IsDialogActive()); + EXPECT_TRUE(delegate->web_contents_blocked()); + + auto new_delegate = + std::make_unique<TestWebContentsModalDialogManagerDelegate>(); + EXPECT_FALSE(new_delegate->web_contents_blocked()); + + manager->SetDelegate(new_delegate.get()); + + // The new delegate should be updated with the current blocked state. + EXPECT_TRUE(new_delegate->web_contents_blocked()); + + // Restore the original delegate so new_delegate doesn't dangle after + // destruction. + manager->SetDelegate(delegate.get()); + + native_manager->StopTracking(); +} + // Test that the dialog is not shown immediately when the delegate indicates the // web contents is not visible. TEST_F(WebContentsModalDialogManagerTest, WebContentsNotVisible) {
diff --git a/content/browser/interest_group/interest_group_browsertest.cc b/content/browser/interest_group/interest_group_browsertest.cc index ff92d58b..92e5ef18 100644 --- a/content/browser/interest_group/interest_group_browsertest.cc +++ b/content/browser/interest_group/interest_group_browsertest.cc
@@ -795,7 +795,6 @@ {blink::features::kFledgeDirectFromSellerSignalsWebBundles, {}}, {blink::features::kFledgeTrustedSignalsKVv1CreativeScanning, {}}, {blink::features::kFledgeTrustedSignalsKVv2ContextualData, {}}, - {features::kFledgeTextConversionHelpers, {}}, {network::features::kAdAuctionEventRegistration, {}}, {blink::features::kFledgeClickiness, {}}, {network::features::kPopulatePermissionsPolicyOnRequest, {}}},
diff --git a/content/browser/network_service_instance_impl.cc b/content/browser/network_service_instance_impl.cc index 86c5c00..2beaf356 100644 --- a/content/browser/network_service_instance_impl.cc +++ b/content/browser/network_service_instance_impl.cc
@@ -138,7 +138,7 @@ // When enabled, sets the in-process network service thread to // base::ThreadType::kPresentation when the scenario indicates that the user is -// actively loading the focused page and not scrolling. +// actively loading the visible page and not scrolling. BASE_FEATURE(kNetworkServiceIncreasedPriorityWhileLoading, base::FEATURE_DISABLED_BY_DEFAULT); @@ -209,13 +209,13 @@ private: friend class base::NoDestructor<BoostNetworkThreadPriority>; - // Boost the network service thread when loading the focused page and not + // Boost the network service thread when loading the visible page and not // scrolling, since the higher thread priority of the network service thread // can take cycles away from threads that are critical to smooth scrolling. static constexpr performance_scenarios::ScenarioPattern kBoostScenarioPattern = { .loading = - {performance_scenarios::LoadingScenario::kFocusedPageLoading}, + {performance_scenarios::LoadingScenario::kVisiblePageLoading}, .input = {performance_scenarios::InputScenario::kNoInput, performance_scenarios::InputScenario::kTyping, performance_scenarios::InputScenario::kTap}};
diff --git a/content/browser/renderer_host/render_frame_host_impl_browsertest.cc b/content/browser/renderer_host/render_frame_host_impl_browsertest.cc index ede9d36..ed089df 100644 --- a/content/browser/renderer_host/render_frame_host_impl_browsertest.cc +++ b/content/browser/renderer_host/render_frame_host_impl_browsertest.cc
@@ -8087,6 +8087,52 @@ EXPECT_FALSE(delegate->did_show_loading_ui_values()[1]); } +IN_PROC_BROWSER_TEST_F( + RenderFrameHostImplBrowserTest, + NavigationApiInterceptsRendererInitiatedSameDocumentRepeated) { + GURL main_url = embedded_test_server()->GetURL("a.com", "/title1.html"); + ASSERT_TRUE(NavigateToURL(shell(), main_url)); + + std::unique_ptr<ShouldShowLoadingUIDelegate> delegate = + std::make_unique<ShouldShowLoadingUIDelegate>(); + web_contents()->SetDelegate(delegate.get()); + + EXPECT_TRUE(ExecJs(web_contents(), R"( + (async () => { + navigation.onnavigate = e => + e.intercept({handler: () => new Promise(r => setTimeout(r, 100))}); + await navigation.navigate('#one').finished; + await navigation.navigate('#two').finished; + })(); + )")); + + EXPECT_THAT(delegate->is_loading_values(), + testing::ElementsAre( + // First navigation: '#one'. + true, // Start renderer-initiated same-document navigation. + true, // Delayed commit requests visible loading UI. + false, // Navigation completes. + + // Second navigation: '#two'. + true, // Start renderer-initiated same-document navigation. + true, // Delayed commit requests visible loading UI. + false // Navigation completes. + )); + + EXPECT_THAT(delegate->did_show_loading_ui_values(), + testing::ElementsAre( + // First navigation: '#one'. + false, // Start renderer-initiated same-document navigation. + true, // Delayed commit requests visible loading UI. + false, // Navigation completes. + + // Second navigation: '#two'. + false, // Start renderer-initiated same-document navigation. + true, // Delayed commit requests visible loading UI. + false // Navigation completes. + )); +} + // Ensure that navigating with a frame tree of A(B(A)) results in the right // number of beforeunload messages sent. IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBeforeUnloadBrowserTest,
diff --git a/content/browser/surface_embed/surface_embed_connector_impl_browsertest.cc b/content/browser/surface_embed/surface_embed_connector_impl_browsertest.cc index a080531..95f6379d 100644 --- a/content/browser/surface_embed/surface_embed_connector_impl_browsertest.cc +++ b/content/browser/surface_embed/surface_embed_connector_impl_browsertest.cc
@@ -48,6 +48,7 @@ MOCK_METHOD(void, DetachedByHost, (), (override)); MOCK_METHOD(bool, IsAttachedForTesting, (), (const, override)); MOCK_METHOD(void, ChildProcessGone, (), (override)); + MOCK_METHOD(void, RequestFocus, (), (override)); }; } // namespace
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc index 74a68ff8..0ffb9c8 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc
@@ -10577,6 +10577,12 @@ RenderWidgetHostImpl* render_widget_host) { OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::FocusOwningWebContents", "render_widget_host", render_widget_host); + + if (surface_embed_connector_) { + // Requests focus for the embedding element in the parent page. + surface_embed_connector_->GetDelegate()->RequestFocus(); + } + RenderWidgetHostImpl* main_frame_widget_host = GetPrimaryMainFrame()->GetRenderWidgetHost(); RenderWidgetHostImpl* focused_widget =
diff --git a/content/browser/web_contents/web_contents_impl_browsertest.cc b/content/browser/web_contents/web_contents_impl_browsertest.cc index 54c40df2..fccff6d 100644 --- a/content/browser/web_contents/web_contents_impl_browsertest.cc +++ b/content/browser/web_contents/web_contents_impl_browsertest.cc
@@ -5645,6 +5645,7 @@ void DetachedByHost() override {} bool IsAttachedForTesting() const override { return false; } void ChildProcessGone() override {} + void RequestFocus() override {} }; content::test::PrerenderTestHelper prerender_helper_;
diff --git a/content/browser/webrtc/resources/stats_graph_helper.js b/content/browser/webrtc/resources/stats_graph_helper.js index 2fb0319..6155f48 100644 --- a/content/browser/webrtc/resources/stats_graph_helper.js +++ b/content/browser/webrtc/resources/stats_graph_helper.js
@@ -123,15 +123,6 @@ if (!graphViews[graphViewId]) { graphViews[graphViewId] = createStatsGraphView( peerConnectionElement, rtcStats, graphType); - const searchParameters = new URLSearchParams(window.location.search); - if (searchParameters.has('statsInterval')) { - const statsInterval = Math.max( - parseInt(searchParameters.get('statsInterval'), 10), - 100); - if (isFinite(statsInterval)) { - graphViews[graphViewId].setScale(statsInterval); - } - } const date = new Date(rtcStats.timestamp); graphViews[graphViewId].setDateRange(date, date); }
diff --git a/content/browser/webrtc/resources/webrtc_internals.js b/content/browser/webrtc/resources/webrtc_internals.js index 68174eb..4b42703 100644 --- a/content/browser/webrtc/resources/webrtc_internals.js +++ b/content/browser/webrtc/resources/webrtc_internals.js
@@ -211,19 +211,6 @@ params.eventLogRecordingsToggleable); }); - // Requests stats from all peer connections every second unless specified via - // ?statsInterval=(milliseconds >= 100ms) - let statsInterval = 1000; - if (searchParameters.has('statsInterval')) { - statsInterval = Math.max( - parseInt(searchParameters.get('statsInterval'), 10), - 100); - if (!isFinite(statsInterval)) { - statsInterval = 1000; - } - } - window.setInterval(requestStats, statsInterval); - addRtcStatsEvent( 'create', null, @@ -248,16 +235,6 @@ document.addEventListener('DOMContentLoaded', initialize); /** - * Sends a request to the browser to get peer connection statistics from the - * standard getStats() API (promise-based). - */ -function requestStats() { - if (Object.keys(peerConnectionDataStore).length > 0) { - chrome.send('getStandardStats'); - } -} - -/** * A helper function for getting a peer connection element id. * * @param {!Object<number>} data The object containing the rid and lid of the @@ -465,7 +442,6 @@ addPeerConnectionUpdate(peerConnection, log[j]); } } - requestStats(); } /**
diff --git a/content/browser/webrtc/webrtc_internals.cc b/content/browser/webrtc/webrtc_internals.cc index aa86a1ec..aabe152a 100644 --- a/content/browser/webrtc/webrtc_internals.cc +++ b/content/browser/webrtc/webrtc_internals.cc
@@ -14,6 +14,7 @@ #include "base/observer_list.h" #include "base/strings/string_number_conversions.h" #include "build/build_config.h" +#include "content/browser/renderer_host/media/peer_connection_tracker_host.h" #include "content/browser/web_contents/web_contents_view.h" #include "content/browser/webrtc/webrtc_internals_connections_observer.h" #include "content/browser/webrtc/webrtc_internals_ui_observer.h" @@ -765,6 +766,7 @@ } } UpdateWakeLock(); + UpdateStatsTimer(); bool found_any = false; // Iterates from the end of the list to remove the getUserMedia requests @@ -823,6 +825,7 @@ ++num_connected_connections_; record.GetDict().Set("connected", true); UpdateWakeLock(); + UpdateStatsTimer(); for (auto& observer : connections_observers_) observer.OnConnectionsCountChange(num_connected_connections_); } @@ -837,6 +840,7 @@ --num_connected_connections_; DCHECK_GE(num_connected_connections_, 0); UpdateWakeLock(); + UpdateStatsTimer(); for (auto& observer : connections_observers_) observer.OnConnectionsCountChange(num_connected_connections_); } @@ -876,6 +880,25 @@ return wake_lock_.get(); } +void WebRTCInternals::RequestStandardStats() { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + for (auto* host : PeerConnectionTrackerHost::GetAllHosts()) { + host->GetStandardStats(); + } +} + +void WebRTCInternals::UpdateStatsTimer() { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + if (num_connected_connections_ > 0 && !observers_.empty()) { + if (!stats_timer_.IsRunning()) { + stats_timer_.Start(FROM_HERE, base::Seconds(1), this, + &WebRTCInternals::RequestStandardStats); + } + } else { + stats_timer_.Stop(); + } +} + void WebRTCInternals::ProcessPendingUpdates() { DCHECK_CURRENTLY_ON(BrowserThread::UI); while (!pending_updates_.empty()) {
diff --git a/content/browser/webrtc/webrtc_internals.h b/content/browser/webrtc/webrtc_internals.h index 024237ed..4294a72 100644 --- a/content/browser/webrtc/webrtc_internals.h +++ b/content/browser/webrtc/webrtc_internals.h
@@ -15,6 +15,7 @@ #include "base/observer_list.h" #include "base/process/process.h" #include "base/threading/thread_checker.h" +#include "base/timer/timer.h" #include "base/values.h" #include "content/common/content_export.h" #include "content/public/browser/global_routing_id.h" @@ -172,6 +173,8 @@ kDataChannelRecordings, }; + void UpdateStatsTimer(); + void SendUpdate(const std::string& event_name, base::Value event_data); void SendUpdate(const std::string& event_name, base::DictValue event_data); @@ -219,6 +222,10 @@ // notifications. void ProcessPendingUpdates(); + // Sends a request to the browser to get peer connection statistics from the + // standard getStats() API (promise-based). + void RequestStandardStats(); + // Returns an iterator for peer_connection_data_.GetList (an end() iterator // if not found). base::ListValue::iterator FindRecord(GlobalRenderFrameHostId frame_id, @@ -228,6 +235,8 @@ base::ObserverList<WebRtcInternalsConnectionsObserver> connections_observers_; + base::RepeatingTimer stats_timer_; + // |peer_connection_data_| is a list containing all the PeerConnection // updates. Stored as a Value rather than as a List::Value so it can be passed // as a Value without having to copy it.
diff --git a/content/browser/webrtc/webrtc_internals_message_handler.cc b/content/browser/webrtc/webrtc_internals_message_handler.cc index 58abf22..5e463e50e 100644 --- a/content/browser/webrtc/webrtc_internals_message_handler.cc +++ b/content/browser/webrtc/webrtc_internals_message_handler.cc
@@ -35,11 +35,6 @@ void WebRTCInternalsMessageHandler::RegisterMessages() { web_ui()->RegisterMessageCallback( - "getStandardStats", - base::BindRepeating(&WebRTCInternalsMessageHandler::OnGetStandardStats, - base::Unretained(this))); - - web_ui()->RegisterMessageCallback( "enableAudioDebugRecordings", base::BindRepeating( &WebRTCInternalsMessageHandler::OnSetAudioDebugRecordingsEnabled, @@ -98,13 +93,6 @@ return host; } -void WebRTCInternalsMessageHandler::OnGetStandardStats( - const base::ListValue& /* unused_list */) { - for (auto* host : PeerConnectionTrackerHost::GetAllHosts()) { - host->GetStandardStats(); - } -} - void WebRTCInternalsMessageHandler::OnSetAudioDebugRecordingsEnabled( bool enable, const base::ListValue& /* unused_list */) {
diff --git a/content/browser/webrtc/webrtc_internals_message_handler.h b/content/browser/webrtc/webrtc_internals_message_handler.h index 422295c..0cf0bd7 100644 --- a/content/browser/webrtc/webrtc_internals_message_handler.h +++ b/content/browser/webrtc/webrtc_internals_message_handler.h
@@ -5,6 +5,7 @@ #ifndef CONTENT_BROWSER_WEBRTC_WEBRTC_INTERNALS_MESSAGE_HANDLER_H_ #define CONTENT_BROWSER_WEBRTC_WEBRTC_INTERNALS_MESSAGE_HANDLER_H_ +#include "base/functional/callback_helpers.h" #include "base/memory/raw_ptr.h" #include "base/values.h" #include "content/browser/webrtc/webrtc_internals_ui_observer.h" @@ -45,7 +46,6 @@ RenderFrameHost* GetWebRTCInternalsHost(); // Javascript message handler. - void OnGetStandardStats(const base::ListValue& list); void OnGetCurrentState(const base::ListValue& list); void OnSetAudioDebugRecordingsEnabled(bool enable, const base::ListValue& list);
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityTreeTest.java b/content/public/android/javatests/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityTreeTest.java index dace9208..c925df3e 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityTreeTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityTreeTest.java
@@ -39,10 +39,7 @@ @SuppressLint("VisibleForTests") @Batch(Batch.PER_CLASS) @Restriction(DeviceRestriction.RESTRICTION_TYPE_NON_AUTO) -@DisableFeatures({ - ContentFeatureList.ACCESSIBILITY_UNIFIED_SNAPSHOTS, - ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API -}) +@DisableFeatures({ContentFeatureList.ACCESSIBILITY_UNIFIED_SNAPSHOTS}) @EnableFeatures({ ContentFeatureList.ACCESSIBILITY_DEPRECATE_TYPE_ANNOUNCE, ContentFeatureList.ACCESSIBILITY_EXTENDED_SELECTION, @@ -214,21 +211,18 @@ @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_descComboboxFocusable() { performAccnameTest("desc-combobox-focusable.html"); } @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_descFromContentOfDescribedbyElement() { performAccnameTest("desc-from-content-of-describedby-element.html"); } @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_nameComboboxFocusable() { performAccnameTest("name-combobox-focusable.html"); } @@ -369,21 +363,18 @@ @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_ariaCombobox() { performAriaTest("aria-combobox.html"); } @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_ariaComboboxImplicitHaspopup() { performAriaTest("aria-combobox-implicit-haspopup.html"); } @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_ariaComboboxUneditable() { performAriaTest("aria-combobox-uneditable.html"); } @@ -474,7 +465,6 @@ @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_ariaErrormessage() { performAriaTest("aria-errormessage.html"); } @@ -567,7 +557,6 @@ @Test @SmallTest @MinAndroidSdkLevel(Build.VERSION_CODES.BAKLAVA) - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_ariaIllegalVal() { Assume.assumeTrue( "Requires Android 16 QPR2 (36.1) or higher", @@ -625,7 +614,6 @@ @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_ariaLabelledbyHeading() { performAriaTest("aria-labelledby-heading.html"); } @@ -768,7 +756,6 @@ @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_ariaMeter() { performAriaTest("aria-meter.html"); } @@ -781,7 +768,6 @@ @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_ariaModal() { performAriaTest("aria-modal.html"); } @@ -896,7 +882,6 @@ @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_ariaProgressbar() { performAriaTest("aria-progressbar.html"); } @@ -915,7 +900,6 @@ @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_ariaReadonly() { performAriaTest("aria-readonly.html"); } @@ -970,7 +954,6 @@ @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_ariaScrollbar() { performAriaTest("aria-scrollbar.html"); } @@ -1001,7 +984,6 @@ @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_ariaSlider() { performAriaTest("aria-slider.html"); } @@ -1028,7 +1010,6 @@ @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_ariaSpinbutton() { performAriaTest("aria-spinbutton.html"); } @@ -1117,14 +1098,12 @@ @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_ariaTextboxWithAriaTextboxChild() { performAriaTest("aria-textbox-with-aria-textbox-child.html"); } @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_ariaTextboxWithNonTextChildren() { performAriaTest("aria-textbox-with-non-text-children.html"); } @@ -1185,14 +1164,12 @@ @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_ariaValuemax() { performAriaTest("aria-valuemax.html"); } @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_ariaValuemin() { performAriaTest("aria-valuemin.html"); } @@ -1247,7 +1224,6 @@ @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_inputTextAriaPlaceholder() { performAriaTest("input-text-aria-placeholder.html"); } @@ -1260,49 +1236,42 @@ @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_supplementalDescriptionAnnotate() { performAriaTest("supplemental-description-annotate.html"); } @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_supplementalDescriptionButtonLabel() { performAriaTest("supplemental-description-button-label.html"); } @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_supplementalDescriptionImageButton() { performAriaTest("supplemental-description-image-button.html"); } @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_supplementalDescriptionLinks() { performAriaTest("supplemental-description-links.html"); } @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_supplementalDescriptionNav() { performAriaTest("supplemental-description-nav.html"); } @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_supplementalDescriptionRegion() { performAriaTest("supplemental-description-region.html"); } @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_supplementalDescriptionSelect() { performAriaTest("supplemental-description-select.html"); } @@ -1381,14 +1350,18 @@ performApgPatternTest("aria-slider-vertical.html"); } + // TODO(crbug.com/508658153): re-enable this test @Test @SmallTest + @DisabledTest(message = "https://crbug.com/508658153") public void test_ariaTreeviewFileDirectoryComputedProperties() { performApgPatternTest("aria-treeview-file-directory-computed-properties.html"); } + // TODO(crbug.com/508658153): re-enable this test @Test @SmallTest + @DisabledTest(message = "https://crbug.com/508658153") public void test_ariaTreeviewFileDirectoryDeclaredProperties() { performApgPatternTest("aria-treeview-file-directory-declared-properties.html"); } @@ -1526,7 +1499,6 @@ @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_actions() { performHtmlTest("actions.html"); } @@ -1569,7 +1541,6 @@ @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_audio() { performHtmlTest("audio.html"); } @@ -1770,7 +1741,6 @@ @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_contenteditableWithNoDescendants() { performHtmlTest("contenteditable-with-no-descendants.html"); } @@ -1800,21 +1770,18 @@ @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_customSelect() { performHtmlTest("custom-select.html"); } @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_customSelectOpen() { performHtmlTest("custom-select-open.html"); } @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_customSelectLabelElement() { performHtmlTest("custom-select-label-element.html"); } @@ -1827,14 +1794,12 @@ @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_customSelectSimple() { performHtmlTest("custom-select-simple.html"); } @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_customSelectSimpleOpen() { performHtmlTest("custom-select-simple-open.html"); } @@ -2016,7 +1981,6 @@ @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_htmlVsAriaAttributes() { performHtmlTest("html-vs-aria-attributes.html"); } @@ -2154,14 +2118,12 @@ @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_inputDateWithPopupOpenMultipleForWin() { performHtmlTest("input-date-with-popup-open-multiple-for-win.html"); } @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_inputDateWithPopupOpenMultiple() { performHtmlTest("input-date-with-popup-open-multiple.html"); } @@ -2174,7 +2136,6 @@ @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_inputDate() { performHtmlTest("input-date.html"); } @@ -2187,7 +2148,6 @@ @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_inputDatetime() { performHtmlTest("input-datetime.html"); } @@ -2200,7 +2160,6 @@ @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_inputFile() { performHtmlTest("input-file.html"); } @@ -2213,7 +2172,6 @@ @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_inputList() { performHtmlTest("input-list.html"); } @@ -2256,14 +2214,12 @@ @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_inputRange() { performHtmlTest("input-range.html"); } @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_progressBar() { performHtmlTest("progress-bar.html"); } @@ -2300,7 +2256,6 @@ @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_inputTextNameCalc() { performHtmlTest("input-text-name-calc.html"); } @@ -2313,21 +2268,18 @@ @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_inputTextReadOnly() { performHtmlTest("input-text-read-only.html"); } @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_inputTextValue() { performHtmlTest("input-text-value.html"); } @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_inputText() { performHtmlTest("input-text.html"); } @@ -2340,35 +2292,30 @@ @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_inputTime() { performHtmlTest("input-time.html"); } @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_inputTypesWithPlaceholder() { performHtmlTest("input-types-with-placeholder.html"); } @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_inputTypesWithValueAndPlaceholder() { performHtmlTest("input-types-with-value-and-placeholder.html"); } @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_inputTypesWithValue() { performHtmlTest("input-types-with-value.html"); } @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_inputTypes() { performHtmlTest("input-types.html"); } @@ -2393,7 +2340,6 @@ @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_interactiveControlsWithLabels() { performHtmlTest("interactive-controls-with-labels.html"); } @@ -2429,8 +2375,10 @@ performHtmlTest("legend.html"); } + // TODO(crbug.com/508658153): re-enable this test @Test @SmallTest + @DisabledTest(message = "https://crbug.com/508658153") public void test_li() { performHtmlTest("li.html"); } @@ -2563,14 +2511,12 @@ @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_optgroupMenulist() { performHtmlTest("optgroup-menulist.html"); } @Test @SmallTest - @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_optgroupCustomMenulist() { performHtmlTest("optgroup-custom-menulist.html"); } @@ -2728,7 +2674,6 @@ @Test @SmallTest - // @EnableFeatures(ContentFeatureList.ACCESSIBILITY_POPULATE_SUPPLEMENTAL_DESCRIPTION_API) public void test_selectOpen() { performHtmlTest("select-open.html"); }
diff --git a/content/public/browser/surface_embed_connector.h b/content/public/browser/surface_embed_connector.h index 602545d..d67628fe 100644 --- a/content/public/browser/surface_embed_connector.h +++ b/content/public/browser/surface_embed_connector.h
@@ -49,6 +49,9 @@ // Called when the process for the child frame crashed. virtual void ChildProcessGone() = 0; + + // Requests focus for the embedding element in the parent. + virtual void RequestFocus() = 0; }; // Attach a child WebContents to a parent WebContents. This creates a
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc index d6e656c4..d3ad779 100644 --- a/content/public/common/content_features.cc +++ b/content/public/common/content_features.cc
@@ -1347,7 +1347,7 @@ // Enables populating the supplemental description information via the // Android supplemental description API. BASE_FEATURE(kAccessibilityPopulateSupplementalDescriptionApi, - base::FEATURE_DISABLED_BY_DEFAULT); + base::FEATURE_ENABLED_BY_DEFAULT); // Enables the reactive synchronization of accessibility and keyboard focus, // relying on new Android framework behavior.
diff --git a/content/services/auction_worklet/BUILD.gn b/content/services/auction_worklet/BUILD.gn index a4b43fc0..02e8ab7c 100644 --- a/content/services/auction_worklet/BUILD.gn +++ b/content/services/auction_worklet/BUILD.gn
@@ -92,8 +92,6 @@ "set_priority_signals_override_bindings.h", "shared_storage_bindings.cc", "shared_storage_bindings.h", - "text_conversion_helpers.cc", - "text_conversion_helpers.h", "trusted_kvv2_signals.cc", "trusted_kvv2_signals.h", "trusted_signals.cc",
diff --git a/content/services/auction_worklet/bidder_worklet.cc b/content/services/auction_worklet/bidder_worklet.cc index 38f7021..53a0ce1eb 100644 --- a/content/services/auction_worklet/bidder_worklet.cc +++ b/content/services/auction_worklet/bidder_worklet.cc
@@ -1136,10 +1136,6 @@ v8::Local<v8::Context> context = context_recycler_scope.GetContext(); AuctionV8Logger v8_logger(v8_helper_.get(), context); - // We want this before RunScript, both because it's meant to be visible - // to globals, and because we don't want to overwrite existing globals. - context_recycler.AddTextConversionHelpers(); - v8::LocalVector<v8::Value> args(isolate); if (!AppendJsonValueOrNull(v8_helper_.get(), context, base::OptionalToPtr(auction_signals_json), @@ -2146,10 +2142,6 @@ v8::Local<v8::Context> context = context_recycler_scope.GetContext(); TRACE_EVENT_END("fledge", perfetto::Track(trace_id)); - // We want this before RunScript, both because it's meant to be visible - // to globals, and because we don't want to overwrite existing globals. - context_recycler->AddTextConversionHelpers(); - v8::Local<v8::UnboundScript> unbound_worklet_script = worklet_script_.Get(v8_helper_->isolate());
diff --git a/content/services/auction_worklet/bidder_worklet_unittest.cc b/content/services/auction_worklet/bidder_worklet_unittest.cc index 358b57c..743b2bde 100644 --- a/content/services/auction_worklet/bidder_worklet_unittest.cc +++ b/content/services/auction_worklet/bidder_worklet_unittest.cc
@@ -343,7 +343,6 @@ SetDefaultParameters(); feature_list_.InitWithFeatures( /*enabled_features=*/{features::kInterestGroupUpdateIfOlderThan, - features::kFledgeTextConversionHelpers, blink::features:: kFledgeTrustedSignalsKVv1CreativeScanning}, /*disabled_features=*/{}); @@ -1298,16 +1297,6 @@ base::test::ScopedFeatureList feature_list_; }; -class BidderWorkletNoTextConversionsTest : public BidderWorkletTest { - public: - BidderWorkletNoTextConversionsTest() { - feature_list_.InitAndDisableFeature(features::kFledgeTextConversionHelpers); - } - - protected: - base::test::ScopedFeatureList feature_list_; -}; - // Test the case the BidderWorklet pipe is closed before invoking the // GenerateBidCallback. The invocation of the GenerateBidCallback is not // observed, since the callback is on the pipe that was just closed. There @@ -5018,23 +5007,6 @@ R"(!('creativeScanningMetadata' in interestGroup.adComponents[0]))"); } -TEST_F(BidderWorkletNoTextConversionsTest, GenerateBidTextConversions) { - RunGenerateBidExpectingExpressionIsTrue( - R"(!('protectedAudience' in globalThis))"); -} - -TEST_F(BidderWorkletTest, GenerateBidTextConversions) { - RunGenerateBidExpectingExpressionIsTrue( - R"('encodeUtf8' in protectedAudience)"); - RunGenerateBidExpectingExpressionIsTrue( - R"('decodeUtf8' in protectedAudience)"); - - RunGenerateBidExpectingExpressionIsTrue( - "protectedAudience.encodeUtf8('A')[0] === 65"); - RunGenerateBidExpectingExpressionIsTrue( - "protectedAudience.decodeUtf8(new Uint8Array([65, 32, 68])) === 'A D'"); -} - // Make sure we don't stomp over an existing user protectedAudience TEST_F(BidderWorkletTest, GenerateBidNoGlobalStomp) { const char kScript[] = R"( @@ -8074,21 +8046,6 @@ {"https://url.test/ top-level execution timed out."}); } -TEST_F(BidderWorkletNoTextConversionsTest, ReportWinTextConversions) { - RunReportWinWithFunctionBodyExpectingResult( - "sendReportTo('https://foo.test?' + ('protectedAudience' in globalThis))", - GURL("https://foo.test/?false")); -} - -TEST_F(BidderWorkletTest, ReportWinTextConversions) { - RunReportWinWithFunctionBodyExpectingResult( - "sendReportTo('https://foo.test?' + ('encodeUtf8' in protectedAudience))", - GURL("https://foo.test/?true")); - RunReportWinWithFunctionBodyExpectingResult( - "sendReportTo('https://foo.test?' + ('decodeUtf8' in protectedAudience))", - GURL("https://foo.test/?true")); -} - // Make sure we don't stomp over an existing user protectedAudience object. TEST_F(BidderWorkletTest, ReportWinNoGlobalStomp) { const char kScript[] = R"(
diff --git a/content/services/auction_worklet/context_recycler.cc b/content/services/auction_worklet/context_recycler.cc index ba6617d..52df3d90 100644 --- a/content/services/auction_worklet/context_recycler.cc +++ b/content/services/auction_worklet/context_recycler.cc
@@ -23,7 +23,6 @@ #include "content/services/auction_worklet/set_priority_bindings.h" #include "content/services/auction_worklet/set_priority_signals_override_bindings.h" #include "content/services/auction_worklet/shared_storage_bindings.h" -#include "content/services/auction_worklet/text_conversion_helpers.h" #include "v8/include/v8-context.h" namespace auction_worklet { @@ -117,13 +116,6 @@ AddBindings(shared_storage_bindings_.get()); } -void ContextRecycler::AddTextConversionHelpers() { - DCHECK(!text_conversion_helpers_); - text_conversion_helpers_ = - std::make_unique<TextConversionHelpers>(v8_helper_); - AddBindings(text_conversion_helpers_.get()); -} - void ContextRecycler::AddInterestGroupLazyFiller() { DCHECK(!interest_group_lazy_filler_); interest_group_lazy_filler_ =
diff --git a/content/services/auction_worklet/context_recycler.h b/content/services/auction_worklet/context_recycler.h index 3720761..2e40385 100644 --- a/content/services/auction_worklet/context_recycler.h +++ b/content/services/auction_worklet/context_recycler.h
@@ -35,7 +35,6 @@ class SetPriorityBindings; class SetPrioritySignalsOverrideBindings; class SharedStorageBindings; -class TextConversionHelpers; class AuctionConfigLazyFiller; class BiddingBrowserSignalsLazyFiller; class InterestGroupLazyFiller; @@ -146,11 +145,6 @@ return shared_storage_bindings_.get(); } - void AddTextConversionHelpers(); - TextConversionHelpers* text_conversion_helpers() { - return text_conversion_helpers_.get(); - } - void AddInterestGroupLazyFiller(); InterestGroupLazyFiller* interest_group_lazy_filler() { return interest_group_lazy_filler_.get(); @@ -210,7 +204,6 @@ std::unique_ptr<SetPrioritySignalsOverrideBindings> set_priority_signals_override_bindings_; std::unique_ptr<SharedStorageBindings> shared_storage_bindings_; - std::unique_ptr<TextConversionHelpers> text_conversion_helpers_; // everything here is owned by one of the unique_ptr's above. std::vector<raw_ptr<Bindings, VectorExperimental>> bindings_list_;
diff --git a/content/services/auction_worklet/context_recycler_unittest.cc b/content/services/auction_worklet/context_recycler_unittest.cc index 3b27faff..fd0c5037 100644 --- a/content/services/auction_worklet/context_recycler_unittest.cc +++ b/content/services/auction_worklet/context_recycler_unittest.cc
@@ -34,7 +34,6 @@ #include "content/services/auction_worklet/seller_lazy_filler.h" #include "content/services/auction_worklet/set_bid_bindings.h" #include "content/services/auction_worklet/set_priority_bindings.h" -#include "content/services/auction_worklet/text_conversion_helpers.h" #include "content/services/auction_worklet/worklet_test_util.h" #include "gin/converter.h" #include "gin/dictionary.h" @@ -6590,260 +6589,6 @@ } } -TEST_F(ContextRecyclerTest, EncodeUtf8) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndEnableFeature( - features::kFledgeTextConversionHelpers); - - const char kScript[] = R"( - function assertEq(l, r, label) { - if (l !== r) - throw 'Mismatch ' + label; - } - - function assertByteArray(result, expect) { - if (!(result instanceof Uint8Array)) { - throw 'Not a Uint8Array!'; - } - assertEq(result.length, expect.length, 'length'); - for (var i = 0; i < result.length; ++i) { - assertEq(result[i], expect[i], i); - } - } - - function test1() { - assertByteArray(protectedAudience.encodeUtf8('ABC'), - [65, 66, 67]); - } - - function test2() { - assertByteArray(protectedAudience.encodeUtf8('A \u0490'), - [65, 32, 0xD2, 0x90]); - } - - // Unmatched surrogate. - function test3() { - assertByteArray(protectedAudience.encodeUtf8('A\uD800C'), - [65, 0xEF, 0xBF, 0xBD, 67]); - } - - // Matched surrogate. - function test4() { - assertByteArray(protectedAudience.encodeUtf8('A\uD83D\uDE02C'), - [65, 0xF0, 0x9F, 0x98, 0x82, 67]); - } - - // Custom conversion. - function test5() { - let obj = { - toString: () => "ABC" - }; - assertByteArray(protectedAudience.encodeUtf8(obj), - [65, 66, 67]); - } - )"; - - v8::Local<v8::UnboundScript> script = Compile(kScript); - ASSERT_FALSE(script.IsEmpty()); - - ContextRecycler context_recycler(helper_.get()); - { - ContextRecyclerScope scope(context_recycler); // Initialize context - context_recycler.AddTextConversionHelpers(); - } - - for (const char* test : {"test1", "test2", "test3", "test4", "test5"}) { - SCOPED_TRACE(test); - ContextRecyclerScope scope(context_recycler); - - std::vector<std::string> error_msgs; - Run(scope, script, test, error_msgs); - EXPECT_THAT(error_msgs, ElementsAre()); - } -} - -TEST_F(ContextRecyclerTest, EncodeUtf8Failure) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndEnableFeature( - features::kFledgeTextConversionHelpers); - - const char kScript[] = R"( - // Not enough arguments. - function test1() { - protectedAudience.encodeUtf8(); - } - - // String conversion failure. - function test2() { - let obj = { - toString: () => { throw 'ouch' } - }; - protectedAudience.encodeUtf8(obj); - } - )"; - - v8::Local<v8::UnboundScript> script = Compile(kScript); - ASSERT_FALSE(script.IsEmpty()); - - ContextRecycler context_recycler(helper_.get()); - { - ContextRecyclerScope scope(context_recycler); // Initialize context - context_recycler.AddTextConversionHelpers(); - } - - const struct TestCase { - const char* functionName; - const char* error; - } kTests[] = { - {"test1", - "https://example.test/script.js:4 Uncaught TypeError: encodeUtf8 at " - "least 1 argument(s) are required."}, - {"test2", "https://example.test/script.js:12 Uncaught ouch."}}; - - for (const auto& test : kTests) { - SCOPED_TRACE(test.functionName); - ContextRecyclerScope scope(context_recycler); - - std::vector<std::string> error_msgs; - Run(scope, script, test.functionName, error_msgs); - EXPECT_THAT(error_msgs, ElementsAre(test.error)); - } -} - -TEST_F(ContextRecyclerTest, DecodeUtf8) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndEnableFeature( - features::kFledgeTextConversionHelpers); - - const char kScript[] = R"( - function assertEq(l, r, label) { - if (l !== r) - throw 'Mismatch ' + label + ' ' + l + ' vs ' + r; - } - - function assertString(result, expect) { - if (typeof result !== 'string') { - throw 'Not a string'; - } - assertEq(result.length, expect.length, 'length'); - for (var i = 0; i < result.length; ++i) { - assertEq(result.charCodeAt(i), expect.charCodeAt(i), i); - } - } - - function test1() { - assertString(protectedAudience.decodeUtf8(new Uint8Array([65, 66, 67])), - 'ABC'); - } - - function test2() { - assertString(protectedAudience.decodeUtf8( - new Uint8Array([65, 32, 0xD2, 0x90])), - 'A \u0490'); - } - - // Broken utf-8 --- gets a replacement character. - function test3() { - assertString(protectedAudience.decodeUtf8(new Uint8Array([65, 32, 0xD2])), - 'A \uFFFD'); - } - - // Utf-8 for just a single surrogate. Every byte ended up replaced with a - // replacement character. - function test4() { - assertString(protectedAudience.decodeUtf8(new Uint8Array( - [65, 32, 0xED, 0xA0, 0x80, 66])), - 'A \uFFFD\uFFFD\uFFFDB'); - } - - // Utf-8 for something that requires two Utf-16 characters. - function test5() { - assertString(protectedAudience.decodeUtf8(new Uint8Array( - [65, 0xF0, 0x9F, 0x98, 0x82, 67])), - 'A\uD83D\uDE02C'); - } - - // Partial view into an ArrayBuffer. - function test6() { - let buffer = new ArrayBuffer(8); - let fullView = new Uint8Array(buffer); - for (let i = 0; i < fullView.length; ++i) - fullView[i] = 65 + i; - let partialView = new Uint8Array(buffer, 2, 3); - assertString(protectedAudience.decodeUtf8(fullView), - 'ABCDEFGH'); - assertString(protectedAudience.decodeUtf8(partialView), - 'CDE'); - } - )"; - - v8::Local<v8::UnboundScript> script = Compile(kScript); - ASSERT_FALSE(script.IsEmpty()); - - ContextRecycler context_recycler(helper_.get()); - { - ContextRecyclerScope scope(context_recycler); // Initialize context - context_recycler.AddTextConversionHelpers(); - } - - for (const char* test : - {"test1", "test2", "test3", "test4", "test5", "test6"}) { - SCOPED_TRACE(test); - ContextRecyclerScope scope(context_recycler); - - std::vector<std::string> error_msgs; - Run(scope, script, test, error_msgs); - EXPECT_THAT(error_msgs, ElementsAre()); - } -} - -TEST_F(ContextRecyclerTest, DecodeUtf8Failure) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndEnableFeature( - features::kFledgeTextConversionHelpers); - - const char kScript[] = R"( - // Not enough arguments. - function test1() { - protectedAudience.decodeUtf8(); - } - - // Wrong type. - function test2() { - protectedAudience.decodeUtf8([65,66]); - } - )"; - - v8::Local<v8::UnboundScript> script = Compile(kScript); - ASSERT_FALSE(script.IsEmpty()); - - ContextRecycler context_recycler(helper_.get()); - { - ContextRecyclerScope scope(context_recycler); // Initialize context - context_recycler.AddTextConversionHelpers(); - } - - const struct TestCase { - const char* functionName; - const char* error; - } kTests[] = { - {"test1", - "https://example.test/script.js:4 Uncaught TypeError: decodeUtf8 " - "expects a Uint8Array argument."}, - {"test2", - "https://example.test/script.js:9 Uncaught TypeError: decodeUtf8 " - "expects a Uint8Array argument."}}; - - for (const auto& test : kTests) { - SCOPED_TRACE(test.functionName); - ContextRecyclerScope scope(context_recycler); - - std::vector<std::string> error_msgs; - Run(scope, script, test.functionName, error_msgs); - EXPECT_THAT(error_msgs, ElementsAre(test.error)); - } -} - class ContextRecyclerRealTimeReportingEnabledTest : public ContextRecyclerTest { public: ContextRecyclerRealTimeReportingEnabledTest() {
diff --git a/content/services/auction_worklet/public/cpp/auction_worklet_features.cc b/content/services/auction_worklet/public/cpp/auction_worklet_features.cc index 47a945e4..326e96ff 100644 --- a/content/services/auction_worklet/public/cpp/auction_worklet_features.cc +++ b/content/services/auction_worklet/public/cpp/auction_worklet_features.cc
@@ -87,6 +87,4 @@ BASE_FEATURE(kFledgeSellerSignalsRequestsOneAtATime, base::FEATURE_DISABLED_BY_DEFAULT); -BASE_FEATURE(kFledgeTextConversionHelpers, base::FEATURE_DISABLED_BY_DEFAULT); - } // namespace features
diff --git a/content/services/auction_worklet/public/cpp/auction_worklet_features.h b/content/services/auction_worklet/public/cpp/auction_worklet_features.h index ccd190b..907e23b 100644 --- a/content/services/auction_worklet/public/cpp/auction_worklet_features.h +++ b/content/services/auction_worklet/public/cpp/auction_worklet_features.h
@@ -78,9 +78,6 @@ // that it does not get batched. CONTENT_EXPORT BASE_DECLARE_FEATURE(kFledgeSellerSignalsRequestsOneAtATime); -// Provide encodeUtf8/decodeUtf8 helpers. -CONTENT_EXPORT BASE_DECLARE_FEATURE(kFledgeTextConversionHelpers); - } // namespace features #endif // CONTENT_SERVICES_AUCTION_WORKLET_PUBLIC_CPP_AUCTION_WORKLET_FEATURES_H_
diff --git a/content/services/auction_worklet/seller_worklet.cc b/content/services/auction_worklet/seller_worklet.cc index 4f17ec9..3667e94 100644 --- a/content/services/auction_worklet/seller_worklet.cc +++ b/content/services/auction_worklet/seller_worklet.cc
@@ -925,10 +925,6 @@ v8::Local<v8::Context> context = context_recycler_scope.GetContext(); TRACE_EVENT_END("fledge", perfetto::Track(trace_id)); // "get_seller_context" - // We want this before RunScript, both because it's meant to be visible - // to globals, and because we don't want to overwrite existing globals. - context_recycler->AddTextConversionHelpers(); - v8::Local<v8::UnboundScript> unbound_worklet_script = worklet_script_.Get(v8_helper_->isolate()); @@ -1761,10 +1757,6 @@ v8::Local<v8::Context> context = context_recycler_scope.GetContext(); AuctionV8Logger v8_logger(v8_helper_.get(), context); - // We want this before RunScript, both because it's meant to be visible - // to globals, and because we don't want to overwrite existing globals. - context_recycler.AddTextConversionHelpers(); - v8::LocalVector<v8::Value> args(isolate); context_recycler.EnsureAuctionConfigLazyFillers(
diff --git a/content/services/auction_worklet/seller_worklet_unittest.cc b/content/services/auction_worklet/seller_worklet_unittest.cc index 4a268d7..c902bae4 100644 --- a/content/services/auction_worklet/seller_worklet_unittest.cc +++ b/content/services/auction_worklet/seller_worklet_unittest.cc
@@ -242,8 +242,7 @@ : task_environment_(time_mode) { feature_list_.InitWithFeatures( /*enabled_features=*/{blink::features:: - kFledgeTrustedSignalsKVv1CreativeScanning, - features::kFledgeTextConversionHelpers}, + kFledgeTrustedSignalsKVv1CreativeScanning}, /*disabled_features=*/{}); SetDefaultParameters(); } @@ -1028,16 +1027,6 @@ size_t NumThreads() override { return 2u; } }; -class SellerWorkletNoTextConversionsTest : public SellerWorkletTest { - public: - SellerWorkletNoTextConversionsTest() { - feature_list_.InitAndDisableFeature(features::kFledgeTextConversionHelpers); - } - - protected: - base::test::ScopedFeatureList feature_list_; -}; - class SellerWorkletMultiThreadingTest : public SellerWorkletTest, public testing::WithParamInterface<std::tuple<size_t, bool>> { @@ -1969,24 +1958,6 @@ 3); } -TEST_F(SellerWorkletNoTextConversionsTest, ScoreAdTextConversions) { - RunScoreAdWithReturnValueExpectingResult( - R"('protectedAudience' in globalThis? 3 : 2)", 2); -} - -TEST_F(SellerWorkletTest, ScoreAdTextConversions) { - RunScoreAdWithReturnValueExpectingResult( - R"('encodeUtf8' in protectedAudience? 3 : 2)", 3); - RunScoreAdWithReturnValueExpectingResult( - R"('decodeUtf8' in protectedAudience? 3 : 2)", 3); - - RunScoreAdWithReturnValueExpectingResult( - "protectedAudience.encodeUtf8('A')[0]", 65); - RunScoreAdWithReturnValueExpectingResult( - "protectedAudience.decodeUtf8(new Uint8Array([65, 68])) === 'AD' ? 3 : 2", - 3); -} - TEST_F(SellerWorkletTest, ScoreAdNoGlobalStomp) { const char kScript[] = R"( function protectedAudience() { @@ -3564,24 +3535,6 @@ /*expected_signals_for_winner=*/"1", GURL("https://foo.test/?2")); } -TEST_F(SellerWorkletNoTextConversionsTest, ReportResultTextConversions) { - RunReportResultCreatedScriptExpectingResult( - "('protectedAudience' in globalThis) ? 2 : 1", - /*extra_code=*/std::string(), "1", - /*expected_report_url=*/std::nullopt); -} - -TEST_F(SellerWorkletTest, ReportResultTextConversions) { - RunReportResultCreatedScriptExpectingResult( - "('encodeUtf8' in protectedAudience) ? 2 : 1", - /*extra_code=*/std::string(), "2", - /*expected_report_url=*/std::nullopt); - RunReportResultCreatedScriptExpectingResult( - "('decodeUtf8' in protectedAudience) ? 2 : 1", - /*extra_code=*/std::string(), "2", - /*expected_report_url=*/std::nullopt); -} - TEST_F(SellerWorkletTest, ReportResultNoGlobalStomp) { const char kScript[] = R"( function protectedAudience() {
diff --git a/content/services/auction_worklet/text_conversion_helpers.cc b/content/services/auction_worklet/text_conversion_helpers.cc deleted file mode 100644 index 2ef93f56..0000000 --- a/content/services/auction_worklet/text_conversion_helpers.cc +++ /dev/null
@@ -1,145 +0,0 @@ -// Copyright 2025 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/services/auction_worklet/text_conversion_helpers.h" - -#include "base/compiler_specific.h" -#include "base/memory/ref_counted.h" -#include "content/services/auction_worklet/auction_v8_helper.h" -#include "content/services/auction_worklet/public/cpp/auction_worklet_features.h" -#include "content/services/auction_worklet/webidl_compat.h" -#include "gin/public/gin_embedders.h" -#include "v8/include/v8-array-buffer.h" -#include "v8/include/v8-exception.h" -#include "v8/include/v8-function-callback.h" -#include "v8/include/v8-function.h" -#include "v8/include/v8-primitive.h" -#include "v8/include/v8-typed-array.h" - -namespace auction_worklet { - -TextConversionHelpers::TextConversionHelpers(AuctionV8Helper* v8_helper) - : v8_helper_(v8_helper) {} - -void TextConversionHelpers::AttachToContext(v8::Local<v8::Context> context) { - if (!base::FeatureList::IsEnabled(features::kFledgeTextConversionHelpers)) { - return; - } - - v8::Local<v8::External> v8_this = v8::External::New( - v8_helper_->isolate(), this, gin::kTextConversionHelpersTag); - v8::Local<v8::Function> encode = - v8::Function::New(context, &TextConversionHelpers::EncodeUtf8, v8_this) - .ToLocalChecked(); - v8::Local<v8::Function> decode = - v8::Function::New(context, &TextConversionHelpers::DecodeUtf8, v8_this) - .ToLocalChecked(); - v8::Local<v8::Object> pa_object = v8::Object::New(v8_helper_->isolate()); - context->Global() - ->Set(context, v8_helper_->CreateStringFromLiteral("protectedAudience"), - pa_object) - .Check(); - pa_object - ->Set(context, v8_helper_->CreateStringFromLiteral("encodeUtf8"), encode) - .Check(); - pa_object - ->Set(context, v8_helper_->CreateStringFromLiteral("decodeUtf8"), decode) - .Check(); -} - -void TextConversionHelpers::Reset() {} - -void TextConversionHelpers::EncodeUtf8( - const v8::FunctionCallbackInfo<v8::Value>& args) { - TextConversionHelpers* bindings = static_cast<TextConversionHelpers*>( - v8::External::Cast(*args.Data())->Value(gin::kTextConversionHelpersTag)); - AuctionV8Helper* v8_helper = bindings->v8_helper_; - v8::Isolate* isolate = v8_helper->isolate(); - - AuctionV8Helper::TimeLimitScope time_limit_scope(v8_helper->GetTimeLimit()); - ArgsConverter args_converter(v8_helper, time_limit_scope, "encodeUtf8 ", - &args, - /*min_required_args=*/1); - if (!args_converter.is_success()) { - args_converter.TakeStatus().PropagateErrorsToV8(v8_helper); - return; - } - - // We don't use webidl_compat to do the string conversion here since we don't - // want the output as a std::string, we want to stick it into a UInt8Array. - // (Also it would get DOMString and not USVString semantics, but that's - // secondary). - v8::Local<v8::String> v8_string; - IdlConvert::Status conversion_status; - { - if (args[0]->IsString()) { - v8_string = args[0].As<v8::String>(); - } else { - v8::TryCatch try_catch(isolate); - if (!args[0] - ->ToString(isolate->GetCurrentContext()) - .ToLocal(&v8_string)) { - conversion_status = IdlConvert::MakeConversionFailure( - try_catch, "encodeUtf8 ", {"argument 0"}, "String"); - } - } - } - - if (!conversion_status.is_success()) { - conversion_status.PropagateErrorsToV8(v8_helper); - return; - } - - size_t required_len = v8_string->Utf8LengthV2(isolate); - v8::Local<v8::ArrayBuffer> buffer; - if (!v8::ArrayBuffer::MaybeNew( - isolate, required_len, - v8::BackingStoreInitializationMode::kZeroInitialized) - .ToLocal(&buffer)) { - isolate->ThrowException( - v8::Exception::TypeError(v8_helper->CreateStringFromLiteral( - "Unable to allocate buffer for result"))); - return; - } - - size_t used_len = v8_string->WriteUtf8V2( - isolate, reinterpret_cast<char*>(buffer->Data()), buffer->ByteLength(), - v8::String::WriteFlags::kReplaceInvalidUtf8); - - // The length should be as expected (despite Utf8LengthV2 not knowing about - // kReplaceInvalidUtf8) since a mismatched surrogate and the unicode - // replacement character both end up the same length (3 bytes). - DCHECK_EQ(used_len, required_len); - args.GetReturnValue().Set(v8::Uint8Array::New(buffer, - /*byte_offset=*/0, - /*length=*/used_len)); -} - -void TextConversionHelpers::DecodeUtf8( - const v8::FunctionCallbackInfo<v8::Value>& args) { - TextConversionHelpers* bindings = static_cast<TextConversionHelpers*>( - v8::External::Cast(*args.Data())->Value(gin::kTextConversionHelpersTag)); - AuctionV8Helper* v8_helper = bindings->v8_helper_; - v8::Isolate* isolate = v8_helper->isolate(); - - if (!args[0]->IsUint8Array()) { - isolate->ThrowException( - v8::Exception::TypeError(v8_helper->CreateStringFromLiteral( - "decodeUtf8 expects a Uint8Array argument"))); - return; - } - - v8::Local<v8::Uint8Array> array = args[0].As<v8::Uint8Array>(); - // SAFETY: Uint8Array data is from ByteOffset and of length ByteLength inside - // the ArrayBuffer it wraps. - args.GetReturnValue().Set( - v8::String::NewFromUtf8( - isolate, - UNSAFE_BUFFERS(reinterpret_cast<char*>(array->Buffer()->Data()) + - array->ByteOffset()), - v8::NewStringType::kNormal, array->ByteLength()) - .ToLocalChecked()); -} - -} // namespace auction_worklet
diff --git a/content/services/auction_worklet/text_conversion_helpers.h b/content/services/auction_worklet/text_conversion_helpers.h deleted file mode 100644 index d50a781..0000000 --- a/content/services/auction_worklet/text_conversion_helpers.h +++ /dev/null
@@ -1,34 +0,0 @@ -// Copyright 2025 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_SERVICES_AUCTION_WORKLET_TEXT_CONVERSION_HELPERS_H_ -#define CONTENT_SERVICES_AUCTION_WORKLET_TEXT_CONVERSION_HELPERS_H_ - -#include "content/common/content_export.h" -#include "content/services/auction_worklet/context_recycler.h" -#include "v8/include/v8-forward.h" - -namespace auction_worklet { - -class AuctionV8Helper; - -// Utilities to add JS functions to help convert between JS Strings and utf-8 -// arrays. -class CONTENT_EXPORT TextConversionHelpers : public Bindings { - public: - explicit TextConversionHelpers(AuctionV8Helper* v8_helper); - - void AttachToContext(v8::Local<v8::Context> context) override; - void Reset() override; - - private: - static void EncodeUtf8(const v8::FunctionCallbackInfo<v8::Value>& args); - static void DecodeUtf8(const v8::FunctionCallbackInfo<v8::Value>& args); - - const raw_ptr<AuctionV8Helper> v8_helper_; -}; - -} // namespace auction_worklet - -#endif // CONTENT_SERVICES_AUCTION_WORKLET_TEXT_CONVERSION_HELPERS_H_
diff --git a/content/test/data/accessibility/aria/annotation-roles-expected-android-external.txt b/content/test/data/accessibility/aria/annotation-roles-expected-android-external.txt index 3b4895f0..3b021c60 100644 --- a/content/test/data/accessibility/aria/annotation-roles-expected-android-external.txt +++ b/content/test/data/accessibility/aria/annotation-roles-expected-android-external.txt
@@ -1,6 +1,6 @@ WebView focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] -++View text:"comment" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="comment", roleDescription="comment"] -++View text:"suggestion" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="suggestion", roleDescription="suggestion"] +++View supplementalDescription:"comment" actions:[AX_FOCUS] bundle:[chromeRole="comment", roleDescription="comment"] +++View supplementalDescription:"suggestion" actions:[AX_FOCUS] bundle:[chromeRole="suggestion", roleDescription="suggestion"] ++View actions:[AX_FOCUS] bundle:[chromeRole="paragraph"] ++++TextView text:"This is " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] ++++View text:"highlighted" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="mark", roleDescription="highlight"]
diff --git a/content/test/data/accessibility/aria/apg-patterns/aria-accordion-expected-android-external.txt b/content/test/data/accessibility/aria/apg-patterns/aria-accordion-expected-android-external.txt index ee8a2af..fd285fa6 100644 --- a/content/test/data/accessibility/aria/apg-patterns/aria-accordion-expected-android-external.txt +++ b/content/test/data/accessibility/aria/apg-patterns/aria-accordion-expected-android-external.txt
@@ -6,9 +6,9 @@ ++++++View actions:[AX_FOCUS] bundle:[chromeRole="group"] ++++++++View actions:[AX_FOCUS] bundle:[chromeRole="paragraph"] ++++++++++View text:"Name : " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="labelText"] -++++++++++EditText hint:"Name :" viewIdResName:"cufc1" clickable editable focusable required inputType:1 textSelectionStart:0 textSelectionEnd:0 actions:[FOCUS, CLICK, AX_FOCUS, PASTE, SET_TEXT, IME_ENTER] bundle:[chromeRole="textField", clickableScore="300", hint="Name :"] +++++++++++EditText viewIdResName:"cufc1" supplementalDescription:"Name :" clickable editable focusable required inputType:1 textSelectionStart:0 textSelectionEnd:0 actions:[FOCUS, CLICK, AX_FOCUS, PASTE, SET_TEXT, IME_ENTER] bundle:[chromeRole="textField", clickableScore="300"] ++++++++View actions:[AX_FOCUS] bundle:[chromeRole="paragraph"] ++++++++++View text:"Phone: " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="labelText"] -++++++++++EditText hint:"Phone:" viewIdResName:"cufc3" clickable editable focusable inputType:1 textSelectionStart:0 textSelectionEnd:0 actions:[FOCUS, CLICK, AX_FOCUS, PASTE, SET_TEXT, IME_ENTER] bundle:[chromeRole="textField", clickableScore="300", hint="Phone:"] +++++++++++EditText viewIdResName:"cufc3" supplementalDescription:"Phone:" clickable editable focusable inputType:1 textSelectionStart:0 textSelectionEnd:0 actions:[FOCUS, CLICK, AX_FOCUS, PASTE, SET_TEXT, IME_ENTER] bundle:[chromeRole="textField", clickableScore="300"] ++++View text:"Billing Address" heading actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="heading", roleDescription="heading 3"] ++++++Button text:"Billing Address" viewIdResName:"accordion2id" clickable focusable expandedState:1 actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS, EXPAND] bundle:[chromeRole="button", clickableScore="300"]
diff --git a/content/test/data/accessibility/aria/apg-patterns/aria-alertdialog-expected-android-external.txt b/content/test/data/accessibility/aria/apg-patterns/aria-alertdialog-expected-android-external.txt index 0f53c7a10..426d1fe 100644 --- a/content/test/data/accessibility/aria/apg-patterns/aria-alertdialog-expected-android-external.txt +++ b/content/test/data/accessibility/aria/apg-patterns/aria-alertdialog-expected-android-external.txt
@@ -1,5 +1,5 @@ WebView focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] -++AlertDialog text:"Confirmation" hint:"Are you sure you want to discard all of your notes?" viewIdResName:"alertdialog" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="alertDialog", hint="Are you sure you want to discard all of your notes?"] +++AlertDialog hint:"Are you sure you want to discard all of your notes?" viewIdResName:"alertdialog" supplementalDescription:"Confirmation" actions:[AX_FOCUS] bundle:[chromeRole="alertDialog", hint="Are you sure you want to discard all of your notes?"] ++++TextView text:"Confirmation" viewIdResName:"dialog_label" heading actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="heading", roleDescription="heading 2"] ++++View viewIdResName:"dialog_desc" actions:[AX_FOCUS] bundle:[chromeRole="genericContainer"] ++++++TextView text:"Are you sure you want to discard all of your notes?" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="paragraph"]
diff --git a/content/test/data/accessibility/aria/apg-patterns/aria-carousel-tabs-expected-android-external.txt b/content/test/data/accessibility/aria/apg-patterns/aria-carousel-tabs-expected-android-external.txt index bf8ea240..52d575b 100644 --- a/content/test/data/accessibility/aria/apg-patterns/aria-carousel-tabs-expected-android-external.txt +++ b/content/test/data/accessibility/aria/apg-patterns/aria-carousel-tabs-expected-android-external.txt
@@ -5,7 +5,7 @@ ++++++View contentDescription:"Slide 1" viewIdResName:"carousel-tab-1" clickable focusable selected CollectionItemInfo:[rowSpan=0, colSpan=0, rowIndex=0, colIndex=0] actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="tab", clickableScore="300", roleDescription="tab"] ++++++View contentDescription:"Slide 2" viewIdResName:"carousel-tab-2" clickable focusable CollectionItemInfo:[rowSpan=0, colSpan=0, rowIndex=1, colIndex=0] actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="tab", clickableScore="300", roleDescription="tab"] ++++View viewIdResName:"myCarousel-items" actions:[AX_FOCUS] bundle:[chromeRole="genericContainer", hasImage="true"] -++++++View text:"1 of 2" viewIdResName:"carousel-item-1" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="tabPanel", hasImage="true", roleDescription="slide"] +++++++View viewIdResName:"carousel-item-1" supplementalDescription:"1 of 2" actions:[AX_FOCUS] bundle:[chromeRole="tabPanel", hasImage="true", roleDescription="slide"] ++++++++View actions:[AX_FOCUS] bundle:[chromeRole="genericContainer", hasImage="true"] ++++++++++View text:"null" contentDescription:"Walking Tour in Amsterdam" viewIdResName:"carousel-image-1" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="link", clickableScore="300", hasImage="true", roleDescription="link", targetUrl="file:///storage/emulated/0/chromium_tests_root/content/test/data/accessibility/aria/apg-patterns/aria-carousel-tabs.html#"] ++++++++++++Image contentDescription:"Walking Tour in Amsterdam" actions:[AX_FOCUS] bundle:[chromeRole="image", clickableScore="100", hasImage="true", targetUrl="file:///storage/emulated/0/chromium_tests_root/content/test/data/accessibility/aria/apg-patterns/"]
diff --git a/content/test/data/accessibility/aria/apg-patterns/aria-quantity-spinbutton-expected-android-external.txt b/content/test/data/accessibility/aria/apg-patterns/aria-quantity-spinbutton-expected-android-external.txt index 0ecede6..03f04d0 100644 --- a/content/test/data/accessibility/aria/apg-patterns/aria-quantity-spinbutton-expected-android-external.txt +++ b/content/test/data/accessibility/aria/apg-patterns/aria-quantity-spinbutton-expected-android-external.txt
@@ -4,8 +4,8 @@ ++++View text:"Adults" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="labelText"] ++++View actions:[AX_FOCUS] bundle:[chromeRole="genericContainer"] ++++++Button text:"Remove adult" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="button", clickableScore="300"] -++++++EditText viewIdResName:"adults" stateDescription:"1" clickable editable focusable inputType:1 textSelectionStart:0 textSelectionEnd:0 actions:[FOCUS, CLICK, AX_FOCUS, COPY, PASTE, CUT, SET_SELECTION, SET_TEXT, SET_PROGRESS, IME_ENTER] bundle:[chromeRole="spinButton", clickableScore="300", roleDescription="spin button"] +++++++EditText viewIdResName:"adults" stateDescription:"1" supplementalDescription:"Adults" clickable editable focusable inputType:1 textSelectionStart:0 textSelectionEnd:0 actions:[FOCUS, CLICK, AX_FOCUS, COPY, PASTE, CUT, SET_SELECTION, SET_TEXT, SET_PROGRESS, IME_ENTER] bundle:[chromeRole="spinButton", clickableScore="300", roleDescription="spin button"] ++++++Button text:"Add adult" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="button", clickableScore="300"] ++++TextView text:"Must be between 1 and 8 " viewIdResName:"error-adults" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="genericContainer"] ++++TextView text:"1 to 8" viewIdResName:"help-adults" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="genericContainer"] -++++View liveRegion:1 actions:[AX_FOCUS] bundle:[chromeRole="status", roleDescription="status"] \ No newline at end of file +++++View liveRegion:1 actions:[AX_FOCUS] bundle:[chromeRole="status", roleDescription="status"]
diff --git a/content/test/data/accessibility/aria/apg-patterns/aria-slider-color-viewer-expected-android-external.txt b/content/test/data/accessibility/aria/apg-patterns/aria-slider-color-viewer-expected-android-external.txt index 0824ab5..73664e5e 100644 --- a/content/test/data/accessibility/aria/apg-patterns/aria-slider-color-viewer-expected-android-external.txt +++ b/content/test/data/accessibility/aria/apg-patterns/aria-slider-color-viewer-expected-android-external.txt
@@ -2,8 +2,8 @@ ++View containerTitle:"Color Viewer" actions:[AX_FOCUS] bundle:[chromeRole="group"] ++++TextView text:"Color Viewer" viewIdResName:"id-color-viewer" heading actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="heading", roleDescription="heading 3"] ++++TextView text:"Red" viewIdResName:"id-red" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="genericContainer"] -++++SeekBar text:"Red" clickable focusable RangeInfo:[current=128.0, min=0.0, max=255.0] actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS, SET_PROGRESS] bundle:[chromeRole="slider"] +++++SeekBar supplementalDescription:"Red" clickable focusable RangeInfo:[current=128.0, min=0.0, max=255.0] actions:[FOCUS, CLICK, AX_FOCUS, SET_PROGRESS] bundle:[chromeRole="slider"] ++++TextView text:"Color View Box" heading actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="heading", roleDescription="heading 4"] ++++View actions:[AX_FOCUS] bundle:[chromeRole="labelText"] ++++++TextView text:"Color (HEX): " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] -++++++EditText hint:"Color (HEX):" clickable focusable inputType:1 textSelectionStart:0 textSelectionEnd:0 actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="textField", clickableScore="300", hint="Color (HEX):"] +++++++EditText supplementalDescription:"Color (HEX):" clickable focusable inputType:1 textSelectionStart:0 textSelectionEnd:0 actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="textField", clickableScore="300"]
diff --git a/content/test/data/accessibility/aria/apg-patterns/aria-slider-multithumb-expected-android-external.txt b/content/test/data/accessibility/aria/apg-patterns/aria-slider-multithumb-expected-android-external.txt index 62cf74d..9a68724 100644 --- a/content/test/data/accessibility/aria/apg-patterns/aria-slider-multithumb-expected-android-external.txt +++ b/content/test/data/accessibility/aria/apg-patterns/aria-slider-multithumb-expected-android-external.txt
@@ -1,5 +1,5 @@ WebView focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] ++View text:"Hotel Price Range (in USD )" heading actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="heading", roleDescription="heading 3"] ++View actions:[AX_FOCUS] bundle:[chromeRole="genericContainer"] -++++SeekBar text:"Hotel Minimum Price in US dollars" clickable focusable RangeInfo:[current=100.0, min=0.0, max=250.0] actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS, SET_PROGRESS] bundle:[chromeRole="slider"] -++++SeekBar text:"Hotel Maximum Price in US dollars" clickable focusable RangeInfo:[current=250.0, min=100.0, max=400.0] actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS, SET_PROGRESS] bundle:[chromeRole="slider"] +++++SeekBar supplementalDescription:"Hotel Minimum Price in US dollars" clickable focusable RangeInfo:[current=100.0, min=0.0, max=250.0] actions:[FOCUS, CLICK, AX_FOCUS, SET_PROGRESS] bundle:[chromeRole="slider"] +++++SeekBar supplementalDescription:"Hotel Maximum Price in US dollars" clickable focusable RangeInfo:[current=250.0, min=100.0, max=400.0] actions:[FOCUS, CLICK, AX_FOCUS, SET_PROGRESS] bundle:[chromeRole="slider"]
diff --git a/content/test/data/accessibility/aria/apg-patterns/aria-slider-rating-expected-android-external.txt b/content/test/data/accessibility/aria/apg-patterns/aria-slider-rating-expected-android-external.txt index 5fc9a55..0ef1fde 100644 --- a/content/test/data/accessibility/aria/apg-patterns/aria-slider-rating-expected-android-external.txt +++ b/content/test/data/accessibility/aria/apg-patterns/aria-slider-rating-expected-android-external.txt
@@ -1,3 +1,3 @@ WebView focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] ++TextView text:"Rate your satisfaction with the service you received" viewIdResName:"id-rating-label" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="genericContainer"] -++SeekBar viewIdResName:"id-rating" stateDescription:"Choose a rating from 1 to 3 where 3 is extremely satisfied" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, SET_PROGRESS] bundle:[chromeRole="slider"] +++SeekBar viewIdResName:"id-rating" stateDescription:"Choose a rating from 1 to 3 where 3 is extremely satisfied" supplementalDescription:"Rate your satisfaction with the service you received" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, SET_PROGRESS] bundle:[chromeRole="slider"]
diff --git a/content/test/data/accessibility/aria/apg-patterns/aria-slider-vertical-expected-android-external.txt b/content/test/data/accessibility/aria/apg-patterns/aria-slider-vertical-expected-android-external.txt index 59e32f3..80b796f1 100644 --- a/content/test/data/accessibility/aria/apg-patterns/aria-slider-vertical-expected-android-external.txt +++ b/content/test/data/accessibility/aria/apg-patterns/aria-slider-vertical-expected-android-external.txt
@@ -1,3 +1,3 @@ WebView focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] ++TextView text:"Temperature" viewIdResName:"id-temp-label" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="genericContainer"] -++SeekBar viewIdResName:"id-temp-slider" stateDescription:"25.0 degrees Celsius" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, SET_PROGRESS] bundle:[chromeRole="slider"] +++SeekBar viewIdResName:"id-temp-slider" stateDescription:"25.0 degrees Celsius" supplementalDescription:"Temperature" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, SET_PROGRESS] bundle:[chromeRole="slider"]
diff --git a/content/test/data/accessibility/aria/apg-patterns/aria-treeview-file-directory-computed-properties-expected-android-external.txt b/content/test/data/accessibility/aria/apg-patterns/aria-treeview-file-directory-computed-properties-expected-android-external.txt index 8d42749..8df14add 100644 --- a/content/test/data/accessibility/aria/apg-patterns/aria-treeview-file-directory-computed-properties-expected-android-external.txt +++ b/content/test/data/accessibility/aria/apg-patterns/aria-treeview-file-directory-computed-properties-expected-android-external.txt
@@ -2,26 +2,26 @@ ++TextView text:"My Documents" viewIdResName:"tree_label" heading actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="heading", roleDescription="heading 3"] ++View containerTitle:"My Documents" CollectionInfo:[hierarchical, rows=2, cols=0] actions:[AX_FOCUS] bundle:[chromeRole="tree", roleDescription="tree"] ++++View text:"Projects" clickable expandedState:1 CollectionItemInfo:[rowSpan=0, colSpan=0, rowIndex=0, colIndex=0] actions:[CLICK, AX_FOCUS, NEXT, PREVIOUS, EXPAND] bundle:[chromeRole="treeItem", roleDescription="tree item"] -++++++TextView text:"• " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] +++++++TextView text:"• " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] ++++++TextView text:"Projects" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] ++++++View actions:[AX_FOCUS] bundle:[chromeRole="group"] ++++++++View text:"project-1.docx" clickable CollectionItemInfo:[rowSpan=0, colSpan=0, rowIndex=0, colIndex=0] actions:[CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="treeItem", roleDescription="tree item"] ++++++++View text:"Project 3" clickable expandedState:1 CollectionItemInfo:[rowSpan=0, colSpan=0, rowIndex=1, colIndex=0] actions:[CLICK, AX_FOCUS, NEXT, PREVIOUS, EXPAND] bundle:[chromeRole="treeItem", roleDescription="tree item"] -++++++++++TextView text:"â—¦ " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] +++++++++++TextView text:"â—¦ " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] ++++++++++TextView text:"Project 3" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] ++++++++++View actions:[AX_FOCUS] bundle:[chromeRole="group"] ++++++++++++View text:"project-3A.docx" clickable CollectionItemInfo:[rowSpan=0, colSpan=0, rowIndex=0, colIndex=0] actions:[CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="treeItem", roleDescription="tree item"] ++++++++View text:"project-4.docx" clickable CollectionItemInfo:[rowSpan=0, colSpan=0, rowIndex=2, colIndex=0] actions:[CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="treeItem", roleDescription="tree item"] ++++View text:"Reports File or Folder Selected: " clickable expandedState:1 CollectionItemInfo:[rowSpan=0, colSpan=0, rowIndex=1, colIndex=0] actions:[CLICK, AX_FOCUS, NEXT, PREVIOUS, EXPAND] bundle:[chromeRole="treeItem", roleDescription="tree item"] -++++++TextView text:"• " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] +++++++TextView text:"• " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] ++++++TextView text:"Reports" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] ++++++View actions:[AX_FOCUS] bundle:[chromeRole="group"] ++++++++View text:"report-1" clickable expandedState:1 CollectionItemInfo:[rowSpan=0, colSpan=0, rowIndex=0, colIndex=0] actions:[CLICK, AX_FOCUS, NEXT, PREVIOUS, EXPAND] bundle:[chromeRole="treeItem", roleDescription="tree item"] -++++++++++TextView text:"â—¦ " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] +++++++++++TextView text:"â—¦ " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] ++++++++++TextView text:"report-1" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] ++++++++++View actions:[AX_FOCUS] bundle:[chromeRole="group"] ++++++++++++View text:"report-1A.docx" clickable CollectionItemInfo:[rowSpan=0, colSpan=0, rowIndex=0, colIndex=0] actions:[CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="treeItem", roleDescription="tree item"] ++++++View actions:[AX_FOCUS] bundle:[chromeRole="paragraph"] ++++++++View actions:[AX_FOCUS] bundle:[chromeRole="labelText"] ++++++++++TextView text:"File or Folder Selected: " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] -++++++++++EditText hint:"File or Folder Selected:" viewIdResName:"last_action" clickable focusable inputType:1 textSelectionStart:0 textSelectionEnd:0 actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="textField", clickableScore="300", hint="File or Folder Selected:"] \ No newline at end of file +++++++++++EditText viewIdResName:"last_action" supplementalDescription:"File or Folder Selected:" clickable focusable inputType:1 textSelectionStart:0 textSelectionEnd:0 actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="textField", clickableScore="300"]
diff --git a/content/test/data/accessibility/aria/apg-patterns/aria-treeview-file-directory-declared-properties-expected-android-external.txt b/content/test/data/accessibility/aria/apg-patterns/aria-treeview-file-directory-declared-properties-expected-android-external.txt index ed74243d..1a306ed 100644 --- a/content/test/data/accessibility/aria/apg-patterns/aria-treeview-file-directory-declared-properties-expected-android-external.txt +++ b/content/test/data/accessibility/aria/apg-patterns/aria-treeview-file-directory-declared-properties-expected-android-external.txt
@@ -2,26 +2,26 @@ ++TextView text:"My Documents" viewIdResName:"tree1" heading actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="heading", roleDescription="heading 3"] ++View containerTitle:"My Documents" CollectionInfo:[hierarchical, rows=2, cols=0] actions:[AX_FOCUS] bundle:[chromeRole="tree", roleDescription="tree"] ++++View text:"Projects" clickable expandedState:1 CollectionItemInfo:[rowSpan=0, colSpan=0, rowIndex=0, colIndex=0] actions:[CLICK, AX_FOCUS, NEXT, PREVIOUS, EXPAND] bundle:[chromeRole="treeItem", roleDescription="tree item"] -++++++TextView text:"• " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] +++++++TextView text:"• " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] ++++++TextView text:"Projects" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] ++++++View actions:[AX_FOCUS] bundle:[chromeRole="group"] ++++++++View text:"project-1.docx" clickable CollectionItemInfo:[rowSpan=0, colSpan=0, rowIndex=0, colIndex=0] actions:[CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="treeItem", roleDescription="tree item"] ++++++++View text:"Project 3" clickable expandedState:1 CollectionItemInfo:[rowSpan=0, colSpan=0, rowIndex=1, colIndex=0] actions:[CLICK, AX_FOCUS, NEXT, PREVIOUS, EXPAND] bundle:[chromeRole="treeItem", roleDescription="tree item"] -++++++++++TextView text:"â—¦ " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] +++++++++++TextView text:"â—¦ " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] ++++++++++TextView text:"Project 3" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] ++++++++++View actions:[AX_FOCUS] bundle:[chromeRole="group"] ++++++++++++View text:"project-3A.docx" clickable CollectionItemInfo:[rowSpan=0, colSpan=0, rowIndex=0, colIndex=0] actions:[CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="treeItem", roleDescription="tree item"] ++++++++View text:"project-4.docx" clickable CollectionItemInfo:[rowSpan=0, colSpan=0, rowIndex=2, colIndex=0] actions:[CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="treeItem", roleDescription="tree item"] ++++View text:"Reports" clickable expandedState:1 CollectionItemInfo:[rowSpan=0, colSpan=0, rowIndex=1, colIndex=0] actions:[CLICK, AX_FOCUS, NEXT, PREVIOUS, EXPAND] bundle:[chromeRole="treeItem", roleDescription="tree item"] -++++++TextView text:"• " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] +++++++TextView text:"• " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] ++++++TextView text:"Reports" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] ++++++View actions:[AX_FOCUS] bundle:[chromeRole="group"] ++++++++View text:"report-1" clickable expandedState:1 CollectionItemInfo:[rowSpan=0, colSpan=0, rowIndex=0, colIndex=0] actions:[CLICK, AX_FOCUS, NEXT, PREVIOUS, EXPAND] bundle:[chromeRole="treeItem", roleDescription="tree item"] -++++++++++TextView text:"â—¦ " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] +++++++++++TextView text:"â—¦ " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] ++++++++++TextView text:"report-1" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] ++++++++++View actions:[AX_FOCUS] bundle:[chromeRole="group"] ++++++++++++View text:"report-1A.docx" clickable CollectionItemInfo:[rowSpan=0, colSpan=0, rowIndex=0, colIndex=0] actions:[CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="treeItem", roleDescription="tree item"] ++View actions:[AX_FOCUS] bundle:[chromeRole="paragraph"] ++++View actions:[AX_FOCUS] bundle:[chromeRole="labelText"] ++++++TextView text:"File or Folder Selected: " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] -++++++EditText hint:"File or Folder Selected:" viewIdResName:"last_action" clickable focusable inputType:1 textSelectionStart:0 textSelectionEnd:0 actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="textField", clickableScore="300", hint="File or Folder Selected:"] \ No newline at end of file +++++++EditText viewIdResName:"last_action" supplementalDescription:"File or Folder Selected:" clickable focusable inputType:1 textSelectionStart:0 textSelectionEnd:0 actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="textField", clickableScore="300"]
diff --git a/content/test/data/accessibility/aria/aria-busy-expected-android-external.txt b/content/test/data/accessibility/aria/aria-busy-expected-android-external.txt index f1dfff84..0e39a459 100644 --- a/content/test/data/accessibility/aria/aria-busy-expected-android-external.txt +++ b/content/test/data/accessibility/aria/aria-busy-expected-android-external.txt
@@ -1,4 +1,4 @@ WebView focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] -++View text:"Busy log" focusable liveRegion:1 actions:[FOCUS, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="log", roleDescription="log"] -++View text:"Not-busy log" focusable liveRegion:1 actions:[FOCUS, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="log", roleDescription="log"] +++View supplementalDescription:"Busy log" focusable liveRegion:1 actions:[FOCUS, AX_FOCUS] bundle:[chromeRole="log", roleDescription="log"] +++View supplementalDescription:"Not-busy log" focusable liveRegion:1 actions:[FOCUS, AX_FOCUS] bundle:[chromeRole="log", roleDescription="log"] ++TextView hint:"plain div" actions:[AX_FOCUS] bundle:[chromeRole="genericContainer", hint="plain div"]
diff --git a/content/test/data/accessibility/aria/aria-code-expected-android-external.txt b/content/test/data/accessibility/aria/aria-code-expected-android-external.txt index 31840f3e..d8cfcb1 100644 --- a/content/test/data/accessibility/aria/aria-code-expected-android-external.txt +++ b/content/test/data/accessibility/aria/aria-code-expected-android-external.txt
@@ -2,4 +2,4 @@ ++View text:"role" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="code"] ++View text:"element (no name)" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="code"] ++TextView text:" " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] -++View text:"include me" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="code"] +++View text:"element (with name)" supplementalDescription:"include me" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="code"]
diff --git a/content/test/data/accessibility/aria/aria-description-expected-android-external.txt b/content/test/data/accessibility/aria/aria-description-expected-android-external.txt index 74f9c3b6..fd9ffff 100644 --- a/content/test/data/accessibility/aria/aria-description-expected-android-external.txt +++ b/content/test/data/accessibility/aria/aria-description-expected-android-external.txt
@@ -1,4 +1,4 @@ WebView focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] -++TextView text:"description" hint:"Text-description" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="genericContainer", hint="Text-description"] -++TextView text:"both" hint:"Description from describedby" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="genericContainer", hint="Description from describedby"] +++TextView hint:"Text-description" supplementalDescription:"description" actions:[AX_FOCUS] bundle:[chromeRole="genericContainer", hint="Text-description"] +++TextView hint:"Description from describedby" supplementalDescription:"both" actions:[AX_FOCUS] bundle:[chromeRole="genericContainer", hint="Description from describedby"] ++View text:"Description from describedby" viewIdResName:"desc1" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="tooltip", roleDescription="tooltip"]
diff --git a/content/test/data/accessibility/aria/aria-emphasis-expected-android-external.txt b/content/test/data/accessibility/aria/aria-emphasis-expected-android-external.txt index 42917de..74e7ffb 100644 --- a/content/test/data/accessibility/aria/aria-emphasis-expected-android-external.txt +++ b/content/test/data/accessibility/aria/aria-emphasis-expected-android-external.txt
@@ -2,4 +2,4 @@ ++View text:"role" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="emphasis"] ++View text:"element (no name)" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="emphasis"] ++TextView text:" " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] -++View text:"include me" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="emphasis"] +++View text:"element (with name)" supplementalDescription:"include me" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="emphasis"]
diff --git a/content/test/data/accessibility/aria/aria-flowto-expected-android-external.txt b/content/test/data/accessibility/aria/aria-flowto-expected-android-external.txt index fb5d5661..0ebbd67 100644 --- a/content/test/data/accessibility/aria/aria-flowto-expected-android-external.txt +++ b/content/test/data/accessibility/aria/aria-flowto-expected-android-external.txt
@@ -1,3 +1,3 @@ WebView focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] ++View text:"Lorem ipsum" containerTitle:"current" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="region", roleDescription="region"] -++View text:"next" viewIdResName:"next" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="footer", roleDescription="footer"] +++View text:"dolor sit amet" viewIdResName:"next" supplementalDescription:"next" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="footer", roleDescription="footer"]
diff --git a/content/test/data/accessibility/aria/aria-hidden-described-by-expected-android-external.txt b/content/test/data/accessibility/aria/aria-hidden-described-by-expected-android-external.txt index cfe6fc7..6ea2ada 100644 --- a/content/test/data/accessibility/aria/aria-hidden-described-by-expected-android-external.txt +++ b/content/test/data/accessibility/aria/aria-hidden-described-by-expected-android-external.txt
@@ -1,6 +1,6 @@ WebView focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] ++View actions:[AX_FOCUS] bundle:[chromeRole="genericContainer"] -++++TextView text:"span-A" hint:"span-1" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="genericContainer", hint="span-1"] -++++TextView text:"span-B" hint:"span-2" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="genericContainer", hint="span-2"] -++++TextView text:"span-C" hint:"span-3" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="genericContainer", hint="span-3"] -++++TextView text:"span-D" hint:"span-4" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="genericContainer", hint="span-4"] +++++TextView hint:"span-1" supplementalDescription:"span-A" actions:[AX_FOCUS] bundle:[chromeRole="genericContainer", hint="span-1"] +++++TextView hint:"span-2" supplementalDescription:"span-B" actions:[AX_FOCUS] bundle:[chromeRole="genericContainer", hint="span-2"] +++++TextView hint:"span-3" supplementalDescription:"span-C" actions:[AX_FOCUS] bundle:[chromeRole="genericContainer", hint="span-3"] +++++TextView hint:"span-4" supplementalDescription:"span-D" actions:[AX_FOCUS] bundle:[chromeRole="genericContainer", hint="span-4"]
diff --git a/content/test/data/accessibility/aria/aria-hidden-labelled-by-expected-android-external.txt b/content/test/data/accessibility/aria/aria-hidden-labelled-by-expected-android-external.txt index 9c0eb01..6fd6753e 100644 --- a/content/test/data/accessibility/aria/aria-hidden-labelled-by-expected-android-external.txt +++ b/content/test/data/accessibility/aria/aria-hidden-labelled-by-expected-android-external.txt
@@ -1,7 +1,7 @@ WebView focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] ++View actions:[AX_FOCUS] bundle:[chromeRole="genericContainer"] -++++TextView text:"span-2" viewIdResName:"s2" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="genericContainer"] -++++TextView text:"span-4" viewIdResName:"s3" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="genericContainer"] +++++TextView viewIdResName:"s2" supplementalDescription:"span-2" actions:[AX_FOCUS] bundle:[chromeRole="genericContainer"] +++++TextView viewIdResName:"s3" supplementalDescription:"span-4" actions:[AX_FOCUS] bundle:[chromeRole="genericContainer"] ++++View containerTitle:"span-1" actions:[AX_FOCUS] bundle:[chromeRole="group"] ++++View containerTitle:"span-2" actions:[AX_FOCUS] bundle:[chromeRole="group"] ++++View containerTitle:"span-3" actions:[AX_FOCUS] bundle:[chromeRole="group"]
diff --git a/content/test/data/accessibility/aria/aria-label-with-visual-content-expected-android-external.txt b/content/test/data/accessibility/aria/aria-label-with-visual-content-expected-android-external.txt index d65df5d..10128a5c 100644 --- a/content/test/data/accessibility/aria/aria-label-with-visual-content-expected-android-external.txt +++ b/content/test/data/accessibility/aria/aria-label-with-visual-content-expected-android-external.txt
@@ -2,7 +2,7 @@ ++Button contentDescription:"button supports naming with child content" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="button", clickableScore="300"] ++View contentDescription:"link supports naming with child content" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="link", clickableScore="300", roleDescription="link", targetUrl="file:///storage/emulated/0/chromium_tests_root/content/test/data/accessibility/aria/aria-label-with-visual-content.html#"] ++++TextView text:"This is a link" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText", clickableScore="100"] -++TextView text:"div does not support naming with child content" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="genericContainer"] -++TextView text:"span does not support naming with child content" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="genericContainer"] +++TextView text:"This is a div" supplementalDescription:"div does not support naming with child content" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="genericContainer"] +++TextView text:"This is a span" supplementalDescription:"span does not support naming with child content" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="genericContainer"] ++TextView text:" " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] -++TextView text:"region does not support naming with child content" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="genericContainer"] +++TextView text:"This is a region" supplementalDescription:"region does not support naming with child content" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="genericContainer"]
diff --git a/content/test/data/accessibility/aria/aria-list-expected-android-external.txt b/content/test/data/accessibility/aria/aria-list-expected-android-external.txt index f4d5136..66d37d7 100644 --- a/content/test/data/accessibility/aria/aria-list-expected-android-external.txt +++ b/content/test/data/accessibility/aria/aria-list-expected-android-external.txt
@@ -1,5 +1,5 @@ WebView focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] ++ListView CollectionInfo:[rows=3, cols=1] actions:[AX_FOCUS] bundle:[chromeRole="list"] -++++View text:"1" CollectionItemInfo:[rowIndex=0, colIndex=0] actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="listItem"] -++++View text:"2" CollectionItemInfo:[rowIndex=1, colIndex=0] actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="listItem"] -++++View text:"3" CollectionItemInfo:[rowIndex=2, colIndex=0] actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="listItem"] +++++View text:"Item 1" supplementalDescription:"1" CollectionItemInfo:[rowIndex=0, colIndex=0] actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="listItem"] +++++View text:"Item 2" supplementalDescription:"2" CollectionItemInfo:[rowIndex=1, colIndex=0] actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="listItem"] +++++View text:"Item 3" supplementalDescription:"3" CollectionItemInfo:[rowIndex=2, colIndex=0] actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="listItem"]
diff --git a/content/test/data/accessibility/aria/aria-listitem-expected-android-external.txt b/content/test/data/accessibility/aria/aria-listitem-expected-android-external.txt index 82b6836..ca63719 100644 --- a/content/test/data/accessibility/aria/aria-listitem-expected-android-external.txt +++ b/content/test/data/accessibility/aria/aria-listitem-expected-android-external.txt
@@ -1,4 +1,4 @@ WebView focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] ++ListView CollectionInfo:[rows=2, cols=1] actions:[AX_FOCUS] bundle:[chromeRole="list"] -++++View text:"1" CollectionItemInfo:[rowIndex=0, colIndex=0] actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="listItem"] -++++View text:"2" CollectionItemInfo:[rowIndex=1, colIndex=0] actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="listItem"] +++++View text:"Item 1" supplementalDescription:"1" CollectionItemInfo:[rowIndex=0, colIndex=0] actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="listItem"] +++++View text:"Item 2" supplementalDescription:"2" CollectionItemInfo:[rowIndex=1, colIndex=0] actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="listItem"]
diff --git a/content/test/data/accessibility/aria/aria-owns-ignored-expected-android-external.txt b/content/test/data/accessibility/aria/aria-owns-ignored-expected-android-external.txt index ace333f..e9d6afe 100644 --- a/content/test/data/accessibility/aria/aria-owns-ignored-expected-android-external.txt +++ b/content/test/data/accessibility/aria/aria-owns-ignored-expected-android-external.txt
@@ -1,14 +1,14 @@ WebView focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] -++View text:"Ordinary presentation element with id" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="splitter", roleDescription="splitter"] -++View text:"An aria-owned element is never ignored" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="splitter", roleDescription="splitter"] +++View supplementalDescription:"Ordinary presentation element with id" actions:[AX_FOCUS] bundle:[chromeRole="splitter", roleDescription="splitter"] +++View supplementalDescription:"An aria-owned element is never ignored" actions:[AX_FOCUS] bundle:[chromeRole="splitter", roleDescription="splitter"] ++View actions:[AX_FOCUS] bundle:[chromeRole="group"] ++++Button text:"button-in-owned-tree" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="button", clickableScore="300"] -++View text:"Element with aria-owns is never ignored" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="splitter", roleDescription="splitter"] +++View supplementalDescription:"Element with aria-owns is never ignored" actions:[AX_FOCUS] bundle:[chromeRole="splitter", roleDescription="splitter"] ++View actions:[AX_FOCUS] bundle:[chromeRole="genericContainer"] ++++EditText viewIdResName:"textbox" clickable editable focusable inputType:1 textSelectionStart:0 textSelectionEnd:0 actions:[FOCUS, CLICK, AX_FOCUS, PASTE, SET_TEXT, IME_ENTER] bundle:[chromeRole="textField", clickableScore="300"] -++View text:"Owning an element with an ignored parent serializes cleanly" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="splitter", roleDescription="splitter"] +++View supplementalDescription:"Owning an element with an ignored parent serializes cleanly" actions:[AX_FOCUS] bundle:[chromeRole="splitter", roleDescription="splitter"] ++View actions:[AX_FOCUS] bundle:[chromeRole="group"] ++++CheckBox viewIdResName:"checkbox" checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="checkBox", clickableScore="300"] -++View text:"All the above in one" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="splitter", roleDescription="splitter"] +++View supplementalDescription:"All the above in one" actions:[AX_FOCUS] bundle:[chromeRole="splitter", roleDescription="splitter"] ++View actions:[AX_FOCUS] bundle:[chromeRole="genericContainer"] ++++SeekBar viewIdResName:"range" clickable focusable RangeInfo:[current=50.0, min=0.0, max=100.0] actions:[FOCUS, CLICK, AX_FOCUS, SET_PROGRESS] bundle:[chromeRole="slider"]
diff --git a/content/test/data/accessibility/aria/aria-posinset-expected-android-external.txt b/content/test/data/accessibility/aria/aria-posinset-expected-android-external.txt index 31ce435..f7f27069 100644 --- a/content/test/data/accessibility/aria/aria-posinset-expected-android-external.txt +++ b/content/test/data/accessibility/aria/aria-posinset-expected-android-external.txt
@@ -20,15 +20,15 @@ ++TextView text:"Banana" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] ++View containerTitle:"Cake" actions:[AX_FOCUS] bundle:[chromeRole="group"] ++++View text:"Cake" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="legend"] -++++RadioButton text:"Chiffon cakes" stateDescription:"Checked. In group, option 1 of 2" checkable clickable focusable checked actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="radioButton", clickableScore="300"] +++++RadioButton stateDescription:"Checked. In group, option 1 of 2" supplementalDescription:"Chiffon cakes" checkable clickable focusable checked actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="radioButton", clickableScore="300"] ++++View text:"\n" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="lineBreak"] -++++RadioButton text:"Chocolate cakes" stateDescription:"Not checked. In group, option 2 of 2" checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="radioButton", clickableScore="300"] +++++RadioButton stateDescription:"Not checked. In group, option 2 of 2" supplementalDescription:"Chocolate cakes" checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="radioButton", clickableScore="300"] ++View actions:[AX_FOCUS] bundle:[chromeRole="form"] ++++View viewIdResName:"pTag" actions:[AX_FOCUS] bundle:[chromeRole="paragraph"] ++++++Button text:"changedFromRadio" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="button", clickableScore="300"] ++++++View text:"red" viewIdResName:"parent" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="labelText"] ++++++View text:"\n" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="lineBreak"] -++++++RadioButton text:"blue" checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="radioButton", clickableScore="300"] +++++++RadioButton supplementalDescription:"blue" checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="radioButton", clickableScore="300"] ++GridView clickable CollectionInfo:[rows=100, cols=1] actions:[CLICK, AX_FOCUS] bundle:[chromeRole="treeGrid"] ++++View text:"content" focusable actions:[FOCUS, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="row"] ++++++View text:"content" CollectionItemInfo:[rowIndex=0, colIndex=0] actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="gridCell"]
diff --git a/content/test/data/accessibility/aria/aria-strong-expected-android-external.txt b/content/test/data/accessibility/aria/aria-strong-expected-android-external.txt index 755b3edb..10401e73 100644 --- a/content/test/data/accessibility/aria/aria-strong-expected-android-external.txt +++ b/content/test/data/accessibility/aria/aria-strong-expected-android-external.txt
@@ -2,4 +2,4 @@ ++View text:"role" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="strong"] ++View text:"element (no name)" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="strong"] ++TextView text:" " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] -++View text:"include me" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="strong"] +++View text:"element (with name)" supplementalDescription:"include me" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="strong"]
diff --git a/content/test/data/accessibility/aria/aria-time-expected-android-external.txt b/content/test/data/accessibility/aria/aria-time-expected-android-external.txt index f450961..b8a511df 100644 --- a/content/test/data/accessibility/aria/aria-time-expected-android-external.txt +++ b/content/test/data/accessibility/aria/aria-time-expected-android-external.txt
@@ -2,4 +2,4 @@ ++View text:"role" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="time"] ++View text:"element (no name)" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="time"] ++TextView text:" " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] -++View text:"include me" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="time"] +++View text:"element (with name)" supplementalDescription:"include me" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="time"]
diff --git a/content/test/data/accessibility/aria/dpub-roles-expected-android-external.txt b/content/test/data/accessibility/aria/dpub-roles-expected-android-external.txt index 050d948..9f80879 100644 --- a/content/test/data/accessibility/aria/dpub-roles-expected-android-external.txt +++ b/content/test/data/accessibility/aria/dpub-roles-expected-android-external.txt
@@ -1,42 +1,42 @@ WebView focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea", hasImage="true"] -++View text:"doc-abstract" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="docAbstract", roleDescription="abstract"] -++View text:"doc-acknowledgments" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="docAcknowledgments", roleDescription="acknowledgments"] -++View text:"doc-afterword" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="docAfterword", roleDescription="afterword"] -++View text:"doc-appendix" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="docAppendix", roleDescription="appendix"] -++View text:"null" contentDescription:"doc-backlink" clickable actions:[CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="docBackLink", roleDescription="back link"] -++View text:"doc-biblioentry" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="docBiblioEntry", roleDescription="bibliography entry"] -++View text:"doc-bibliography" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="docBibliography", roleDescription="bibliography"] -++View text:"null" contentDescription:"doc-biblioref" clickable actions:[CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="docBiblioRef", roleDescription="bibliography reference"] -++View text:"doc-chapter" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="docChapter", roleDescription="chapter"] -++View text:"doc-colophon" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="docColophon", roleDescription="colophon"] -++View text:"doc-conclusion" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="docConclusion", roleDescription="conclusion"] +++View supplementalDescription:"doc-abstract" actions:[AX_FOCUS] bundle:[chromeRole="docAbstract", roleDescription="abstract"] +++View supplementalDescription:"doc-acknowledgments" actions:[AX_FOCUS] bundle:[chromeRole="docAcknowledgments", roleDescription="acknowledgments"] +++View supplementalDescription:"doc-afterword" actions:[AX_FOCUS] bundle:[chromeRole="docAfterword", roleDescription="afterword"] +++View supplementalDescription:"doc-appendix" actions:[AX_FOCUS] bundle:[chromeRole="docAppendix", roleDescription="appendix"] +++View text:"null" contentDescription:"" supplementalDescription:"doc-backlink" clickable actions:[CLICK, AX_FOCUS] bundle:[chromeRole="docBackLink", roleDescription="back link"] +++View supplementalDescription:"doc-biblioentry" actions:[AX_FOCUS] bundle:[chromeRole="docBiblioEntry", roleDescription="bibliography entry"] +++View supplementalDescription:"doc-bibliography" actions:[AX_FOCUS] bundle:[chromeRole="docBibliography", roleDescription="bibliography"] +++View text:"null" contentDescription:"" supplementalDescription:"doc-biblioref" clickable actions:[CLICK, AX_FOCUS] bundle:[chromeRole="docBiblioRef", roleDescription="bibliography reference"] +++View supplementalDescription:"doc-chapter" actions:[AX_FOCUS] bundle:[chromeRole="docChapter", roleDescription="chapter"] +++View supplementalDescription:"doc-colophon" actions:[AX_FOCUS] bundle:[chromeRole="docColophon", roleDescription="colophon"] +++View supplementalDescription:"doc-conclusion" actions:[AX_FOCUS] bundle:[chromeRole="docConclusion", roleDescription="conclusion"] ++View contentDescription:"doc-cover" actions:[AX_FOCUS] bundle:[chromeRole="docCover", hasImage="true", roleDescription="cover"] -++View text:"doc-credit" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="docCredit", roleDescription="credit"] -++View text:"doc-credits" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="docCredits", roleDescription="credits"] -++View text:"doc-dedication" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="docDedication", roleDescription="dedication"] -++View text:"doc-endnote" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="docEndnote", roleDescription="endnote"] -++View text:"doc-endnotes" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="docEndnotes", roleDescription="endnotes"] -++View text:"doc-epigraph" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="docEpigraph", roleDescription="epigraph"] -++View text:"doc-epilogue" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="docEpilogue", roleDescription="epilogue"] -++View text:"doc-errata" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="docErrata", roleDescription="errata"] -++View text:"doc-example" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="docExample", roleDescription="example"] -++View text:"doc-footnote" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="docFootnote", roleDescription="footnote"] -++View text:"doc-foreword" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="docForeword", roleDescription="foreword"] -++View text:"doc-glossary" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="docGlossary", roleDescription="glossary"] -++View text:"null" contentDescription:"doc-glossref" clickable actions:[CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="docGlossref", roleDescription="glossary reference"] -++View text:"doc-index" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="docIndex", roleDescription="index"] -++View text:"doc-introduction" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="docIntroduction", roleDescription="introduction"] -++View text:"null" contentDescription:"doc-noteref" clickable actions:[CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="docNoteRef", roleDescription="note reference"] -++View text:"doc-notice" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="docNotice", roleDescription="notice"] -++View text:"doc-pagebreak" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="docPageBreak", roleDescription="page break"] -++View text:"doc-pagefooter" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="docPageFooter", roleDescription="page footer"] -++View text:"doc-pageheader" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="docPageHeader", roleDescription="page header"] -++View text:"doc-pagelist" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="docPageList", roleDescription="page list"] -++View text:"doc-part" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="docPart", roleDescription="part"] -++View text:"doc-preface" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="docPreface", roleDescription="preface"] -++View text:"doc-prologue" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="docPrologue", roleDescription="prologue"] -++View text:"doc-pullquote" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="docPullquote", roleDescription="pullquote"] -++View text:"doc-qna" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="docQna", roleDescription="Q&A"] -++View text:"doc-subtitle" heading actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="docSubtitle", roleDescription="subtitle"] -++View text:"doc-tip" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="docTip", roleDescription="tip"] -++View text:"doc-toc" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="docToc", roleDescription="table of contents"] +++View supplementalDescription:"doc-credit" actions:[AX_FOCUS] bundle:[chromeRole="docCredit", roleDescription="credit"] +++View supplementalDescription:"doc-credits" actions:[AX_FOCUS] bundle:[chromeRole="docCredits", roleDescription="credits"] +++View supplementalDescription:"doc-dedication" actions:[AX_FOCUS] bundle:[chromeRole="docDedication", roleDescription="dedication"] +++View supplementalDescription:"doc-endnote" actions:[AX_FOCUS] bundle:[chromeRole="docEndnote", roleDescription="endnote"] +++View supplementalDescription:"doc-endnotes" actions:[AX_FOCUS] bundle:[chromeRole="docEndnotes", roleDescription="endnotes"] +++View supplementalDescription:"doc-epigraph" actions:[AX_FOCUS] bundle:[chromeRole="docEpigraph", roleDescription="epigraph"] +++View supplementalDescription:"doc-epilogue" actions:[AX_FOCUS] bundle:[chromeRole="docEpilogue", roleDescription="epilogue"] +++View supplementalDescription:"doc-errata" actions:[AX_FOCUS] bundle:[chromeRole="docErrata", roleDescription="errata"] +++View supplementalDescription:"doc-example" actions:[AX_FOCUS] bundle:[chromeRole="docExample", roleDescription="example"] +++View supplementalDescription:"doc-footnote" actions:[AX_FOCUS] bundle:[chromeRole="docFootnote", roleDescription="footnote"] +++View supplementalDescription:"doc-foreword" actions:[AX_FOCUS] bundle:[chromeRole="docForeword", roleDescription="foreword"] +++View supplementalDescription:"doc-glossary" actions:[AX_FOCUS] bundle:[chromeRole="docGlossary", roleDescription="glossary"] +++View text:"null" contentDescription:"" supplementalDescription:"doc-glossref" clickable actions:[CLICK, AX_FOCUS] bundle:[chromeRole="docGlossref", roleDescription="glossary reference"] +++View supplementalDescription:"doc-index" actions:[AX_FOCUS] bundle:[chromeRole="docIndex", roleDescription="index"] +++View supplementalDescription:"doc-introduction" actions:[AX_FOCUS] bundle:[chromeRole="docIntroduction", roleDescription="introduction"] +++View text:"null" contentDescription:"" supplementalDescription:"doc-noteref" clickable actions:[CLICK, AX_FOCUS] bundle:[chromeRole="docNoteRef", roleDescription="note reference"] +++View supplementalDescription:"doc-notice" actions:[AX_FOCUS] bundle:[chromeRole="docNotice", roleDescription="notice"] +++View supplementalDescription:"doc-pagebreak" actions:[AX_FOCUS] bundle:[chromeRole="docPageBreak", roleDescription="page break"] +++View supplementalDescription:"doc-pagefooter" actions:[AX_FOCUS] bundle:[chromeRole="docPageFooter", roleDescription="page footer"] +++View supplementalDescription:"doc-pageheader" actions:[AX_FOCUS] bundle:[chromeRole="docPageHeader", roleDescription="page header"] +++View supplementalDescription:"doc-pagelist" actions:[AX_FOCUS] bundle:[chromeRole="docPageList", roleDescription="page list"] +++View supplementalDescription:"doc-part" actions:[AX_FOCUS] bundle:[chromeRole="docPart", roleDescription="part"] +++View supplementalDescription:"doc-preface" actions:[AX_FOCUS] bundle:[chromeRole="docPreface", roleDescription="preface"] +++View supplementalDescription:"doc-prologue" actions:[AX_FOCUS] bundle:[chromeRole="docPrologue", roleDescription="prologue"] +++View supplementalDescription:"doc-pullquote" actions:[AX_FOCUS] bundle:[chromeRole="docPullquote", roleDescription="pullquote"] +++View supplementalDescription:"doc-qna" actions:[AX_FOCUS] bundle:[chromeRole="docQna", roleDescription="Q&A"] +++View supplementalDescription:"doc-subtitle" heading actions:[AX_FOCUS] bundle:[chromeRole="docSubtitle", roleDescription="subtitle"] +++View supplementalDescription:"doc-tip" actions:[AX_FOCUS] bundle:[chromeRole="docTip", roleDescription="tip"] +++View supplementalDescription:"doc-toc" actions:[AX_FOCUS] bundle:[chromeRole="docToc", roleDescription="table of contents"]
diff --git a/content/test/data/accessibility/aria/graphics-roles-expected-android-external.txt b/content/test/data/accessibility/aria/graphics-roles-expected-android-external.txt index 6e6b071e..b1df049 100644 --- a/content/test/data/accessibility/aria/graphics-roles-expected-android-external.txt +++ b/content/test/data/accessibility/aria/graphics-roles-expected-android-external.txt
@@ -1,4 +1,4 @@ WebView focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea", hasImage="true"] -++View text:"graphics-document" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="graphicsDocument", roleDescription="graphics document"] -++View text:"graphics-object" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="graphicsObject", roleDescription="graphics object"] +++View supplementalDescription:"graphics-document" actions:[AX_FOCUS] bundle:[chromeRole="graphicsDocument", roleDescription="graphics document"] +++View supplementalDescription:"graphics-object" actions:[AX_FOCUS] bundle:[chromeRole="graphicsObject", roleDescription="graphics object"] ++View contentDescription:"graphics-symbol" actions:[AX_FOCUS] bundle:[chromeRole="graphicsSymbol", hasImage="true", roleDescription="graphics symbol"]
diff --git a/content/test/data/accessibility/aria/hidden-described-by-expected-android-external.txt b/content/test/data/accessibility/aria/hidden-described-by-expected-android-external.txt index 6cc28028..091bb03 100644 --- a/content/test/data/accessibility/aria/hidden-described-by-expected-android-external.txt +++ b/content/test/data/accessibility/aria/hidden-described-by-expected-android-external.txt
@@ -1,5 +1,5 @@ WebView focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] ++View actions:[AX_FOCUS] bundle:[chromeRole="genericContainer"] -++++TextView text:"span-A3" hint:"span-A4" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="genericContainer", hint="span-A4"] -++++TextView text:"span-B" hint:"span-A2" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="genericContainer", hint="span-A2"] -++++TextView text:"span-C" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="genericContainer"] +++++TextView hint:"span-A4" supplementalDescription:"span-A3" actions:[AX_FOCUS] bundle:[chromeRole="genericContainer", hint="span-A4"] +++++TextView hint:"span-A2" supplementalDescription:"span-B" actions:[AX_FOCUS] bundle:[chromeRole="genericContainer", hint="span-A2"] +++++TextView supplementalDescription:"span-C" actions:[AX_FOCUS] bundle:[chromeRole="genericContainer"]
diff --git a/content/test/data/accessibility/aria/hidden-labelled-by-expected-android-external.txt b/content/test/data/accessibility/aria/hidden-labelled-by-expected-android-external.txt index 7fe9c956..57f6ad68 100644 --- a/content/test/data/accessibility/aria/hidden-labelled-by-expected-android-external.txt +++ b/content/test/data/accessibility/aria/hidden-labelled-by-expected-android-external.txt
@@ -2,4 +2,4 @@ ++View actions:[AX_FOCUS] bundle:[chromeRole="genericContainer"] ++++View containerTitle:"span-A4" actions:[AX_FOCUS] bundle:[chromeRole="group"] ++++View containerTitle:"span-A2" actions:[AX_FOCUS] bundle:[chromeRole="group"] -++++TextView text:"span-C" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="genericContainer"] +++++TextView supplementalDescription:"span-C" actions:[AX_FOCUS] bundle:[chromeRole="genericContainer"]
diff --git a/content/test/data/accessibility/html/a-name-calc-expected-android-external.txt b/content/test/data/accessibility/html/a-name-calc-expected-android-external.txt index ab331200..7c7dd9d 100644 --- a/content/test/data/accessibility/html/a-name-calc-expected-android-external.txt +++ b/content/test/data/accessibility/html/a-name-calc-expected-android-external.txt
@@ -8,11 +8,11 @@ ++View contentDescription:"Title2" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="link", clickableScore="300", roleDescription="link", targetUrl="file:///storage/emulated/0/chromium_tests_root/content/test/data/accessibility/html/a-name-calc.html#"] ++++TextView text:"InnerText2" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText", clickableScore="100"] ++TextView text:" " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] -++View text:"null" contentDescription:"LabelledBy3" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="link", clickableScore="300", roleDescription="link", targetUrl="file:///storage/emulated/0/chromium_tests_root/content/test/data/accessibility/html/a-name-calc.html#"] +++View text:"null" contentDescription:"InnerText3" supplementalDescription:"LabelledBy3" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="link", clickableScore="300", roleDescription="link", targetUrl="file:///storage/emulated/0/chromium_tests_root/content/test/data/accessibility/html/a-name-calc.html#"] ++++TextView text:"InnerText3" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText", clickableScore="100"] ++View text:"null" contentDescription:"Title4" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="link", clickableScore="300", roleDescription="link", targetUrl="file:///storage/emulated/0/chromium_tests_root/content/test/data/accessibility/html/a-name-calc.html#"] ++View contentDescription:"Label5" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="link", clickableScore="300", roleDescription="link", targetUrl="file:///storage/emulated/0/chromium_tests_root/content/test/data/accessibility/html/a-name-calc.html#"] -++View text:"null" contentDescription:"LabelledBy6" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="link", clickableScore="300", roleDescription="link", targetUrl="file:///storage/emulated/0/chromium_tests_root/content/test/data/accessibility/html/a-name-calc.html#"] +++View text:"null" contentDescription:"" supplementalDescription:"LabelledBy6" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="link", clickableScore="300", roleDescription="link", targetUrl="file:///storage/emulated/0/chromium_tests_root/content/test/data/accessibility/html/a-name-calc.html#"] ++View actions:[AX_FOCUS] bundle:[chromeRole="paragraph"] ++++TextView text:"LabelledBy3" viewIdResName:"label3" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="genericContainer"] ++++TextView text:" " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"]
diff --git a/content/test/data/accessibility/html/action-verbs-expected-android-external.txt b/content/test/data/accessibility/html/action-verbs-expected-android-external.txt index 941e4c3..38df6cae 100644 --- a/content/test/data/accessibility/html/action-verbs-expected-android-external.txt +++ b/content/test/data/accessibility/html/action-verbs-expected-android-external.txt
@@ -1,4 +1,4 @@ -WebView text:"Action verbs" focusable focused actions:[CLEAR_FOCUS, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="rootWebArea"] +WebView supplementalDescription:"Action verbs" focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] ++TextView text:"Generic div" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="genericContainer"] ++TextView text:"Heading" heading actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="heading", roleDescription="heading 1"] ++Button text:"Button" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="button", clickableScore="300"]
diff --git a/content/test/data/accessibility/html/button-name-calc-expected-android-external.txt b/content/test/data/accessibility/html/button-name-calc-expected-android-external.txt index 559dce0..fdc25ac 100644 --- a/content/test/data/accessibility/html/button-name-calc-expected-android-external.txt +++ b/content/test/data/accessibility/html/button-name-calc-expected-android-external.txt
@@ -2,8 +2,8 @@ ++Button text:"InnerText0" viewIdResName:"c0" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="button", clickableScore="300"] ++Button text:"InnerText1" tooltipText:"Title1" viewIdResName:"c1" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="button", clickableScore="300"] ++Button tooltipText:"Title2" contentDescription:"AriaLabel2" viewIdResName:"c2" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="button", clickableScore="300"] -++Button text:"LabelledBy3" tooltipText:"Title3" viewIdResName:"c3" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="button", clickableScore="300"] -++Button text:"LabelledBy4" hint:"DescribedBy4" tooltipText:"Title4" viewIdResName:"c4" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="button", clickableScore="300", hint="DescribedBy4"] +++Button text:"InnerText3" tooltipText:"Title3" viewIdResName:"c3" supplementalDescription:"LabelledBy3" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="button", clickableScore="300"] +++Button text:"InnerText4" hint:"DescribedBy4" tooltipText:"Title4" viewIdResName:"c4" supplementalDescription:"LabelledBy4" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="button", clickableScore="300", hint="DescribedBy4"] ++Button text:"InnerText5" hint:"DescribedBy5" viewIdResName:"c5" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="button", clickableScore="300", hint="DescribedBy5"] ++Button text:"Outer inner" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="button", clickableScore="300"] ++Button text:"Outer inner1" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="button", clickableScore="300"]
diff --git a/content/test/data/accessibility/html/button-with-listbox-popup-expected-android-external.txt b/content/test/data/accessibility/html/button-with-listbox-popup-expected-android-external.txt index 919ede4..1c1cfd2c 100644 --- a/content/test/data/accessibility/html/button-with-listbox-popup-expected-android-external.txt +++ b/content/test/data/accessibility/html/button-with-listbox-popup-expected-android-external.txt
@@ -1,7 +1,7 @@ WebView focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] ++View viewIdResName:"test1" actions:[AX_FOCUS] bundle:[chromeRole="genericContainer"] ++++TextView text:"Choose one:" viewIdResName:"span" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="genericContainer"] -++++Button text:"Choose one: Foo" viewIdResName:"test" canOpenPopUp clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="popUpButton", clickableScore="300", roleDescription="pop up button"] +++++Button text:"Foo" viewIdResName:"test" supplementalDescription:"Choose one: Foo" canOpenPopUp clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="popUpButton", clickableScore="300", roleDescription="pop up button"] ++++ListView viewIdResName:"options" containerTitle:"Choose one:" clickable focusable CollectionInfo:[selection_mode_single, rows=3, cols=1] actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="listBox", clickableScore="300"] ++++++View text:"Baz" viewIdResName:"option1" clickable CollectionItemInfo:[rowIndex=0, colIndex=0] actions:[CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="listBoxOption", clickableScore="200"] ++++++View text:"Bar" viewIdResName:"option2" clickable CollectionItemInfo:[rowIndex=1, colIndex=0] actions:[CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="listBoxOption", clickableScore="200"]
diff --git a/content/test/data/accessibility/html/caption-expected-android-external.txt b/content/test/data/accessibility/html/caption-expected-android-external.txt index 0e19a8e..995757e 100644 --- a/content/test/data/accessibility/html/caption-expected-android-external.txt +++ b/content/test/data/accessibility/html/caption-expected-android-external.txt
@@ -1,5 +1,5 @@ WebView focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] -++GridView text:"Browser and Engine" CollectionInfo:[rows=3, cols=2] actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="table"] +++GridView supplementalDescription:"Browser and Engine" CollectionInfo:[rows=3, cols=2] actions:[AX_FOCUS] bundle:[chromeRole="table"] ++++View text:"Browser and Engine" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="caption", roleDescription="caption"] ++++View actions:[AX_FOCUS] bundle:[chromeRole="row"] ++++++View text:"Browser" heading CollectionItemInfo:[tableHeader, rowIndex=0, colIndex=0] actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="columnHeader"] @@ -10,7 +10,7 @@ ++++View actions:[AX_FOCUS] bundle:[chromeRole="row"] ++++++View text:"Safari" CollectionItemInfo:[rowIndex=2, colIndex=0] actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="cell"] ++++++View text:"WebKit" CollectionItemInfo:[rowIndex=2, colIndex=1] actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="cell"] -++GridView text:"Name" hint:"Description" CollectionInfo:[rows=1, cols=2] actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="table", hint="Description"] +++GridView hint:"Description" supplementalDescription:"Name" CollectionInfo:[rows=1, cols=2] actions:[AX_FOCUS] bundle:[chromeRole="table", hint="Description"] ++++View text:"Description" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="caption", roleDescription="caption"] ++++View actions:[AX_FOCUS] bundle:[chromeRole="row"] ++++++View text:"A" CollectionItemInfo:[rowIndex=0, colIndex=0] actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="cell"]
diff --git a/content/test/data/accessibility/html/character-locations-expected-android-external.txt b/content/test/data/accessibility/html/character-locations-expected-android-external.txt index a44d4bf..c84bdaa5 100644 --- a/content/test/data/accessibility/html/character-locations-expected-android-external.txt +++ b/content/test/data/accessibility/html/character-locations-expected-android-external.txt
@@ -1,4 +1,4 @@ -WebView text:"Character Locations" focusable focused actions:[CLEAR_FOCUS, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="rootWebArea", hasImage="true"] +WebView supplementalDescription:"Character Locations" focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea", hasImage="true"] ++TextView text:"Heading" heading actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="heading", roleDescription="heading 1"] ++TextView text:"Paragraph" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="paragraph"] ++Button text:"Button" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="button", clickableScore="300"]
diff --git a/content/test/data/accessibility/html/checkbox-name-calc-expected-android-external.txt b/content/test/data/accessibility/html/checkbox-name-calc-expected-android-external.txt index 975651b2..1f9b413 100644 --- a/content/test/data/accessibility/html/checkbox-name-calc-expected-android-external.txt +++ b/content/test/data/accessibility/html/checkbox-name-calc-expected-android-external.txt
@@ -1,9 +1,9 @@ WebView focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] ++CheckBox text:"Title0" viewIdResName:"c0" checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="checkBox", clickableScore="300"] -++CheckBox text:"Label1" tooltipText:"Title1" viewIdResName:"c1" checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="checkBox", clickableScore="300"] +++CheckBox tooltipText:"Title1" viewIdResName:"c1" supplementalDescription:"Label1" checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="checkBox", clickableScore="300"] ++CheckBox tooltipText:"Title2" contentDescription:"AriaLabel2" viewIdResName:"c2" checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="checkBox", clickableScore="300"] -++CheckBox text:"LabelledBy3" tooltipText:"Title3" viewIdResName:"c3" checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="checkBox", clickableScore="300"] -++CheckBox text:"LabelledBy4" hint:"DescribedBy4" tooltipText:"Title4" viewIdResName:"c4" checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="checkBox", clickableScore="300", hint="DescribedBy4"] +++CheckBox tooltipText:"Title3" viewIdResName:"c3" supplementalDescription:"LabelledBy3" checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="checkBox", clickableScore="300"] +++CheckBox hint:"DescribedBy4" tooltipText:"Title4" viewIdResName:"c4" supplementalDescription:"LabelledBy4" checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="checkBox", clickableScore="300", hint="DescribedBy4"] ++CheckBox hint:"DescribedBy5" viewIdResName:"c5" checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="checkBox", clickableScore="300", hint="DescribedBy5"] ++View actions:[AX_FOCUS] bundle:[chromeRole="paragraph"] ++++TextView text:" " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"]
diff --git a/content/test/data/accessibility/html/clickable-ancestor-expected-android-external.txt b/content/test/data/accessibility/html/clickable-ancestor-expected-android-external.txt index 15e91ac..1231ef4 100644 --- a/content/test/data/accessibility/html/clickable-ancestor-expected-android-external.txt +++ b/content/test/data/accessibility/html/clickable-ancestor-expected-android-external.txt
@@ -1,4 +1,4 @@ -WebView text:"Checking nodes marked as clickable" focusable focused actions:[CLEAR_FOCUS, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="rootWebArea"] +WebView supplementalDescription:"Checking nodes marked as clickable" focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] ++TextView text:"Generic div" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="genericContainer"] ++TextView text:"Heading" heading actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="heading", roleDescription="heading 1"] ++Button text:"Button" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="button", clickableScore="300"]
diff --git a/content/test/data/accessibility/html/hr-expected-android-external.txt b/content/test/data/accessibility/html/hr-expected-android-external.txt index e3b9bac..4f4bad2e21 100644 --- a/content/test/data/accessibility/html/hr-expected-android-external.txt +++ b/content/test/data/accessibility/html/hr-expected-android-external.txt
@@ -1,6 +1,6 @@ WebView focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] ++TextView text:"Before." actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="paragraph"] -++View text:"Dividing line" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="splitter", roleDescription="splitter"] +++View supplementalDescription:"Dividing line" actions:[AX_FOCUS] bundle:[chromeRole="splitter", roleDescription="splitter"] ++TextView text:"Middle." actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="paragraph"] ++View actions:[AX_FOCUS] bundle:[chromeRole="splitter", roleDescription="splitter"] ++TextView text:"After." actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="paragraph"]
diff --git a/content/test/data/accessibility/html/html-attributes-and-tag-names-expected-android-external.txt b/content/test/data/accessibility/html/html-attributes-and-tag-names-expected-android-external.txt index c9cc6eb4..d72e6723 100644 --- a/content/test/data/accessibility/html/html-attributes-and-tag-names-expected-android-external.txt +++ b/content/test/data/accessibility/html/html-attributes-and-tag-names-expected-android-external.txt
@@ -1,4 +1,4 @@ -WebView text:"Hello World" focusable focused actions:[CLEAR_FOCUS, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="rootWebArea"] +WebView supplementalDescription:"Hello World" focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] ++TextView text:"Heading" heading actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="heading", roleDescription="heading 1"] ++TextView text:"Paragraph" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="paragraph"] ++View actions:[AX_FOCUS] bundle:[chromeRole="genericContainer"]
diff --git a/content/test/data/accessibility/html/html-expected-android-external.txt b/content/test/data/accessibility/html/html-expected-android-external.txt index fd2ac5a0..3a59596 100644 --- a/content/test/data/accessibility/html/html-expected-android-external.txt +++ b/content/test/data/accessibility/html/html-expected-android-external.txt
@@ -1,3 +1,3 @@ -WebView text:"HTML element" focusable focused actions:[CLEAR_FOCUS, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="rootWebArea"] -++View text:"BODY element" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="genericContainer"] +WebView supplementalDescription:"HTML element" focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] +++View supplementalDescription:"BODY element" actions:[AX_FOCUS] bundle:[chromeRole="genericContainer"] ++++Button contentDescription:"Button element" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="button", clickableScore="300"]
diff --git a/content/test/data/accessibility/html/iframe-cross-process-expected-android-external.txt b/content/test/data/accessibility/html/iframe-cross-process-expected-android-external.txt index b5a4f74..e6863334 100644 --- a/content/test/data/accessibility/html/iframe-cross-process-expected-android-external.txt +++ b/content/test/data/accessibility/html/iframe-cross-process-expected-android-external.txt
@@ -2,6 +2,6 @@ ++TextView text:"Before frame" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="paragraph"] ++View actions:[AX_FOCUS] bundle:[chromeRole="genericContainer"] ++++View containerTitle:"Cross-process iframe" focusable actions:[FOCUS, AX_FOCUS] bundle:[chromeRole="iframe"] -++++++View text:"Error" focusable actions:[FOCUS, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="rootWebArea"] +++++++View supplementalDescription:"Error" focusable actions:[FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] ++++++++TextView text:"Could not load the requested resource.\nError code: -6 (net::ERR_FILE_NOT_FOUND)" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="genericContainer"] ++TextView text:"After frame" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="paragraph"]
diff --git a/content/test/data/accessibility/html/iframe-traversal-expected-android-external.txt b/content/test/data/accessibility/html/iframe-traversal-expected-android-external.txt index 4328ca4..cadac58d 100644 --- a/content/test/data/accessibility/html/iframe-traversal-expected-android-external.txt +++ b/content/test/data/accessibility/html/iframe-traversal-expected-android-external.txt
@@ -2,6 +2,6 @@ ++TextView text:"Before iframe" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="paragraph"] ++View actions:[AX_FOCUS] bundle:[chromeRole="genericContainer"] ++++View actions:[AX_FOCUS] bundle:[chromeRole="iframe"] -++++++View text:"Error" focusable actions:[FOCUS, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="rootWebArea"] +++++++View supplementalDescription:"Error" focusable actions:[FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] ++++++++TextView text:"Could not load the requested resource.\nError code: -6 (net::ERR_FILE_NOT_FOUND)" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="genericContainer"] ++TextView text:"After iframe" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="paragraph"]
diff --git a/content/test/data/accessibility/html/input-checkbox-label-expected-android-external.txt b/content/test/data/accessibility/html/input-checkbox-label-expected-android-external.txt index 565ad8a..bada8a2f 100644 --- a/content/test/data/accessibility/html/input-checkbox-label-expected-android-external.txt +++ b/content/test/data/accessibility/html/input-checkbox-label-expected-android-external.txt
@@ -1,3 +1,3 @@ WebView focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] ++View actions:[AX_FOCUS] bundle:[chromeRole="genericContainer"] -++++CheckBox text:"Checkbox Title" checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="checkBox", clickableScore="300"] +++++CheckBox supplementalDescription:"Checkbox Title" checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="checkBox", clickableScore="300"]
diff --git a/content/test/data/accessibility/html/input-color-with-popup-open-expected-android-external.txt b/content/test/data/accessibility/html/input-color-with-popup-open-expected-android-external.txt index ea581912..29b0921 100644 --- a/content/test/data/accessibility/html/input-color-with-popup-open-expected-android-external.txt +++ b/content/test/data/accessibility/html/input-color-with-popup-open-expected-android-external.txt
@@ -1,3 +1,3 @@ WebView focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] ++View actions:[AX_FOCUS] bundle:[chromeRole="genericContainer"] -++++Spinner text:"#FF9900" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="colorWell", clickableScore="300", roleDescription="color picker"] +++++Spinner text:"#FF9900" supplementalDescription:"color picker" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="colorWell", clickableScore="300", roleDescription="color picker"]
diff --git a/content/test/data/accessibility/html/input-radio-checkbox-label-expected-android-external.txt b/content/test/data/accessibility/html/input-radio-checkbox-label-expected-android-external.txt index dbf4a37..27fd4c0e 100644 --- a/content/test/data/accessibility/html/input-radio-checkbox-label-expected-android-external.txt +++ b/content/test/data/accessibility/html/input-radio-checkbox-label-expected-android-external.txt
@@ -1,10 +1,10 @@ WebView focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] ++View actions:[AX_FOCUS] bundle:[chromeRole="genericContainer"] -++++RadioButton text:"label ignored for radio button" viewIdResName:"radio1" stateDescription:"Not checked. In group, option 1 of 2" checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="radioButton", clickableScore="300"] -++++CheckBox text:"label ignored for checkbox" viewIdResName:"checkbox1" checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="checkBox", clickableScore="300"] +++++RadioButton viewIdResName:"radio1" stateDescription:"Not checked. In group, option 1 of 2" supplementalDescription:"label ignored for radio button" checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="radioButton", clickableScore="300"] +++++CheckBox viewIdResName:"checkbox1" supplementalDescription:"label ignored for checkbox" checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="checkBox", clickableScore="300"] ++++View focusable actions:[FOCUS, AX_FOCUS] bundle:[chromeRole="labelText"] ++++++TextView text:"label exposed for radio button " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] -++++++RadioButton text:"label exposed for radio button" viewIdResName:"radio2" stateDescription:"Not checked. In group, option 2 of 2" checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="radioButton", clickableScore="300"] +++++++RadioButton viewIdResName:"radio2" stateDescription:"Not checked. In group, option 2 of 2" supplementalDescription:"label exposed for radio button" checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="radioButton", clickableScore="300"] ++++View focusable actions:[FOCUS, AX_FOCUS] bundle:[chromeRole="labelText"] ++++++TextView text:"label exposed for checkbox " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] -++++++CheckBox text:"label exposed for checkbox" viewIdResName:"checkbox2" checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="checkBox", clickableScore="300"] +++++++CheckBox viewIdResName:"checkbox2" supplementalDescription:"label exposed for checkbox" checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="checkBox", clickableScore="300"]
diff --git a/content/test/data/accessibility/html/input-radio-expected-android-external.txt b/content/test/data/accessibility/html/input-radio-expected-android-external.txt index 1b893c31..ef0036b 100644 --- a/content/test/data/accessibility/html/input-radio-expected-android-external.txt +++ b/content/test/data/accessibility/html/input-radio-expected-android-external.txt
@@ -6,8 +6,8 @@ ++++RadioButton checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="radioButton", clickableScore="300"] ++++TextView text:"Radio2" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] ++View actions:[AX_FOCUS] bundle:[chromeRole="form"] -++++RadioButton text:"Radio3" stateDescription:"Not checked. In group, option 1 of 2" checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="radioButton", clickableScore="300"] -++++RadioButton text:"Radio4" stateDescription:"Checked. In group, option 2 of 2" checkable clickable focusable checked actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="radioButton", clickableScore="300"] +++++RadioButton stateDescription:"Not checked. In group, option 1 of 2" supplementalDescription:"Radio3" checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="radioButton", clickableScore="300"] +++++RadioButton stateDescription:"Checked. In group, option 2 of 2" supplementalDescription:"Radio4" checkable clickable focusable checked actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="radioButton", clickableScore="300"] ++View actions:[AX_FOCUS] bundle:[chromeRole="form"] -++++RadioButton text:"Radio5" checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="radioButton", clickableScore="300"] -++++RadioButton text:"Radio6" checkable clickable focusable checked actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="radioButton", clickableScore="300"] +++++RadioButton supplementalDescription:"Radio5" checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="radioButton", clickableScore="300"] +++++RadioButton supplementalDescription:"Radio6" checkable clickable focusable checked actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="radioButton", clickableScore="300"]
diff --git a/content/test/data/accessibility/html/input-radio-in-menu-expected-android-external.txt b/content/test/data/accessibility/html/input-radio-in-menu-expected-android-external.txt index a123e3a..5bd67f06 100644 --- a/content/test/data/accessibility/html/input-radio-in-menu-expected-android-external.txt +++ b/content/test/data/accessibility/html/input-radio-in-menu-expected-android-external.txt
@@ -4,8 +4,8 @@ ++++TextView text:"Radio0 " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] ++++RadioButton stateDescription:"Not checked. In group, option 2 of 3" checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="radioButton", clickableScore="300"] ++++TextView text:"Radio1 " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] -++++RadioButton text:"Radio2" stateDescription:"Not checked. In group, option 3 of 3" checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="radioButton", clickableScore="300"] +++++RadioButton stateDescription:"Not checked. In group, option 3 of 3" supplementalDescription:"Radio2" checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="radioButton", clickableScore="300"] ++View CollectionInfo:[rows=0, cols=1] actions:[AX_FOCUS] bundle:[chromeRole="menu", roleDescription="menu"] -++++RadioButton text:"Radio3" stateDescription:"Not checked. In group, option 1 of 3" checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="radioButton", clickableScore="300"] +++++RadioButton stateDescription:"Not checked. In group, option 1 of 3" supplementalDescription:"Radio3" checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="radioButton", clickableScore="300"] ++++RadioButton stateDescription:"Not checked. In group, option 2 of 3" checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="radioButton", clickableScore="300"] ++++RadioButton stateDescription:"Checked. In group, option 3 of 3" checkable clickable focusable checked actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="radioButton", clickableScore="300"]
diff --git a/content/test/data/accessibility/html/label-with-selected-option-expected-android-external.txt b/content/test/data/accessibility/html/label-with-selected-option-expected-android-external.txt index a792605..70b408a 100644 --- a/content/test/data/accessibility/html/label-with-selected-option-expected-android-external.txt +++ b/content/test/data/accessibility/html/label-with-selected-option-expected-android-external.txt
@@ -1,12 +1,12 @@ WebView focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] ++View actions:[AX_FOCUS] bundle:[chromeRole="genericContainer"] -++++CheckBox text:"Test 1: Flash the screen 2 times." viewIdResName:"test1" checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="checkBox", clickableScore="300"] +++++CheckBox viewIdResName:"test1" supplementalDescription:"Test 1: Flash the screen 2 times." checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="checkBox", clickableScore="300"] ++++View actions:[AX_FOCUS] bundle:[chromeRole="labelText"] ++++++TextView text:"Test 1: Flash the screen " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] ++++++View text:"2" canOpenPopUp clickable focusable expandedState:1 actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS, EXPAND] bundle:[chromeRole="comboBoxSelect", clickableScore="300", roleDescription="menu pop up button"] ++++++TextView text:" times." actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] ++View actions:[AX_FOCUS] bundle:[chromeRole="genericContainer"] -++++CheckBox text:"Test 2: Flash the screen 2 times." viewIdResName:"test2" checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="checkBox", clickableScore="300"] +++++CheckBox viewIdResName:"test2" supplementalDescription:"Test 2: Flash the screen 2 times." checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="checkBox", clickableScore="300"] ++++View actions:[AX_FOCUS] bundle:[chromeRole="labelText"] ++++++TextView text:"Test 2: Flash the screen " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] ++++++ListView clickable focusable CollectionInfo:[selection_mode_single, rows=3, cols=1] actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="listBox", clickableScore="300"] @@ -15,13 +15,13 @@ ++++++++View text:"3" clickable focusable CollectionItemInfo:[rowIndex=2, colIndex=0] actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="listBoxOption", clickableScore="200"] ++++++TextView text:" times." actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] ++View actions:[AX_FOCUS] bundle:[chromeRole="genericContainer"] -++++CheckBox text:"Test 3: Flash the screen two times." viewIdResName:"test3" checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="checkBox", clickableScore="300"] +++++CheckBox viewIdResName:"test3" supplementalDescription:"Test 3: Flash the screen two times." checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="checkBox", clickableScore="300"] ++++View actions:[AX_FOCUS] bundle:[chromeRole="labelText"] ++++++TextView text:"Test 3: Flash the screen " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] ++++++View text:"two" canOpenPopUp clickable focusable expandedState:1 actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS, EXPAND] bundle:[chromeRole="comboBoxSelect", clickableScore="300", roleDescription="menu pop up button"] ++++++TextView text:" times." actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] ++View actions:[AX_FOCUS] bundle:[chromeRole="genericContainer"] -++++CheckBox text:"Test 4: Flash the screen two times." viewIdResName:"test4" checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="checkBox", clickableScore="300"] +++++CheckBox viewIdResName:"test4" supplementalDescription:"Test 4: Flash the screen two times." checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="checkBox", clickableScore="300"] ++++View actions:[AX_FOCUS] bundle:[chromeRole="labelText"] ++++++TextView text:"Test 4: Flash the screen " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] ++++++ListView clickable focusable CollectionInfo:[selection_mode_single, rows=3, cols=1] actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="listBox", clickableScore="300"] @@ -30,7 +30,7 @@ ++++++++View text:"3" clickable focusable CollectionItemInfo:[rowIndex=2, colIndex=0] actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="listBoxOption", clickableScore="200"] ++++++TextView text:" times." actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] ++View actions:[AX_FOCUS] bundle:[chromeRole="genericContainer"] -++++CheckBox text:"Test 5: Flash the screen two 3 times." viewIdResName:"test5" checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="checkBox", clickableScore="300"] +++++CheckBox viewIdResName:"test5" supplementalDescription:"Test 5: Flash the screen two 3 times." checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="checkBox", clickableScore="300"] ++++View actions:[AX_FOCUS] bundle:[chromeRole="labelText"] ++++++TextView text:"Test 5: Flash the screen " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] ++++++ListView stateDescription:"multiselectable, 2 of 3 selected." clickable focusable CollectionInfo:[selection_mode_multiple, rows=3, cols=1] actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="listBox", clickableScore="300"]
diff --git a/content/test/data/accessibility/html/li-expected-android-external.txt b/content/test/data/accessibility/html/li-expected-android-external.txt index 08d9114..f1685f5 100644 --- a/content/test/data/accessibility/html/li-expected-android-external.txt +++ b/content/test/data/accessibility/html/li-expected-android-external.txt
@@ -1,11 +1,11 @@ WebView focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] ++ListView CollectionInfo:[rows=3, cols=1] actions:[AX_FOCUS] bundle:[chromeRole="list"] -++++View text:"Custom name" CollectionItemInfo:[rowIndex=0, colIndex=0] actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="listItem"] -++++++View text:"• " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="listMarker"] +++++View supplementalDescription:"Custom name" CollectionItemInfo:[rowIndex=0, colIndex=0] actions:[AX_FOCUS] bundle:[chromeRole="listItem"] +++++++View text:"• " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="listMarker"] ++++++TextView text:"Item 1" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] ++++View CollectionItemInfo:[rowIndex=1, colIndex=0] actions:[AX_FOCUS] bundle:[chromeRole="listItem"] -++++++View text:"• " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="listMarker"] +++++++View text:"• " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="listMarker"] ++++++TextView text:"Item 2" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"] ++++View CollectionItemInfo:[rowIndex=2, colIndex=0] actions:[AX_FOCUS] bundle:[chromeRole="listItem"] -++++++View text:"• " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="listMarker"] +++++++View text:"• " actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="listMarker"] ++++++TextView text:"Item 3" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText"]
diff --git a/content/test/data/accessibility/html/name-from-related-fieldset-expected-android-external.txt b/content/test/data/accessibility/html/name-from-related-fieldset-expected-android-external.txt index aaa4217..c59bb63 100644 --- a/content/test/data/accessibility/html/name-from-related-fieldset-expected-android-external.txt +++ b/content/test/data/accessibility/html/name-from-related-fieldset-expected-android-external.txt
@@ -1,4 +1,4 @@ WebView focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] ++View containerTitle:"User Preferences" actions:[AX_FOCUS] bundle:[chromeRole="group"] ++++View text:"User Preferences" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="legend"] -++++CheckBox text:"Dark Mode" viewIdResName:"dark-mode" checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="checkBox", clickableScore="300"] +++++CheckBox viewIdResName:"dark-mode" supplementalDescription:"Dark Mode" checkable clickable focusable actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="checkBox", clickableScore="300"]
diff --git a/content/test/data/accessibility/html/name-from-related-labelable-expected-android-external.txt b/content/test/data/accessibility/html/name-from-related-labelable-expected-android-external.txt index 7f1cdb61..64f8137 100644 --- a/content/test/data/accessibility/html/name-from-related-labelable-expected-android-external.txt +++ b/content/test/data/accessibility/html/name-from-related-labelable-expected-android-external.txt
@@ -1,4 +1,4 @@ WebView focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] ++View actions:[AX_FOCUS] bundle:[chromeRole="genericContainer"] ++++View text:"Username:" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="labelText"] -++++EditText hint:"Username:" viewIdResName:"username" clickable editable focusable inputType:1 textSelectionStart:0 textSelectionEnd:0 actions:[FOCUS, CLICK, AX_FOCUS, PASTE, SET_TEXT, IME_ENTER] bundle:[chromeRole="textField", clickableScore="300", hint="Username:"] +++++EditText viewIdResName:"username" supplementalDescription:"Username:" clickable editable focusable inputType:1 textSelectionStart:0 textSelectionEnd:0 actions:[FOCUS, CLICK, AX_FOCUS, PASTE, SET_TEXT, IME_ENTER] bundle:[chromeRole="textField", clickableScore="300"]
diff --git a/content/test/data/accessibility/html/name-from-related-svg-expected-android-external.txt b/content/test/data/accessibility/html/name-from-related-svg-expected-android-external.txt index 019e333c..2b274eb 100644 --- a/content/test/data/accessibility/html/name-from-related-svg-expected-android-external.txt +++ b/content/test/data/accessibility/html/name-from-related-svg-expected-android-external.txt
@@ -1,3 +1,3 @@ WebView focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea", hasImage="true"] ++View actions:[AX_FOCUS] bundle:[chromeRole="genericContainer", hasImage="true"] -++++Image text:"A red circle" tooltipText:"A red circle" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="image", hasImage="true"] +++++Image tooltipText:"A red circle" supplementalDescription:"A red circle" actions:[AX_FOCUS] bundle:[chromeRole="image", hasImage="true"]
diff --git a/content/test/data/accessibility/html/name-from-related-title-expected-android-external.txt b/content/test/data/accessibility/html/name-from-related-title-expected-android-external.txt index d6774a1..34f8281 100644 --- a/content/test/data/accessibility/html/name-from-related-title-expected-android-external.txt +++ b/content/test/data/accessibility/html/name-from-related-title-expected-android-external.txt
@@ -1,2 +1,2 @@ -WebView text:"Document Title Example" focusable focused actions:[CLEAR_FOCUS, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="rootWebArea"] +WebView supplementalDescription:"Document Title Example" focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] ++TextView text:"Testing document title name mapping." actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="paragraph"]
diff --git a/content/test/data/accessibility/html/select-open-expected-android-external.txt b/content/test/data/accessibility/html/select-open-expected-android-external.txt index 3f2ec10..ca5f4bc 100644 --- a/content/test/data/accessibility/html/select-open-expected-android-external.txt +++ b/content/test/data/accessibility/html/select-open-expected-android-external.txt
@@ -1,4 +1,4 @@ WebView focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] ++View actions:[AX_FOCUS] bundle:[chromeRole="genericContainer"] -++++View text:"Eggplant" hint:"Animal collapsed" canOpenPopUp clickable focusable expandedState:1 actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS, EXPAND] bundle:[chromeRole="comboBoxSelect", clickableScore="300", hint="Animal collapsed", roleDescription="menu pop up button"] -++++View text:"Mango" hint:"Fruit expanded" canOpenPopUp clickable focusable expandedState:1 actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS, EXPAND] bundle:[chromeRole="comboBoxSelect", clickableScore="300", hint="Fruit expanded", roleDescription="menu pop up button"] +++++View text:"Eggplant" supplementalDescription:"Animal collapsed" canOpenPopUp clickable focusable expandedState:1 actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS, EXPAND] bundle:[chromeRole="comboBoxSelect", clickableScore="300", roleDescription="menu pop up button"] +++++View text:"Mango" supplementalDescription:"Fruit expanded" canOpenPopUp clickable focusable expandedState:1 actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS, EXPAND] bundle:[chromeRole="comboBoxSelect", clickableScore="300", roleDescription="menu pop up button"]
diff --git a/content/test/data/accessibility/html/summary-expected-android-external.txt b/content/test/data/accessibility/html/summary-expected-android-external.txt index 9e09e10..0829cc0 100644 --- a/content/test/data/accessibility/html/summary-expected-android-external.txt +++ b/content/test/data/accessibility/html/summary-expected-android-external.txt
@@ -2,5 +2,5 @@ ++View actions:[AX_FOCUS] bundle:[chromeRole="details"] ++++View text:"details tag" clickable focusable expandedState:1 actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS, EXPAND] bundle:[chromeRole="disclosureTriangle", clickableScore="300", roleDescription="disclosure triangle"] ++View actions:[AX_FOCUS] bundle:[chromeRole="details"] -++++View text:"name" hint:"details #2" clickable focusable expandedState:1 actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS, EXPAND] bundle:[chromeRole="disclosureTriangle", clickableScore="300", hint="details #2", roleDescription="disclosure triangle"] +++++View text:"details #2" hint:"details #2" supplementalDescription:"name" clickable focusable expandedState:1 actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS, EXPAND] bundle:[chromeRole="disclosureTriangle", clickableScore="300", hint="details #2", roleDescription="disclosure triangle"] ++++++TextView text:"details #2" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="staticText", clickableScore="100"]
diff --git a/content/test/data/accessibility/html/svg-as-object-source-expected-android-external.txt b/content/test/data/accessibility/html/svg-as-object-source-expected-android-external.txt index a852407..25c8da0 100644 --- a/content/test/data/accessibility/html/svg-as-object-source-expected-android-external.txt +++ b/content/test/data/accessibility/html/svg-as-object-source-expected-android-external.txt
@@ -1,4 +1,4 @@ WebView focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] ++View actions:[AX_FOCUS] bundle:[chromeRole="genericContainer"] -++++View text:"object without space" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="pluginObject", roleDescription="object"] -++++View text:"object with space" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="pluginObject", roleDescription="object"] +++++View supplementalDescription:"object without space" actions:[AX_FOCUS] bundle:[chromeRole="pluginObject", roleDescription="object"] +++++View supplementalDescription:"object with space" actions:[AX_FOCUS] bundle:[chromeRole="pluginObject", roleDescription="object"]
diff --git a/content/test/data/accessibility/html/svg-symbol-with-role-expected-android-external.txt b/content/test/data/accessibility/html/svg-symbol-with-role-expected-android-external.txt index 4e92cb7e..d2eb49b 100644 --- a/content/test/data/accessibility/html/svg-symbol-with-role-expected-android-external.txt +++ b/content/test/data/accessibility/html/svg-symbol-with-role-expected-android-external.txt
@@ -1,5 +1,5 @@ WebView focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea", hasImage="true"] ++View actions:[AX_FOCUS] bundle:[chromeRole="genericContainer", hasImage="true"] ++++Image actions:[AX_FOCUS] bundle:[chromeRole="svgRoot", hasImage="true"] -++++++Button text:"Click me!" tooltipText:"Click me!" viewIdResName:"myRect" clickable actions:[CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="button", roleDescription="fancy button"] -++++++Button text:"Click me!" tooltipText:"Click me!" viewIdResName:"myRect" clickable actions:[CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="button", roleDescription="fancy button"] +++++++Button tooltipText:"Click me!" viewIdResName:"myRect" supplementalDescription:"Click me!" clickable actions:[CLICK, AX_FOCUS] bundle:[chromeRole="button", roleDescription="fancy button"] +++++++Button tooltipText:"Click me!" viewIdResName:"myRect" supplementalDescription:"Click me!" clickable actions:[CLICK, AX_FOCUS] bundle:[chromeRole="button", roleDescription="fancy button"]
diff --git a/content/test/data/accessibility/html/svg-text-alternative-computation-expected-android-external.txt b/content/test/data/accessibility/html/svg-text-alternative-computation-expected-android-external.txt index 241179d1..2c4b287f 100644 --- a/content/test/data/accessibility/html/svg-text-alternative-computation-expected-android-external.txt +++ b/content/test/data/accessibility/html/svg-text-alternative-computation-expected-android-external.txt
@@ -1,41 +1,41 @@ WebView focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea", hasImage="true"] ++View actions:[AX_FOCUS] bundle:[chromeRole="genericContainer", hasImage="true"] ++++Image actions:[AX_FOCUS] bundle:[chromeRole="svgRoot", hasImage="true"] -++++++View text:"null" tooltipText:"Link (from title)" contentDescription:"Link (from aria-labelledby)" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="link", clickableScore="300", roleDescription="link", targetUrl="file:///storage/emulated/0/chromium_tests_root/content/test/data/accessibility/html/foo.html"] +++++++View text:"null" tooltipText:"Link (from title)" contentDescription:"" supplementalDescription:"Link (from aria-labelledby)" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="link", clickableScore="300", roleDescription="link", targetUrl="file:///storage/emulated/0/chromium_tests_root/content/test/data/accessibility/html/foo.html"] ++++Image actions:[AX_FOCUS] bundle:[chromeRole="svgRoot", hasImage="true"] ++++++View tooltipText:"Link (from title)" contentDescription:"Link (from aria-label)" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="link", clickableScore="300", roleDescription="link", targetUrl="file:///storage/emulated/0/chromium_tests_root/content/test/data/accessibility/html/foo.html"] ++++Image actions:[AX_FOCUS] bundle:[chromeRole="svgRoot", hasImage="true"] -++++++View text:"null" hint:"Link (from xlink:title)" tooltipText:"Link (from title)" contentDescription:"Link (from title)" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="link", clickableScore="300", hint="Link (from xlink:title)", roleDescription="link", targetUrl="file:///storage/emulated/0/chromium_tests_root/content/test/data/accessibility/html/foo.html"] +++++++View text:"null" hint:"Link (from xlink:title)" tooltipText:"Link (from title)" contentDescription:"" supplementalDescription:"Link (from title)" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="link", clickableScore="300", hint="Link (from xlink:title)", roleDescription="link", targetUrl="file:///storage/emulated/0/chromium_tests_root/content/test/data/accessibility/html/foo.html"] ++++Image actions:[AX_FOCUS] bundle:[chromeRole="svgRoot", hasImage="true"] ++++++View contentDescription:"Link (from xlink:title)" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="link", clickableScore="300", roleDescription="link", targetUrl="file:///storage/emulated/0/chromium_tests_root/content/test/data/accessibility/html/foo.html"] ++++Image actions:[AX_FOCUS] bundle:[chromeRole="svgRoot", hasImage="true"] -++++++View text:"Circle (from aria-labelledby)" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="graphicsSymbol", hasImage="true", roleDescription="graphics symbol"] +++++++View supplementalDescription:"Circle (from aria-labelledby)" actions:[AX_FOCUS] bundle:[chromeRole="graphicsSymbol", hasImage="true", roleDescription="graphics symbol"] ++++Image actions:[AX_FOCUS] bundle:[chromeRole="svgRoot", hasImage="true"] ++++++View contentDescription:"Circle (from aria-label)" actions:[AX_FOCUS] bundle:[chromeRole="graphicsSymbol", hasImage="true", roleDescription="graphics symbol"] ++++Image actions:[AX_FOCUS] bundle:[chromeRole="svgRoot", hasImage="true"] -++++++View text:"Circle (from title)" tooltipText:"Circle (from title)" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="graphicsSymbol", hasImage="true", roleDescription="graphics symbol"] +++++++View tooltipText:"Circle (from title)" supplementalDescription:"Circle (from title)" actions:[AX_FOCUS] bundle:[chromeRole="graphicsSymbol", hasImage="true", roleDescription="graphics symbol"] ++++Image actions:[AX_FOCUS] bundle:[chromeRole="svgRoot", hasImage="true"] -++++++View text:"Circle (From first use element's title)" tooltipText:"Circle (From first use element's title)" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="graphicsObject", roleDescription="graphics object"] -++++++View text:"Circle (From second use element's title)" tooltipText:"Circle (From second use element's title)" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="graphicsObject", roleDescription="graphics object"] +++++++View tooltipText:"Circle (From first use element's title)" supplementalDescription:"Circle (From first use element's title)" actions:[AX_FOCUS] bundle:[chromeRole="graphicsObject", roleDescription="graphics object"] +++++++View tooltipText:"Circle (From second use element's title)" supplementalDescription:"Circle (From second use element's title)" actions:[AX_FOCUS] bundle:[chromeRole="graphicsObject", roleDescription="graphics object"] ++++Image actions:[AX_FOCUS] bundle:[chromeRole="svgRoot", hasImage="true"] ++++++View tooltipText:"Rectangle Symbol (From symbol's title)" viewIdResName:"myRect" containerTitle:"Rectangle Symbol (From symbol's title)" actions:[AX_FOCUS] bundle:[chromeRole="group"] ++++++View tooltipText:"Rectangle Symbol (From symbol's title)" viewIdResName:"myRect" containerTitle:"Rectangle Symbol (From symbol's title)" actions:[AX_FOCUS] bundle:[chromeRole="group"] ++++Image actions:[AX_FOCUS] bundle:[chromeRole="svgRoot", hasImage="true"] -++++++View text:"null" hint:"Link (from aria-describedby)" tooltipText:"Link (from title)" contentDescription:"Link (from title)" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="link", clickableScore="300", hint="Link (from aria-describedby)", roleDescription="link", targetUrl="file:///storage/emulated/0/chromium_tests_root/content/test/data/accessibility/html/foo.html"] +++++++View text:"null" hint:"Link (from aria-describedby)" tooltipText:"Link (from title)" contentDescription:"" supplementalDescription:"Link (from title)" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="link", clickableScore="300", hint="Link (from aria-describedby)", roleDescription="link", targetUrl="file:///storage/emulated/0/chromium_tests_root/content/test/data/accessibility/html/foo.html"] ++++Image actions:[AX_FOCUS] bundle:[chromeRole="svgRoot", hasImage="true"] -++++++View text:"null" hint:"Link (from aria-description)" tooltipText:"Link (from title)" contentDescription:"Link (from title)" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="link", clickableScore="300", hint="Link (from aria-description)", roleDescription="link", targetUrl="file:///storage/emulated/0/chromium_tests_root/content/test/data/accessibility/html/foo.html"] +++++++View text:"null" hint:"Link (from aria-description)" tooltipText:"Link (from title)" contentDescription:"" supplementalDescription:"Link (from title)" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="link", clickableScore="300", hint="Link (from aria-description)", roleDescription="link", targetUrl="file:///storage/emulated/0/chromium_tests_root/content/test/data/accessibility/html/foo.html"] ++++Image actions:[AX_FOCUS] bundle:[chromeRole="svgRoot", hasImage="true"] -++++++View text:"null" hint:"Link (from desc)" tooltipText:"Link (from title)" contentDescription:"Link (from title)" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="link", clickableScore="300", hint="Link (from desc)", roleDescription="link", targetUrl="file:///storage/emulated/0/chromium_tests_root/content/test/data/accessibility/html/foo.html"] +++++++View text:"null" hint:"Link (from desc)" tooltipText:"Link (from title)" contentDescription:"" supplementalDescription:"Link (from title)" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="link", clickableScore="300", hint="Link (from desc)", roleDescription="link", targetUrl="file:///storage/emulated/0/chromium_tests_root/content/test/data/accessibility/html/foo.html"] ++++Image actions:[AX_FOCUS] bundle:[chromeRole="svgRoot", hasImage="true"] ++++++View tooltipText:"Link (from title)" contentDescription:"Link (from aria-label)" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="link", clickableScore="300", roleDescription="link", targetUrl="file:///storage/emulated/0/chromium_tests_root/content/test/data/accessibility/html/foo.html"] ++++Image actions:[AX_FOCUS] bundle:[chromeRole="svgRoot", hasImage="true"] -++++++View text:"null" hint:"Link (from xlink:title)" tooltipText:"Link (from title)" contentDescription:"Link (from title)" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="link", clickableScore="300", hint="Link (from xlink:title)", roleDescription="link", targetUrl="file:///storage/emulated/0/chromium_tests_root/content/test/data/accessibility/html/foo.html"] +++++++View text:"null" hint:"Link (from xlink:title)" tooltipText:"Link (from title)" contentDescription:"" supplementalDescription:"Link (from title)" clickable focusable actions:[FOCUS, CLICK, AX_FOCUS] bundle:[chromeRole="link", clickableScore="300", hint="Link (from xlink:title)", roleDescription="link", targetUrl="file:///storage/emulated/0/chromium_tests_root/content/test/data/accessibility/html/foo.html"] ++++Image actions:[AX_FOCUS] bundle:[chromeRole="svgRoot", hasImage="true"] ++++++View hint:"Circle (From first use element's desc)" actions:[AX_FOCUS] bundle:[chromeRole="graphicsObject", hint="Circle (From first use element's desc)", roleDescription="graphics object"] ++++++View hint:"Circle (From second use element's desc)" actions:[AX_FOCUS] bundle:[chromeRole="graphicsObject", hint="Circle (From second use element's desc)", roleDescription="graphics object"] ++++Image actions:[AX_FOCUS] bundle:[chromeRole="svgRoot", hasImage="true"] -++++++View text:"Circle 1" tooltipText:"Circle (From first use element's title)" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="graphicsObject", roleDescription="graphics object"] -++++++View text:"Circle 2" tooltipText:"Circle (From second use element's title)" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="graphicsObject", roleDescription="graphics object"] +++++++View tooltipText:"Circle (From first use element's title)" supplementalDescription:"Circle 1" actions:[AX_FOCUS] bundle:[chromeRole="graphicsObject", roleDescription="graphics object"] +++++++View tooltipText:"Circle (From second use element's title)" supplementalDescription:"Circle 2" actions:[AX_FOCUS] bundle:[chromeRole="graphicsObject", roleDescription="graphics object"] ++++Image actions:[AX_FOCUS] bundle:[chromeRole="svgRoot", hasImage="true"] ++++++View hint:"Rectangle Symbol (From symbol's desc)" viewIdResName:"myRect2" actions:[AX_FOCUS] bundle:[chromeRole="group", hint="Rectangle Symbol (From symbol's desc)"] ++++++View hint:"Rectangle Symbol (From symbol's desc)" viewIdResName:"myRect2" actions:[AX_FOCUS] bundle:[chromeRole="group", hint="Rectangle Symbol (From symbol's desc)"]
diff --git a/content/test/data/accessibility/html/tab-panel-expected-android-external.txt b/content/test/data/accessibility/html/tab-panel-expected-android-external.txt index 3e9b491..663a6ea 100644 --- a/content/test/data/accessibility/html/tab-panel-expected-android-external.txt +++ b/content/test/data/accessibility/html/tab-panel-expected-android-external.txt
@@ -2,5 +2,5 @@ ++View text:"First Tab" viewIdResName:"tab-1" clickable focusable selected CollectionItemInfo:[rowSpan=0, colSpan=0, rowIndex=0, colIndex=0] actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="tab", clickableScore="300", roleDescription="tab"] ++View text:"Second Tab" viewIdResName:"tab-2" clickable focusable CollectionItemInfo:[rowSpan=0, colSpan=0, rowIndex=0, colIndex=0] actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="tab", clickableScore="300", roleDescription="tab"] ++View text:"Third Tab" viewIdResName:"tab-3" clickable focusable CollectionItemInfo:[rowSpan=0, colSpan=0, rowIndex=0, colIndex=0] actions:[FOCUS, CLICK, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="tab", clickableScore="300", roleDescription="tab"] -++View text:"First Tab" viewIdResName:"panel-1" focusable actions:[FOCUS, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="tabPanel", roleDescription="tab panel"] +++View viewIdResName:"panel-1" supplementalDescription:"First Tab" focusable actions:[FOCUS, AX_FOCUS] bundle:[chromeRole="tabPanel", roleDescription="tab panel"] ++++TextView text:"Content for the first panel, this should be read." actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="paragraph"]
diff --git a/content/test/data/accessibility/html/table-focusable-sections-expected-android-external.txt b/content/test/data/accessibility/html/table-focusable-sections-expected-android-external.txt index 309efe4..e4b9edc 100644 --- a/content/test/data/accessibility/html/table-focusable-sections-expected-android-external.txt +++ b/content/test/data/accessibility/html/table-focusable-sections-expected-android-external.txt
@@ -1,4 +1,4 @@ -WebView text:"Table example - focusable thead, tbody, tfoot" focusable focused actions:[CLEAR_FOCUS, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="rootWebArea"] +WebView supplementalDescription:"Table example - focusable thead, tbody, tfoot" focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] ++GridView CollectionInfo:[rows=4, cols=2] actions:[AX_FOCUS] bundle:[chromeRole="table"] ++++View actions:[AX_FOCUS] bundle:[chromeRole="row"] ++++++View text:"Sum" heading CollectionItemInfo:[tableHeader, rowIndex=0, colIndex=0] actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="columnHeader"]
diff --git a/content/test/data/accessibility/html/table-layout-expected-android-external.txt b/content/test/data/accessibility/html/table-layout-expected-android-external.txt index cefc464..5eddd524 100644 --- a/content/test/data/accessibility/html/table-layout-expected-android-external.txt +++ b/content/test/data/accessibility/html/table-layout-expected-android-external.txt
@@ -1,4 +1,4 @@ -WebView text:"Table example #2" focusable focused actions:[CLEAR_FOCUS, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="rootWebArea"] +WebView supplementalDescription:"Table example #2" focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] ++View actions:[AX_FOCUS] bundle:[chromeRole="layoutTable"] ++++View actions:[AX_FOCUS] bundle:[chromeRole="layoutTableRow"] ++++++View text:"1" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="layoutTableCell"]
diff --git a/content/test/data/accessibility/html/table-presentation-expected-android-external.txt b/content/test/data/accessibility/html/table-presentation-expected-android-external.txt index c8b2aff1..4c59d26b 100644 --- a/content/test/data/accessibility/html/table-presentation-expected-android-external.txt +++ b/content/test/data/accessibility/html/table-presentation-expected-android-external.txt
@@ -1,4 +1,4 @@ -WebView text:"Table with role=presentation" focusable focused actions:[CLEAR_FOCUS, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="rootWebArea"] +WebView supplementalDescription:"Table with role=presentation" focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] ++TextView text:"1" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="genericContainer"] ++TextView text:"2" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="genericContainer"] ++TextView text:"4" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="genericContainer"]
diff --git a/content/test/data/accessibility/html/table-simple-2-expected-android-external.txt b/content/test/data/accessibility/html/table-simple-2-expected-android-external.txt index cefc464..5eddd524 100644 --- a/content/test/data/accessibility/html/table-simple-2-expected-android-external.txt +++ b/content/test/data/accessibility/html/table-simple-2-expected-android-external.txt
@@ -1,4 +1,4 @@ -WebView text:"Table example #2" focusable focused actions:[CLEAR_FOCUS, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="rootWebArea"] +WebView supplementalDescription:"Table example #2" focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] ++View actions:[AX_FOCUS] bundle:[chromeRole="layoutTable"] ++++View actions:[AX_FOCUS] bundle:[chromeRole="layoutTableRow"] ++++++View text:"1" actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="layoutTableCell"]
diff --git a/content/test/data/accessibility/html/table-simple-expected-android-external.txt b/content/test/data/accessibility/html/table-simple-expected-android-external.txt index 5e27e47..6e8b5d5 100644 --- a/content/test/data/accessibility/html/table-simple-expected-android-external.txt +++ b/content/test/data/accessibility/html/table-simple-expected-android-external.txt
@@ -1,4 +1,4 @@ -WebView text:"Table example" focusable focused actions:[CLEAR_FOCUS, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="rootWebArea"] +WebView supplementalDescription:"Table example" focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] ++GridView CollectionInfo:[rows=3, cols=2] actions:[AX_FOCUS] bundle:[chromeRole="table"] ++++View actions:[AX_FOCUS] bundle:[chromeRole="row"] ++++++View text:"Pair" heading CollectionItemInfo:[tableHeader, rowIndex=0, colIndex=0] actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="columnHeader"]
diff --git a/content/test/data/accessibility/html/table-spans-expected-android-external.txt b/content/test/data/accessibility/html/table-spans-expected-android-external.txt index 8d968c3..f393b94 100644 --- a/content/test/data/accessibility/html/table-spans-expected-android-external.txt +++ b/content/test/data/accessibility/html/table-spans-expected-android-external.txt
@@ -1,4 +1,4 @@ -WebView text:"Table example with rowspan and colspan" focusable focused actions:[CLEAR_FOCUS, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="rootWebArea"] +WebView supplementalDescription:"Table example with rowspan and colspan" focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] ++GridView CollectionInfo:[rows=2, cols=2] actions:[AX_FOCUS] bundle:[chromeRole="table"] ++++View actions:[AX_FOCUS] bundle:[chromeRole="row"] ++++++View text:"AD" CollectionItemInfo:[rowSpan=2, rowIndex=0, colIndex=0] actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="cell"]
diff --git a/content/test/data/accessibility/html/table-th-rowheader-expected-android-external.txt b/content/test/data/accessibility/html/table-th-rowheader-expected-android-external.txt index 91fe936c..f3ab3b6 100644 --- a/content/test/data/accessibility/html/table-th-rowheader-expected-android-external.txt +++ b/content/test/data/accessibility/html/table-th-rowheader-expected-android-external.txt
@@ -1,4 +1,4 @@ -WebView text:"Table example - th rowheader" focusable focused actions:[CLEAR_FOCUS, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="rootWebArea"] +WebView supplementalDescription:"Table example - th rowheader" focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] ++GridView CollectionInfo:[rows=2, cols=2] actions:[AX_FOCUS] bundle:[chromeRole="table"] ++++View actions:[AX_FOCUS] bundle:[chromeRole="row"] ++++++View contentDescription:"Firstname" heading CollectionItemInfo:[tableHeader, rowIndex=0, colIndex=0] actions:[AX_FOCUS] bundle:[chromeRole="rowHeader"]
diff --git a/content/test/data/accessibility/html/table-thead-tbody-tfoot-expected-android-external.txt b/content/test/data/accessibility/html/table-thead-tbody-tfoot-expected-android-external.txt index 05b9869d..09d817d7 100644 --- a/content/test/data/accessibility/html/table-thead-tbody-tfoot-expected-android-external.txt +++ b/content/test/data/accessibility/html/table-thead-tbody-tfoot-expected-android-external.txt
@@ -1,4 +1,4 @@ -WebView text:"Table example - thead, tbody, tfoot" focusable focused actions:[CLEAR_FOCUS, AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="rootWebArea"] +WebView supplementalDescription:"Table example - thead, tbody, tfoot" focusable focused actions:[CLEAR_FOCUS, AX_FOCUS] bundle:[chromeRole="rootWebArea"] ++GridView CollectionInfo:[rows=4, cols=2] actions:[AX_FOCUS] bundle:[chromeRole="table"] ++++View actions:[AX_FOCUS] bundle:[chromeRole="row"] ++++++View text:"Sum" heading CollectionItemInfo:[tableHeader, rowIndex=0, colIndex=0] actions:[AX_FOCUS, NEXT, PREVIOUS] bundle:[chromeRole="columnHeader"]
diff --git a/device/base/features.cc b/device/base/features.cc index c4cc032..0037dea 100644 --- a/device/base/features.cc +++ b/device/base/features.cc
@@ -39,10 +39,5 @@ base::FEATURE_DISABLED_BY_DEFAULT); #endif // BUILDFLAG(IS_ANDROID) -#if BUILDFLAG(IS_ANDROID) -// Controls whether to enable Web Serial API for wired devices on Android. -BASE_FEATURE(kWebSerialWiredDevicesAndroid, base::FEATURE_ENABLED_BY_DEFAULT); -#endif // BUILDFLAG(IS_ANDROID) - } // namespace features } // namespace device
diff --git a/docs/website b/docs/website index adf532f..81a7ea9 160000 --- a/docs/website +++ b/docs/website
@@ -1 +1 @@ -Subproject commit adf532f7c299a1f849f0310446669bcaf3816230 +Subproject commit 81a7ea93897de0f405c0105c06e94b2c7d8f9b34
diff --git a/extensions/browser/api/web_request/web_request_api.cc b/extensions/browser/api/web_request/web_request_api.cc index ee00f64..84606c51 100644 --- a/extensions/browser/api/web_request/web_request_api.cc +++ b/extensions/browser/api/web_request/web_request_api.cc
@@ -1009,7 +1009,7 @@ void WebRequestAPI::UpdateMayHaveProxies() { bool may_have_proxies = MayHaveProxies(); - if (!may_have_proxies_ && may_have_proxies) { + if (may_have_proxies_ != may_have_proxies) { ResetURLLoaderFactories(); } may_have_proxies_ = may_have_proxies;
diff --git a/extensions/browser/api/web_request/web_request_api.h b/extensions/browser/api/web_request/web_request_api.h index 4473f73..31d9473 100644 --- a/extensions/browser/api/web_request/web_request_api.h +++ b/extensions/browser/api/web_request/web_request_api.h
@@ -320,8 +320,8 @@ static const bool kServiceRedirectedInIncognito = true; static const bool kServiceIsNULLWhileTesting = true; - // Checks if |MayHaveProxies()| has changed from false to true, and resets - // URLLoaderFactories if so. + // Checks if |MayHaveProxies()| has changed, and resets URLLoaderFactories + // if so. void UpdateMayHaveProxies(); void ResetURLLoaderFactories();
diff --git a/extensions/browser/service_worker/service_worker_task_queue.cc b/extensions/browser/service_worker/service_worker_task_queue.cc index 7157535..b65ff987 100644 --- a/extensions/browser/service_worker/service_worker_task_queue.cc +++ b/extensions/browser/service_worker/service_worker_task_queue.cc
@@ -529,6 +529,9 @@ context_id.token, worker_unregistration_wait_retries_, base::BindOnce(&ServiceWorkerTaskQueue::RetryRegisterServiceWorker, weak_factory_.GetWeakPtr(), context_id, reason))) { + if (g_test_observer) { + g_test_observer->OnWorkerRegistrationDelayed(context_id.extension_id); + } return; } @@ -783,8 +786,6 @@ return true; // Registration or version was not found. - // TODO(https://crbug.com/444255717): investigate and clean up - // if it's not actually transient. case blink::ServiceWorkerStatusCode::kErrorNotFound: return true; @@ -848,7 +849,7 @@ return; } - if (it->second->backoff_entry.failure_count() > 0) { + if (histogram_name && it->second->backoff_entry.failure_count() > 0) { base::UmaHistogramBoolean(histogram_name, success); } retry_map.erase(it); @@ -934,9 +935,7 @@ "WorkerRegistrationRetryAttemptsResult", success); ClearRetryState(context_id.token, worker_unregistration_wait_retries_, - "Extensions.ServiceWorkerBackground." - "WorkerRegistrationRetryForUnregistrationAttemptsResult", - success); + nullptr, success); // After retries are exhausted, emit the ultimate end result. base::UmaHistogramBoolean(
diff --git a/extensions/browser/service_worker/service_worker_task_queue.h b/extensions/browser/service_worker/service_worker_task_queue.h index 910374b3..41ecc06 100644 --- a/extensions/browser/service_worker/service_worker_task_queue.h +++ b/extensions/browser/service_worker/service_worker_task_queue.h
@@ -328,6 +328,10 @@ // `extension_id` has been registered in the //content layer. It is always // called, even if the registration request fails. virtual void OnWorkerRegistered(const ExtensionId& extension_id) {} + + // Called when a service worker registration is delayed because there is a + // pending unregistration for the same extension. + virtual void OnWorkerRegistrationDelayed(const ExtensionId& extension_id) {} }; static void SetObserverForTest(TestObserver* observer);
diff --git a/gin/public/gin_embedders.h b/gin/public/gin_embedders.h index cecf528..528656c 100644 --- a/gin/public/gin_embedders.h +++ b/gin/public/gin_embedders.h
@@ -50,7 +50,6 @@ kSetPriorityBindingsTag, kSetPrioritySignalsOverrideBindingsTag, kSharedStorageBindingsTag, - kTextConversionHelpersTag, kWebIDLCompatTestTag, kDeclarativeContentHooksDelegateHandlerCallbackTag, kAPIBindingHandlerCallbackTag,
diff --git "a/infra/config/generated/builders/ci/GPU FYI Mac arm64 Builder \050asan\051/targets/chromium.gpu.fyi.json" "b/infra/config/generated/builders/ci/GPU FYI Mac arm64 Builder \050asan\051/targets/chromium.gpu.fyi.json" index 852816a1..6b8115f 100644 --- "a/infra/config/generated/builders/ci/GPU FYI Mac arm64 Builder \050asan\051/targets/chromium.gpu.fyi.json" +++ "b/infra/config/generated/builders/ci/GPU FYI Mac arm64 Builder \050asan\051/targets/chromium.gpu.fyi.json"
@@ -188,88 +188,6 @@ "--passthrough", "-v", "--stable-jobs", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=gl --disable-skia-graphite", - "--enforce-browser-version", - "--jobs=4" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "module_name": "//chrome/test:telemetry_gpu_integration_test", - "module_scheme": "flat", - "name": "context_lost_gl_passthrough_ganesh_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "containment_type": "AUTO", - "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" - }, - "test": "telemetry_gpu_integration_test", - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" - }, - { - "args": [ - "context_lost", - "--show-stdout", - "--browser=release", - "--passthrough", - "-v", - "--stable-jobs", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=metal --disable-skia-graphite", - "--enforce-browser-version", - "--jobs=4" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "module_name": "//chrome/test:telemetry_gpu_integration_test", - "module_scheme": "flat", - "name": "context_lost_metal_passthrough_ganesh_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "containment_type": "AUTO", - "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" - }, - "test": "telemetry_gpu_integration_test", - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" - }, - { - "args": [ - "context_lost", - "--show-stdout", - "--browser=release", - "--passthrough", - "-v", - "--stable-jobs", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=metal --enable-skia-graphite", "--enforce-browser-version", "--jobs=4" @@ -311,106 +229,6 @@ "--passthrough", "-v", "--stable-jobs", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=gl --disable-skia-graphite", - "--enforce-browser-version", - "--git-revision=${got_revision}", - "--dont-restore-color-profile-after-test", - "--test-machine-name", - "${buildername}", - "--jobs=4" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "module_name": "//chrome/test:telemetry_gpu_integration_test", - "module_scheme": "flat", - "name": "expected_color_pixel_gl_passthrough_ganesh_test", - "precommit_args": [ - "--gerrit-issue=${patch_issue}", - "--gerrit-patchset=${patch_set}", - "--buildbucket-id=${buildbucket_build_id}" - ], - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "containment_type": "AUTO", - "dimensions": { - "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" - }, - "test": "telemetry_gpu_integration_test", - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" - }, - { - "args": [ - "expected_color", - "--show-stdout", - "--browser=release", - "--passthrough", - "-v", - "--stable-jobs", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=metal --disable-skia-graphite", - "--enforce-browser-version", - "--git-revision=${got_revision}", - "--dont-restore-color-profile-after-test", - "--test-machine-name", - "${buildername}", - "--jobs=4" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "module_name": "//chrome/test:telemetry_gpu_integration_test", - "module_scheme": "flat", - "name": "expected_color_pixel_metal_passthrough_ganesh_test", - "precommit_args": [ - "--gerrit-issue=${patch_issue}", - "--gerrit-patchset=${patch_set}", - "--buildbucket-id=${buildbucket_build_id}" - ], - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "containment_type": "AUTO", - "dimensions": { - "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" - }, - "test": "telemetry_gpu_integration_test", - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" - }, - { - "args": [ - "expected_color", - "--show-stdout", - "--browser=release", - "--passthrough", - "-v", - "--stable-jobs", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=metal --enable-skia-graphite", "--enforce-browser-version", "--git-revision=${got_revision}", @@ -588,108 +406,6 @@ "--passthrough", "-v", "--stable-jobs", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=gl --disable-skia-graphite", - "--enforce-browser-version", - "--git-revision=${got_revision}", - "--dont-restore-color-profile-after-test", - "--test-machine-name", - "${buildername}", - "--jobs=4" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "module_name": "//chrome/test:telemetry_gpu_integration_test", - "module_scheme": "flat", - "name": "pixel_skia_gold_gl_passthrough_ganesh_test", - "precommit_args": [ - "--gerrit-issue=${patch_issue}", - "--gerrit-patchset=${patch_set}", - "--buildbucket-id=${buildbucket_build_id}" - ], - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "containment_type": "AUTO", - "dimensions": { - "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": 2 - }, - "test": "telemetry_gpu_integration_test", - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" - }, - { - "args": [ - "pixel", - "--show-stdout", - "--browser=release", - "--passthrough", - "-v", - "--stable-jobs", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=metal --disable-skia-graphite", - "--enforce-browser-version", - "--git-revision=${got_revision}", - "--dont-restore-color-profile-after-test", - "--test-machine-name", - "${buildername}", - "--jobs=4" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "module_name": "//chrome/test:telemetry_gpu_integration_test", - "module_scheme": "flat", - "name": "pixel_skia_gold_metal_passthrough_ganesh_test", - "precommit_args": [ - "--gerrit-issue=${patch_issue}", - "--gerrit-patchset=${patch_set}", - "--buildbucket-id=${buildbucket_build_id}" - ], - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "containment_type": "AUTO", - "dimensions": { - "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": 2 - }, - "test": "telemetry_gpu_integration_test", - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" - }, - { - "args": [ - "pixel", - "--show-stdout", - "--browser=release", - "--passthrough", - "-v", - "--stable-jobs", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=metal --enable-skia-graphite", "--enforce-browser-version", "--git-revision=${got_revision}", @@ -741,90 +457,6 @@ "--passthrough", "-v", "--stable-jobs", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=gl --disable-skia-graphite", - "--enforce-browser-version", - "--dont-restore-color-profile-after-test", - "--jobs=4" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "module_name": "//chrome/test:telemetry_gpu_integration_test", - "module_scheme": "flat", - "name": "screenshot_sync_gl_passthrough_ganesh_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "containment_type": "AUTO", - "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" - }, - "test": "telemetry_gpu_integration_test", - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" - }, - { - "args": [ - "screenshot_sync", - "--show-stdout", - "--browser=release", - "--passthrough", - "-v", - "--stable-jobs", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=metal --disable-skia-graphite", - "--enforce-browser-version", - "--dont-restore-color-profile-after-test", - "--jobs=4" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "module_name": "//chrome/test:telemetry_gpu_integration_test", - "module_scheme": "flat", - "name": "screenshot_sync_metal_passthrough_ganesh_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "containment_type": "AUTO", - "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" - }, - "test": "telemetry_gpu_integration_test", - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" - }, - { - "args": [ - "screenshot_sync", - "--show-stdout", - "--browser=release", - "--passthrough", - "-v", - "--stable-jobs", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=metal --enable-skia-graphite", "--enforce-browser-version", "--dont-restore-color-profile-after-test", @@ -909,88 +541,6 @@ "--passthrough", "-v", "--stable-jobs", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=gl --disable-skia-graphite", - "--enforce-browser-version", - "--jobs=4" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "module_name": "//chrome/test:telemetry_gpu_integration_test", - "module_scheme": "flat", - "name": "webcodecs_gl_passthrough_ganesh_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "containment_type": "AUTO", - "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" - }, - "test": "telemetry_gpu_integration_test", - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" - }, - { - "args": [ - "webcodecs", - "--show-stdout", - "--browser=release", - "--passthrough", - "-v", - "--stable-jobs", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=metal --disable-skia-graphite", - "--enforce-browser-version", - "--jobs=4" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "module_name": "//chrome/test:telemetry_gpu_integration_test", - "module_scheme": "flat", - "name": "webcodecs_metal_passthrough_ganesh_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "containment_type": "AUTO", - "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" - }, - "test": "telemetry_gpu_integration_test", - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" - }, - { - "args": [ - "webcodecs", - "--show-stdout", - "--browser=release", - "--passthrough", - "-v", - "--stable-jobs", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=metal --enable-skia-graphite", "--enforce-browser-version", "--jobs=4" @@ -1032,50 +582,6 @@ "--passthrough", "-v", "--stable-jobs", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=gl --disable-skia-graphite --force_high_performance_gpu", - "--enforce-browser-version", - "--webgl-conformance-version=2.0.1", - "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl2_conformance_mac_runtimes.json", - "--jobs=4" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "module_name": "//chrome/test:telemetry_gpu_integration_test", - "module_scheme": "flat", - "name": "webgl2_conformance_gl_passthrough_ganesh_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "containment_type": "AUTO", - "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": 20 - }, - "test": "telemetry_gpu_integration_test", - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" - }, - { - "args": [ - "webgl2_conformance", - "--show-stdout", - "--browser=release", - "--passthrough", - "-v", - "--stable-jobs", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=metal --enable-skia-graphite --enable-features=EGLDualGPURendering,ForceHighPerformanceGPUForWebGL --disable-metal-shader-cache", "--enforce-browser-version", "--enable-metal-debug-layers", @@ -1121,92 +627,6 @@ "--passthrough", "-v", "--stable-jobs", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=gl --disable-skia-graphite --force_high_performance_gpu", - "--enforce-browser-version", - "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl1_conformance_mac_runtimes.json", - "--jobs=4" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "module_name": "//chrome/test:telemetry_gpu_integration_test", - "module_scheme": "flat", - "name": "webgl_conformance_gl_passthrough_ganesh_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "containment_type": "AUTO", - "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": 2 - }, - "test": "telemetry_gpu_integration_test", - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" - }, - { - "args": [ - "webgl1_conformance", - "--show-stdout", - "--browser=release", - "--passthrough", - "-v", - "--stable-jobs", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=metal --disable-skia-graphite --enable-features=EGLDualGPURendering,ForceHighPerformanceGPUForWebGL", - "--enforce-browser-version", - "--enable-metal-debug-layers", - "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl1_conformance_mac_runtimes.json", - "--jobs=4" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "module_name": "//chrome/test:telemetry_gpu_integration_test", - "module_scheme": "flat", - "name": "webgl_conformance_metal_passthrough_ganesh_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "containment_type": "AUTO", - "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" - }, - "test": "telemetry_gpu_integration_test", - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" - }, - { - "args": [ - "webgl1_conformance", - "--show-stdout", - "--browser=release", - "--passthrough", - "-v", - "--stable-jobs", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=metal --enable-skia-graphite --enable-features=EGLDualGPURendering,ForceHighPerformanceGPUForWebGL --disable-metal-shader-cache", "--enforce-browser-version", "--enable-metal-debug-layers", @@ -1292,88 +712,6 @@ "--passthrough", "-v", "--stable-jobs", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=gl --disable-skia-graphite", - "--enforce-browser-version", - "--jobs=4" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "module_name": "//chrome/test:telemetry_gpu_integration_test", - "module_scheme": "flat", - "name": "webrtc_gl_passthrough_ganesh_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "containment_type": "AUTO", - "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" - }, - "test": "telemetry_gpu_integration_test", - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" - }, - { - "args": [ - "webrtc", - "--show-stdout", - "--browser=release", - "--passthrough", - "-v", - "--stable-jobs", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=metal --disable-skia-graphite", - "--enforce-browser-version", - "--jobs=4" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "module_name": "//chrome/test:telemetry_gpu_integration_test", - "module_scheme": "flat", - "name": "webrtc_metal_passthrough_ganesh_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "containment_type": "AUTO", - "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" - }, - "test": "telemetry_gpu_integration_test", - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" - }, - { - "args": [ - "webrtc", - "--show-stdout", - "--browser=release", - "--passthrough", - "-v", - "--stable-jobs", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=metal --enable-skia-graphite", "--enforce-browser-version", "--jobs=4"
diff --git "a/infra/config/generated/builders/ci/Mac FYI Retina Release ASAN \050Apple M2\051/targets/chromium.gpu.fyi.json" "b/infra/config/generated/builders/ci/Mac FYI Retina Release ASAN \050Apple M2\051/targets/chromium.gpu.fyi.json" index 3c4b8fe..ee4ead1 100644 --- "a/infra/config/generated/builders/ci/Mac FYI Retina Release ASAN \050Apple M2\051/targets/chromium.gpu.fyi.json" +++ "b/infra/config/generated/builders/ci/Mac FYI Retina Release ASAN \050Apple M2\051/targets/chromium.gpu.fyi.json"
@@ -187,88 +187,6 @@ "--passthrough", "-v", "--stable-jobs", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=gl --disable-skia-graphite", - "--enforce-browser-version", - "--jobs=4" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "module_name": "//chrome/test:telemetry_gpu_integration_test", - "module_scheme": "flat", - "name": "context_lost_gl_passthrough_ganesh_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "containment_type": "AUTO", - "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" - }, - "test": "telemetry_gpu_integration_test", - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" - }, - { - "args": [ - "context_lost", - "--show-stdout", - "--browser=release", - "--passthrough", - "-v", - "--stable-jobs", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=metal --disable-skia-graphite", - "--enforce-browser-version", - "--jobs=4" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "module_name": "//chrome/test:telemetry_gpu_integration_test", - "module_scheme": "flat", - "name": "context_lost_metal_passthrough_ganesh_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "containment_type": "AUTO", - "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" - }, - "test": "telemetry_gpu_integration_test", - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" - }, - { - "args": [ - "context_lost", - "--show-stdout", - "--browser=release", - "--passthrough", - "-v", - "--stable-jobs", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=metal --enable-skia-graphite", "--enforce-browser-version", "--jobs=4" @@ -310,106 +228,6 @@ "--passthrough", "-v", "--stable-jobs", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=gl --disable-skia-graphite", - "--enforce-browser-version", - "--git-revision=${got_revision}", - "--dont-restore-color-profile-after-test", - "--test-machine-name", - "${buildername}", - "--jobs=4" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "module_name": "//chrome/test:telemetry_gpu_integration_test", - "module_scheme": "flat", - "name": "expected_color_pixel_gl_passthrough_ganesh_test", - "precommit_args": [ - "--gerrit-issue=${patch_issue}", - "--gerrit-patchset=${patch_set}", - "--buildbucket-id=${buildbucket_build_id}" - ], - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "containment_type": "AUTO", - "dimensions": { - "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" - }, - "test": "telemetry_gpu_integration_test", - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" - }, - { - "args": [ - "expected_color", - "--show-stdout", - "--browser=release", - "--passthrough", - "-v", - "--stable-jobs", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=metal --disable-skia-graphite", - "--enforce-browser-version", - "--git-revision=${got_revision}", - "--dont-restore-color-profile-after-test", - "--test-machine-name", - "${buildername}", - "--jobs=4" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "module_name": "//chrome/test:telemetry_gpu_integration_test", - "module_scheme": "flat", - "name": "expected_color_pixel_metal_passthrough_ganesh_test", - "precommit_args": [ - "--gerrit-issue=${patch_issue}", - "--gerrit-patchset=${patch_set}", - "--buildbucket-id=${buildbucket_build_id}" - ], - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "containment_type": "AUTO", - "dimensions": { - "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" - }, - "test": "telemetry_gpu_integration_test", - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" - }, - { - "args": [ - "expected_color", - "--show-stdout", - "--browser=release", - "--passthrough", - "-v", - "--stable-jobs", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=metal --enable-skia-graphite", "--enforce-browser-version", "--git-revision=${got_revision}", @@ -587,108 +405,6 @@ "--passthrough", "-v", "--stable-jobs", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=gl --disable-skia-graphite", - "--enforce-browser-version", - "--git-revision=${got_revision}", - "--dont-restore-color-profile-after-test", - "--test-machine-name", - "${buildername}", - "--jobs=4" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "module_name": "//chrome/test:telemetry_gpu_integration_test", - "module_scheme": "flat", - "name": "pixel_skia_gold_gl_passthrough_ganesh_test", - "precommit_args": [ - "--gerrit-issue=${patch_issue}", - "--gerrit-patchset=${patch_set}", - "--buildbucket-id=${buildbucket_build_id}" - ], - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "containment_type": "AUTO", - "dimensions": { - "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": 2 - }, - "test": "telemetry_gpu_integration_test", - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" - }, - { - "args": [ - "pixel", - "--show-stdout", - "--browser=release", - "--passthrough", - "-v", - "--stable-jobs", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=metal --disable-skia-graphite", - "--enforce-browser-version", - "--git-revision=${got_revision}", - "--dont-restore-color-profile-after-test", - "--test-machine-name", - "${buildername}", - "--jobs=4" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "module_name": "//chrome/test:telemetry_gpu_integration_test", - "module_scheme": "flat", - "name": "pixel_skia_gold_metal_passthrough_ganesh_test", - "precommit_args": [ - "--gerrit-issue=${patch_issue}", - "--gerrit-patchset=${patch_set}", - "--buildbucket-id=${buildbucket_build_id}" - ], - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "containment_type": "AUTO", - "dimensions": { - "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": 2 - }, - "test": "telemetry_gpu_integration_test", - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" - }, - { - "args": [ - "pixel", - "--show-stdout", - "--browser=release", - "--passthrough", - "-v", - "--stable-jobs", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=metal --enable-skia-graphite", "--enforce-browser-version", "--git-revision=${got_revision}", @@ -740,90 +456,6 @@ "--passthrough", "-v", "--stable-jobs", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=gl --disable-skia-graphite", - "--enforce-browser-version", - "--dont-restore-color-profile-after-test", - "--jobs=4" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "module_name": "//chrome/test:telemetry_gpu_integration_test", - "module_scheme": "flat", - "name": "screenshot_sync_gl_passthrough_ganesh_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "containment_type": "AUTO", - "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" - }, - "test": "telemetry_gpu_integration_test", - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" - }, - { - "args": [ - "screenshot_sync", - "--show-stdout", - "--browser=release", - "--passthrough", - "-v", - "--stable-jobs", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=metal --disable-skia-graphite", - "--enforce-browser-version", - "--dont-restore-color-profile-after-test", - "--jobs=4" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "module_name": "//chrome/test:telemetry_gpu_integration_test", - "module_scheme": "flat", - "name": "screenshot_sync_metal_passthrough_ganesh_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "containment_type": "AUTO", - "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" - }, - "test": "telemetry_gpu_integration_test", - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" - }, - { - "args": [ - "screenshot_sync", - "--show-stdout", - "--browser=release", - "--passthrough", - "-v", - "--stable-jobs", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=metal --enable-skia-graphite", "--enforce-browser-version", "--dont-restore-color-profile-after-test", @@ -908,88 +540,6 @@ "--passthrough", "-v", "--stable-jobs", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=gl --disable-skia-graphite", - "--enforce-browser-version", - "--jobs=4" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "module_name": "//chrome/test:telemetry_gpu_integration_test", - "module_scheme": "flat", - "name": "webcodecs_gl_passthrough_ganesh_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "containment_type": "AUTO", - "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" - }, - "test": "telemetry_gpu_integration_test", - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" - }, - { - "args": [ - "webcodecs", - "--show-stdout", - "--browser=release", - "--passthrough", - "-v", - "--stable-jobs", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=metal --disable-skia-graphite", - "--enforce-browser-version", - "--jobs=4" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "module_name": "//chrome/test:telemetry_gpu_integration_test", - "module_scheme": "flat", - "name": "webcodecs_metal_passthrough_ganesh_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "containment_type": "AUTO", - "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" - }, - "test": "telemetry_gpu_integration_test", - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" - }, - { - "args": [ - "webcodecs", - "--show-stdout", - "--browser=release", - "--passthrough", - "-v", - "--stable-jobs", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=metal --enable-skia-graphite", "--enforce-browser-version", "--jobs=4" @@ -1031,50 +581,6 @@ "--passthrough", "-v", "--stable-jobs", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=gl --disable-skia-graphite --force_high_performance_gpu", - "--enforce-browser-version", - "--webgl-conformance-version=2.0.1", - "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl2_conformance_mac_runtimes.json", - "--jobs=4" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "module_name": "//chrome/test:telemetry_gpu_integration_test", - "module_scheme": "flat", - "name": "webgl2_conformance_gl_passthrough_ganesh_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "containment_type": "AUTO", - "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": 20 - }, - "test": "telemetry_gpu_integration_test", - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" - }, - { - "args": [ - "webgl2_conformance", - "--show-stdout", - "--browser=release", - "--passthrough", - "-v", - "--stable-jobs", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=metal --enable-skia-graphite --enable-features=EGLDualGPURendering,ForceHighPerformanceGPUForWebGL --disable-metal-shader-cache", "--enforce-browser-version", "--enable-metal-debug-layers", @@ -1120,92 +626,6 @@ "--passthrough", "-v", "--stable-jobs", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=gl --disable-skia-graphite --force_high_performance_gpu", - "--enforce-browser-version", - "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl1_conformance_mac_runtimes.json", - "--jobs=4" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "module_name": "//chrome/test:telemetry_gpu_integration_test", - "module_scheme": "flat", - "name": "webgl_conformance_gl_passthrough_ganesh_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "containment_type": "AUTO", - "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": 2 - }, - "test": "telemetry_gpu_integration_test", - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" - }, - { - "args": [ - "webgl1_conformance", - "--show-stdout", - "--browser=release", - "--passthrough", - "-v", - "--stable-jobs", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=metal --disable-skia-graphite --enable-features=EGLDualGPURendering,ForceHighPerformanceGPUForWebGL", - "--enforce-browser-version", - "--enable-metal-debug-layers", - "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl1_conformance_mac_runtimes.json", - "--jobs=4" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "module_name": "//chrome/test:telemetry_gpu_integration_test", - "module_scheme": "flat", - "name": "webgl_conformance_metal_passthrough_ganesh_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "containment_type": "AUTO", - "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" - }, - "test": "telemetry_gpu_integration_test", - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" - }, - { - "args": [ - "webgl1_conformance", - "--show-stdout", - "--browser=release", - "--passthrough", - "-v", - "--stable-jobs", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=metal --enable-skia-graphite --enable-features=EGLDualGPURendering,ForceHighPerformanceGPUForWebGL --disable-metal-shader-cache", "--enforce-browser-version", "--enable-metal-debug-layers", @@ -1291,88 +711,6 @@ "--passthrough", "-v", "--stable-jobs", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=gl --disable-skia-graphite", - "--enforce-browser-version", - "--jobs=4" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "module_name": "//chrome/test:telemetry_gpu_integration_test", - "module_scheme": "flat", - "name": "webrtc_gl_passthrough_ganesh_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "containment_type": "AUTO", - "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" - }, - "test": "telemetry_gpu_integration_test", - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" - }, - { - "args": [ - "webrtc", - "--show-stdout", - "--browser=release", - "--passthrough", - "-v", - "--stable-jobs", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=metal --disable-skia-graphite", - "--enforce-browser-version", - "--jobs=4" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "module_name": "//chrome/test:telemetry_gpu_integration_test", - "module_scheme": "flat", - "name": "webrtc_metal_passthrough_ganesh_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "containment_type": "AUTO", - "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" - }, - "test": "telemetry_gpu_integration_test", - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" - }, - { - "args": [ - "webrtc", - "--show-stdout", - "--browser=release", - "--passthrough", - "-v", - "--stable-jobs", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=metal --enable-skia-graphite", "--enforce-browser-version", "--jobs=4"
diff --git a/infra/config/generated/builders/try/gpu-fyi-try-mac-arm64-apple-m2-asan/targets/chromium.gpu.fyi.json b/infra/config/generated/builders/try/gpu-fyi-try-mac-arm64-apple-m2-asan/targets/chromium.gpu.fyi.json index 852816a1..6b8115f 100644 --- a/infra/config/generated/builders/try/gpu-fyi-try-mac-arm64-apple-m2-asan/targets/chromium.gpu.fyi.json +++ b/infra/config/generated/builders/try/gpu-fyi-try-mac-arm64-apple-m2-asan/targets/chromium.gpu.fyi.json
@@ -188,88 +188,6 @@ "--passthrough", "-v", "--stable-jobs", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=gl --disable-skia-graphite", - "--enforce-browser-version", - "--jobs=4" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "module_name": "//chrome/test:telemetry_gpu_integration_test", - "module_scheme": "flat", - "name": "context_lost_gl_passthrough_ganesh_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "containment_type": "AUTO", - "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" - }, - "test": "telemetry_gpu_integration_test", - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" - }, - { - "args": [ - "context_lost", - "--show-stdout", - "--browser=release", - "--passthrough", - "-v", - "--stable-jobs", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=metal --disable-skia-graphite", - "--enforce-browser-version", - "--jobs=4" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "module_name": "//chrome/test:telemetry_gpu_integration_test", - "module_scheme": "flat", - "name": "context_lost_metal_passthrough_ganesh_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "containment_type": "AUTO", - "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" - }, - "test": "telemetry_gpu_integration_test", - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" - }, - { - "args": [ - "context_lost", - "--show-stdout", - "--browser=release", - "--passthrough", - "-v", - "--stable-jobs", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=metal --enable-skia-graphite", "--enforce-browser-version", "--jobs=4" @@ -311,106 +229,6 @@ "--passthrough", "-v", "--stable-jobs", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=gl --disable-skia-graphite", - "--enforce-browser-version", - "--git-revision=${got_revision}", - "--dont-restore-color-profile-after-test", - "--test-machine-name", - "${buildername}", - "--jobs=4" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "module_name": "//chrome/test:telemetry_gpu_integration_test", - "module_scheme": "flat", - "name": "expected_color_pixel_gl_passthrough_ganesh_test", - "precommit_args": [ - "--gerrit-issue=${patch_issue}", - "--gerrit-patchset=${patch_set}", - "--buildbucket-id=${buildbucket_build_id}" - ], - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "containment_type": "AUTO", - "dimensions": { - "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" - }, - "test": "telemetry_gpu_integration_test", - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" - }, - { - "args": [ - "expected_color", - "--show-stdout", - "--browser=release", - "--passthrough", - "-v", - "--stable-jobs", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=metal --disable-skia-graphite", - "--enforce-browser-version", - "--git-revision=${got_revision}", - "--dont-restore-color-profile-after-test", - "--test-machine-name", - "${buildername}", - "--jobs=4" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "module_name": "//chrome/test:telemetry_gpu_integration_test", - "module_scheme": "flat", - "name": "expected_color_pixel_metal_passthrough_ganesh_test", - "precommit_args": [ - "--gerrit-issue=${patch_issue}", - "--gerrit-patchset=${patch_set}", - "--buildbucket-id=${buildbucket_build_id}" - ], - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "containment_type": "AUTO", - "dimensions": { - "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" - }, - "test": "telemetry_gpu_integration_test", - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" - }, - { - "args": [ - "expected_color", - "--show-stdout", - "--browser=release", - "--passthrough", - "-v", - "--stable-jobs", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=metal --enable-skia-graphite", "--enforce-browser-version", "--git-revision=${got_revision}", @@ -588,108 +406,6 @@ "--passthrough", "-v", "--stable-jobs", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=gl --disable-skia-graphite", - "--enforce-browser-version", - "--git-revision=${got_revision}", - "--dont-restore-color-profile-after-test", - "--test-machine-name", - "${buildername}", - "--jobs=4" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "module_name": "//chrome/test:telemetry_gpu_integration_test", - "module_scheme": "flat", - "name": "pixel_skia_gold_gl_passthrough_ganesh_test", - "precommit_args": [ - "--gerrit-issue=${patch_issue}", - "--gerrit-patchset=${patch_set}", - "--buildbucket-id=${buildbucket_build_id}" - ], - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "containment_type": "AUTO", - "dimensions": { - "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": 2 - }, - "test": "telemetry_gpu_integration_test", - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" - }, - { - "args": [ - "pixel", - "--show-stdout", - "--browser=release", - "--passthrough", - "-v", - "--stable-jobs", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=metal --disable-skia-graphite", - "--enforce-browser-version", - "--git-revision=${got_revision}", - "--dont-restore-color-profile-after-test", - "--test-machine-name", - "${buildername}", - "--jobs=4" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "module_name": "//chrome/test:telemetry_gpu_integration_test", - "module_scheme": "flat", - "name": "pixel_skia_gold_metal_passthrough_ganesh_test", - "precommit_args": [ - "--gerrit-issue=${patch_issue}", - "--gerrit-patchset=${patch_set}", - "--buildbucket-id=${buildbucket_build_id}" - ], - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "containment_type": "AUTO", - "dimensions": { - "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": 2 - }, - "test": "telemetry_gpu_integration_test", - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" - }, - { - "args": [ - "pixel", - "--show-stdout", - "--browser=release", - "--passthrough", - "-v", - "--stable-jobs", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=metal --enable-skia-graphite", "--enforce-browser-version", "--git-revision=${got_revision}", @@ -741,90 +457,6 @@ "--passthrough", "-v", "--stable-jobs", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=gl --disable-skia-graphite", - "--enforce-browser-version", - "--dont-restore-color-profile-after-test", - "--jobs=4" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "module_name": "//chrome/test:telemetry_gpu_integration_test", - "module_scheme": "flat", - "name": "screenshot_sync_gl_passthrough_ganesh_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "containment_type": "AUTO", - "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" - }, - "test": "telemetry_gpu_integration_test", - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" - }, - { - "args": [ - "screenshot_sync", - "--show-stdout", - "--browser=release", - "--passthrough", - "-v", - "--stable-jobs", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=metal --disable-skia-graphite", - "--enforce-browser-version", - "--dont-restore-color-profile-after-test", - "--jobs=4" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "module_name": "//chrome/test:telemetry_gpu_integration_test", - "module_scheme": "flat", - "name": "screenshot_sync_metal_passthrough_ganesh_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "containment_type": "AUTO", - "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" - }, - "test": "telemetry_gpu_integration_test", - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" - }, - { - "args": [ - "screenshot_sync", - "--show-stdout", - "--browser=release", - "--passthrough", - "-v", - "--stable-jobs", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=metal --enable-skia-graphite", "--enforce-browser-version", "--dont-restore-color-profile-after-test", @@ -909,88 +541,6 @@ "--passthrough", "-v", "--stable-jobs", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=gl --disable-skia-graphite", - "--enforce-browser-version", - "--jobs=4" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "module_name": "//chrome/test:telemetry_gpu_integration_test", - "module_scheme": "flat", - "name": "webcodecs_gl_passthrough_ganesh_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "containment_type": "AUTO", - "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" - }, - "test": "telemetry_gpu_integration_test", - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" - }, - { - "args": [ - "webcodecs", - "--show-stdout", - "--browser=release", - "--passthrough", - "-v", - "--stable-jobs", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=metal --disable-skia-graphite", - "--enforce-browser-version", - "--jobs=4" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "module_name": "//chrome/test:telemetry_gpu_integration_test", - "module_scheme": "flat", - "name": "webcodecs_metal_passthrough_ganesh_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "containment_type": "AUTO", - "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" - }, - "test": "telemetry_gpu_integration_test", - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" - }, - { - "args": [ - "webcodecs", - "--show-stdout", - "--browser=release", - "--passthrough", - "-v", - "--stable-jobs", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=metal --enable-skia-graphite", "--enforce-browser-version", "--jobs=4" @@ -1032,50 +582,6 @@ "--passthrough", "-v", "--stable-jobs", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=gl --disable-skia-graphite --force_high_performance_gpu", - "--enforce-browser-version", - "--webgl-conformance-version=2.0.1", - "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl2_conformance_mac_runtimes.json", - "--jobs=4" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "module_name": "//chrome/test:telemetry_gpu_integration_test", - "module_scheme": "flat", - "name": "webgl2_conformance_gl_passthrough_ganesh_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "containment_type": "AUTO", - "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": 20 - }, - "test": "telemetry_gpu_integration_test", - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" - }, - { - "args": [ - "webgl2_conformance", - "--show-stdout", - "--browser=release", - "--passthrough", - "-v", - "--stable-jobs", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=metal --enable-skia-graphite --enable-features=EGLDualGPURendering,ForceHighPerformanceGPUForWebGL --disable-metal-shader-cache", "--enforce-browser-version", "--enable-metal-debug-layers", @@ -1121,92 +627,6 @@ "--passthrough", "-v", "--stable-jobs", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=gl --disable-skia-graphite --force_high_performance_gpu", - "--enforce-browser-version", - "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl1_conformance_mac_runtimes.json", - "--jobs=4" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "module_name": "//chrome/test:telemetry_gpu_integration_test", - "module_scheme": "flat", - "name": "webgl_conformance_gl_passthrough_ganesh_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "containment_type": "AUTO", - "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": 2 - }, - "test": "telemetry_gpu_integration_test", - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" - }, - { - "args": [ - "webgl1_conformance", - "--show-stdout", - "--browser=release", - "--passthrough", - "-v", - "--stable-jobs", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=metal --disable-skia-graphite --enable-features=EGLDualGPURendering,ForceHighPerformanceGPUForWebGL", - "--enforce-browser-version", - "--enable-metal-debug-layers", - "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl1_conformance_mac_runtimes.json", - "--jobs=4" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "module_name": "//chrome/test:telemetry_gpu_integration_test", - "module_scheme": "flat", - "name": "webgl_conformance_metal_passthrough_ganesh_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "containment_type": "AUTO", - "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" - }, - "test": "telemetry_gpu_integration_test", - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" - }, - { - "args": [ - "webgl1_conformance", - "--show-stdout", - "--browser=release", - "--passthrough", - "-v", - "--stable-jobs", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=metal --enable-skia-graphite --enable-features=EGLDualGPURendering,ForceHighPerformanceGPUForWebGL --disable-metal-shader-cache", "--enforce-browser-version", "--enable-metal-debug-layers", @@ -1292,88 +712,6 @@ "--passthrough", "-v", "--stable-jobs", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=gl --disable-skia-graphite", - "--enforce-browser-version", - "--jobs=4" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "module_name": "//chrome/test:telemetry_gpu_integration_test", - "module_scheme": "flat", - "name": "webrtc_gl_passthrough_ganesh_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "containment_type": "AUTO", - "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" - }, - "test": "telemetry_gpu_integration_test", - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" - }, - { - "args": [ - "webrtc", - "--show-stdout", - "--browser=release", - "--passthrough", - "-v", - "--stable-jobs", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=metal --disable-skia-graphite", - "--enforce-browser-version", - "--jobs=4" - ], - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "module_name": "//chrome/test:telemetry_gpu_integration_test", - "module_scheme": "flat", - "name": "webrtc_metal_passthrough_ganesh_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "containment_type": "AUTO", - "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" - }, - "test": "telemetry_gpu_integration_test", - "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/" - }, - { - "args": [ - "webrtc", - "--show-stdout", - "--browser=release", - "--passthrough", - "-v", - "--stable-jobs", "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle --use-angle=metal --enable-skia-graphite", "--enforce-browser-version", "--jobs=4"
diff --git a/infra/config/subprojects/chromium/ci/chromium.gpu.fyi.star b/infra/config/subprojects/chromium/ci/chromium.gpu.fyi.star index 7a5de6a..7e15bf68 100644 --- a/infra/config/subprojects/chromium/ci/chromium.gpu.fyi.star +++ b/infra/config/subprojects/chromium/ci/chromium.gpu.fyi.star
@@ -2372,26 +2372,12 @@ targets = targets.bundle( targets = [ "gpu_fyi_mac_release_gtests", - "gpu_fyi_only_mac_release_telemetry_tests", + "gpu_fyi_only_mac_release_graphite_telemetry_tests", ], mixins = [ "mac_arm64_apple_m2_retina_gpu_stable", ], per_test_modifications = { - "pixel_skia_gold_gl_passthrough_ganesh_test": targets.per_test_modification( - mixins = targets.mixin( - swarming = targets.swarming( - shards = 2, - ), - ), - ), - "pixel_skia_gold_metal_passthrough_ganesh_test": targets.per_test_modification( - mixins = targets.mixin( - swarming = targets.swarming( - shards = 2, - ), - ), - ), "pixel_skia_gold_metal_passthrough_graphite_test": targets.per_test_modification( mixins = targets.mixin( swarming = targets.swarming(
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd index 1bfbdbc..9d56d48 100644 --- a/ios/chrome/app/strings/ios_strings.grd +++ b/ios/chrome/app/strings/ios_strings.grd
@@ -3312,6 +3312,9 @@ <message name="IDS_IOS_GEMINI_IMAGE_REMIX_TOOL_IPH" desc="Main text in the in-product help tooltip suggesting to users that they can upload an image to remix with Nano Banana."> Upload an image to remix with Nano Banana </message> + <message name="IDS_IOS_GEMINI_LIVE_SHARING_LABEL" desc="Label describing the current page context shown in Gemini Live mode, indicating that the current page is being shared. [iOS only]"> + Sharing <ph name="PAGE_TITLE">$1<ex>Example Page</ex></ph> + </message> <message name="IDS_IOS_GEMINI_PERMISSION_CAMERA_DISABLED_PROMPT_BODY" desc="Text body of the Gemini-specific camera permission prompt when camera is already disabled."> To let Gemini use your camera, turn on Camera in iOS settings </message>
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_GEMINI_LIVE_SHARING_LABEL.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_GEMINI_LIVE_SHARING_LABEL.png.sha1 new file mode 100644 index 0000000..a7481238 --- /dev/null +++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_GEMINI_LIVE_SHARING_LABEL.png.sha1
@@ -0,0 +1 @@ +6d1d9ea73bef1ae7bdb778f81e2569e7b16958a4 \ No newline at end of file
diff --git a/ios/chrome/browser/collaboration/model/ios_collaboration_controller_delegate.h b/ios/chrome/browser/collaboration/model/ios_collaboration_controller_delegate.h index 5007beb7..c798ae6 100644 --- a/ios/chrome/browser/collaboration/model/ios_collaboration_controller_delegate.h +++ b/ios/chrome/browser/collaboration/model/ios_collaboration_controller_delegate.h
@@ -190,13 +190,13 @@ // Configures the shareKit config for the share flow and starts the flow. void ConfigureAndShareTabGroup(const tab_groups::EitherGroupID& either_id, ResultWithGroupTokenCallback result, - const TabGroup* tab_group, + base::WeakPtr<const TabGroup> tab_group, UIImage* faviconsGridImage); // Configures the shareKit config for the manage flow and starts the flow. void ConfigureAndManageTabGroup(const tab_groups::EitherGroupID& either_id, ResultCallback result, - const TabGroup* tab_group, + base::WeakPtr<const TabGroup> tab_group, UIImage* faviconsGridImage); // Returns the join group image displayed in the join flow.
diff --git a/ios/chrome/browser/collaboration/model/ios_collaboration_controller_delegate.mm b/ios/chrome/browser/collaboration/model/ios_collaboration_controller_delegate.mm index 8ae4021..6895b2fa 100644 --- a/ios/chrome/browser/collaboration/model/ios_collaboration_controller_delegate.mm +++ b/ios/chrome/browser/collaboration/model/ios_collaboration_controller_delegate.mm
@@ -385,7 +385,8 @@ auto callback = base::BindOnce( &IOSCollaborationControllerDelegate::ConfigureAndShareTabGroup, - weak_ptr_factory_.GetWeakPtr(), either_id, std::move(result), tab_group); + weak_ptr_factory_.GetWeakPtr(), either_id, std::move(result), + tab_group->GetWeakPtr()); favicons_grid_configurator_->FetchFaviconsGrid(tab_group, std::move(callback)); @@ -419,7 +420,8 @@ auto callback = base::BindOnce( &IOSCollaborationControllerDelegate::ConfigureAndManageTabGroup, - weak_ptr_factory_.GetWeakPtr(), either_id, std::move(result), tab_group); + weak_ptr_factory_.GetWeakPtr(), either_id, std::move(result), + tab_group->GetWeakPtr()); favicons_grid_configurator_->FetchFaviconsGrid(tab_group, std::move(callback)); @@ -785,7 +787,7 @@ void IOSCollaborationControllerDelegate::ConfigureAndShareTabGroup( const tab_groups::EitherGroupID& either_id, ResultWithGroupTokenCallback result, - const TabGroup* tab_group, + base::WeakPtr<const TabGroup> tab_group, UIImage* faviconsGridImage) { if (!tab_group || !faviconsGridImage) { std::move(result).Run(CollaborationControllerDelegate::Outcome::kFailure, @@ -817,7 +819,7 @@ void IOSCollaborationControllerDelegate::ConfigureAndManageTabGroup( const tab_groups::EitherGroupID& either_id, ResultCallback result, - const TabGroup* tab_group, + base::WeakPtr<const TabGroup> tab_group, UIImage* faviconsGridImage) { if (!tab_group || !faviconsGridImage) { std::move(result).Run(CollaborationControllerDelegate::Outcome::kFailure);
diff --git a/ios/chrome/browser/intelligence/bwg/coordinator/gemini_entry_flow_coordinator.mm b/ios/chrome/browser/intelligence/bwg/coordinator/gemini_entry_flow_coordinator.mm index 74aabb4..5c71e44 100644 --- a/ios/chrome/browser/intelligence/bwg/coordinator/gemini_entry_flow_coordinator.mm +++ b/ios/chrome/browser/intelligence/bwg/coordinator/gemini_entry_flow_coordinator.mm
@@ -9,19 +9,30 @@ #import "ios/chrome/browser/authentication/ui_bundled/continuation.h" #import "ios/chrome/browser/authentication/ui_bundled/signin/signin_coordinator.h" #import "ios/chrome/browser/intelligence/bwg/metrics/gemini_metrics.h" +#import "ios/chrome/browser/intelligence/bwg/model/gemini_browser_agent.h" #import "ios/chrome/browser/intelligence/bwg/model/gemini_service.h" #import "ios/chrome/browser/intelligence/bwg/model/gemini_service_factory.h" +#import "ios/chrome/browser/intelligence/bwg/model/gemini_tab_helper.h" +#import "ios/chrome/browser/intelligence/bwg/utils/gemini_constants.h" #import "ios/chrome/browser/shared/model/browser/browser.h" #import "ios/chrome/browser/shared/model/profile/profile_ios.h" +#import "ios/chrome/browser/shared/model/web_state_list/web_state_list.h" #import "ios/chrome/browser/shared/public/commands/command_dispatcher.h" #import "ios/chrome/browser/shared/public/commands/snackbar_commands.h" #import "ios/chrome/browser/shared/public/snackbar/snackbar_message.h" #import "ios/chrome/browser/signin/model/authentication_service.h" #import "ios/chrome/browser/signin/model/authentication_service_factory.h" #import "ios/chrome/grit/ios_strings.h" +#import "ios/web/public/web_state.h" #import "ui/base/l10n/l10n_util.h" #import "url/gurl.h" +// The type of ineligibility snackbar to show. +typedef NS_ENUM(NSInteger, IneligibilitySnackbarType) { + kIneligibilitySnackbarTypeAccount, + kIneligibilitySnackbarTypePage, +}; + @implementation GeminiEntryFlowCoordinator { // The sign-in coordinator presented when the user is signed out. SigninCoordinator* _signinCoordinator; @@ -90,8 +101,7 @@ GeminiService* geminiService = GeminiServiceFactory::GetForProfile(self.browser->GetProfile()); if (geminiService && geminiService->IsProfileEligibleForGemini()) { - // TODO(crbug.com/507509815): Page eligibility check. - [self finishWithResult:kGeminiEntryFlowResultSuccess]; + [self startGeminiIfPageEligible]; return; } @@ -167,13 +177,12 @@ // Eligible — check page availability. if (!result.has_value()) { - // TODO(crbug.com/507509815): Page eligibility check. - [self finishWithResult:kGeminiEntryFlowResultSuccess]; + [self startGeminiIfPageEligible]; return; } // Ineligible — show snackbar if enabled. - [self showIneligibleSnackbarIfNeeded]; + [self showSnackbarForIneligibilityType:kIneligibilitySnackbarTypeAccount]; // Enterprise policy restriction. if (result.value().chrome_enterprise) { @@ -192,19 +201,6 @@ [self finishWithResult:kGeminiEntryFlowResultUnknown]; } -// Shows the ineligible account snackbar if showSnackbarOnCompletion is YES. -- (void)showIneligibleSnackbarIfNeeded { - if (!_showSnackbarOnCompletion) { - return; - } - id<SnackbarCommands> snackbarHandler = HandlerForProtocol( - self.browser->GetCommandDispatcher(), SnackbarCommands); - SnackbarMessage* message = [[SnackbarMessage alloc] - initWithTitle:l10n_util::GetNSString( - IDS_IOS_AI_HUB_INELIGIBLE_ACCOUNT_SNACKBAR)]; - [snackbarHandler showSnackbarMessage:message]; -} - // Presents the account menu for switching to a different account. - (void)presentAccountMenu { _accountMenuCoordinator = [[AccountMenuCoordinator alloc] @@ -223,4 +219,59 @@ _accountMenuCoordinator = nil; } +// Starts the Gemini session if the current page is eligible. +- (void)startGeminiIfPageEligible { + web::WebState* activeWebState = + self.browser->GetWebStateList()->GetActiveWebState(); + + // TODO(crbug.com/503013746): Support invoking from the tab grid where + // there is no active web state. + if (!activeWebState) { + [self showSnackbarForIneligibilityType:kIneligibilitySnackbarTypePage]; + [self finishWithResult:kGeminiEntryFlowResultPageIneligible]; + return; + } + + GeminiTabHelper* tabHelper = GeminiTabHelper::FromWebState(activeWebState); + if (!tabHelper || !tabHelper->IsGeminiAvailableForWebState()) { + [self showSnackbarForIneligibilityType:kIneligibilitySnackbarTypePage]; + [self finishWithResult:kGeminiEntryFlowResultPageIneligible]; + return; + } + + // All checks passed — start the Gemini session. + [self startGeminiSession]; + [self finishWithResult:kGeminiEntryFlowResultSuccess]; +} + +// Starts the Gemini session via the GeminiBrowserAgent. +- (void)startGeminiSession { + GeminiBrowserAgent* geminiBrowserAgent = + GeminiBrowserAgent::FromBrowser(self.browser); + if (geminiBrowserAgent) { + geminiBrowserAgent->StartGeminiFlow(self.baseViewController, _startupState); + } +} + +// Shows an ineligibility snackbar if showSnackbarOnCompletion is set. +- (void)showSnackbarForIneligibilityType:(IneligibilitySnackbarType)type { + if (!_showSnackbarOnCompletion) { + return; + } + int messageID; + switch (type) { + case kIneligibilitySnackbarTypeAccount: + messageID = IDS_IOS_AI_HUB_INELIGIBLE_ACCOUNT_SNACKBAR; + break; + case kIneligibilitySnackbarTypePage: + messageID = IDS_IOS_AI_HUB_PAGE_INELIGIBLE_SNACKBAR; + break; + } + id<SnackbarCommands> snackbarHandler = HandlerForProtocol( + self.browser->GetCommandDispatcher(), SnackbarCommands); + SnackbarMessage* message = + [[SnackbarMessage alloc] initWithTitle:l10n_util::GetNSString(messageID)]; + [snackbarHandler showSnackbarMessage:message]; +} + @end
diff --git a/ios/chrome/browser/intelligence/bwg/metrics/BUILD.gn b/ios/chrome/browser/intelligence/bwg/metrics/BUILD.gn index 98f9b287..6a1d5e595b 100644 --- a/ios/chrome/browser/intelligence/bwg/metrics/BUILD.gn +++ b/ios/chrome/browser/intelligence/bwg/metrics/BUILD.gn
@@ -9,6 +9,7 @@ ] deps = [ "//base", + "//components/optimization_guide/core", "//ios/chrome/browser/intelligence/bwg/utils:constants", "//ios/public/provider/chrome/browser/bwg:bwg_api", ] @@ -20,6 +21,7 @@ deps = [ ":metrics", "//base/test:test_support", + "//components/optimization_guide/core", "//ios/chrome/browser/intelligence/bwg/utils:constants", ] }
diff --git a/ios/chrome/browser/intelligence/bwg/metrics/gemini_metrics.h b/ios/chrome/browser/intelligence/bwg/metrics/gemini_metrics.h index 68454cd..70d0eb937 100644 --- a/ios/chrome/browser/intelligence/bwg/metrics/gemini_metrics.h +++ b/ios/chrome/browser/intelligence/bwg/metrics/gemini_metrics.h
@@ -14,6 +14,10 @@ class TimeTicks; } // namespace base +namespace optimization_guide { +enum class OptimizationGuideDecision; +} // namespace optimization_guide + namespace gemini { enum class EntryPoint; enum class FloatyUpdateSource; @@ -250,6 +254,9 @@ // UMA histogram key for IOS.Gemini.EditMenuPrompt.SelectedText.Length. extern const char kEditMenuSelectedTextLengthHistogram[]; +// UMA histogram key for IOS.Gemini.GlicContextualCue.Decision. +extern const char kGlicContextualCueDecisionHistogram[]; + // Represents the completed Gemini session types. enum class IOSGeminiSessionType { kUnknown = 0, @@ -574,4 +581,8 @@ // Records the length of the selected text in the edit menu. void RecordGeminiEditMenuSelectedTextLength(int length); +// Records the glic contextual cue decision for Gemini. +void RecordGeminiGlicContextualCueDecision( + optimization_guide::OptimizationGuideDecision decision); + #endif // IOS_CHROME_BROWSER_INTELLIGENCE_BWG_METRICS_GEMINI_METRICS_H_
diff --git a/ios/chrome/browser/intelligence/bwg/metrics/gemini_metrics.mm b/ios/chrome/browser/intelligence/bwg/metrics/gemini_metrics.mm index 61cdb09..cb21323 100644 --- a/ios/chrome/browser/intelligence/bwg/metrics/gemini_metrics.mm +++ b/ios/chrome/browser/intelligence/bwg/metrics/gemini_metrics.mm
@@ -8,6 +8,7 @@ #import "base/metrics/user_metrics.h" #import "base/metrics/user_metrics_action.h" #import "base/time/time.h" +#import "components/optimization_guide/core/hints/optimization_guide_decision.h" #import "ios/chrome/browser/intelligence/bwg/utils/gemini_constants.h" #import "ios/public/provider/chrome/browser/bwg/bwg_api.h" @@ -202,6 +203,9 @@ const char kEditMenuSelectedTextLengthHistogram[] = "IOS.Gemini.EditMenuPrompt.SelectedText.Length"; +const char kGlicContextualCueDecisionHistogram[] = + "IOS.Gemini.GlicContextualCue.Decision"; + void RecordFREPromoAction(IOSGeminiFREAction action) { switch (action) { case IOSGeminiFREAction::kAccept: @@ -651,3 +655,8 @@ void RecordGeminiEditMenuSelectedTextLength(int length) { base::UmaHistogramCounts1000(kEditMenuSelectedTextLengthHistogram, length); } + +void RecordGeminiGlicContextualCueDecision( + optimization_guide::OptimizationGuideDecision decision) { + base::UmaHistogramEnumeration(kGlicContextualCueDecisionHistogram, decision); +}
diff --git a/ios/chrome/browser/intelligence/bwg/metrics/gemini_metrics_unittest.mm b/ios/chrome/browser/intelligence/bwg/metrics/gemini_metrics_unittest.mm index 2f932f3..fdf7f6c 100644 --- a/ios/chrome/browser/intelligence/bwg/metrics/gemini_metrics_unittest.mm +++ b/ios/chrome/browser/intelligence/bwg/metrics/gemini_metrics_unittest.mm
@@ -6,6 +6,7 @@ #import "base/test/metrics/histogram_tester.h" #import "base/test/metrics/user_action_tester.h" +#import "components/optimization_guide/core/hints/optimization_guide_decision.h" #import "ios/chrome/browser/intelligence/bwg/utils/gemini_constants.h" #import "testing/platform_test.h" @@ -411,3 +412,17 @@ IOSGeminiPageAvailability::kUnavailable, 1); } + +TEST_F(GeminiMetricsTest, RecordGeminiGlicContextualCueDecision) { + RecordGeminiGlicContextualCueDecision( + optimization_guide::OptimizationGuideDecision::kTrue); + histogram_tester_.ExpectBucketCount( + kGlicContextualCueDecisionHistogram, + optimization_guide::OptimizationGuideDecision::kTrue, 1); + + RecordGeminiGlicContextualCueDecision( + optimization_guide::OptimizationGuideDecision::kFalse); + histogram_tester_.ExpectBucketCount( + kGlicContextualCueDecisionHistogram, + optimization_guide::OptimizationGuideDecision::kFalse, 1); +}
diff --git a/ios/chrome/browser/intelligence/bwg/model/gemini_tab_helper.mm b/ios/chrome/browser/intelligence/bwg/model/gemini_tab_helper.mm index ca8d4bf5..c1f3272 100644 --- a/ios/chrome/browser/intelligence/bwg/model/gemini_tab_helper.mm +++ b/ios/chrome/browser/intelligence/bwg/model/gemini_tab_helper.mm
@@ -621,6 +621,10 @@ optimization_guide::OptimizationGuideDecision decision, const optimization_guide::OptimizationMetadata& metadata) { CHECK(IsAskGeminiChipEnabled()); + + // Record every decision before checking if the url changed. + RecordGeminiGlicContextualCueDecision(decision); + // The URL has changed so the metadata is obsolete. if (previous_main_frame_url_ != main_frame_url) { return;
diff --git a/ios/chrome/browser/share_kit/model/share_kit_manage_configuration.h b/ios/chrome/browser/share_kit/model/share_kit_manage_configuration.h index b115676..f455302 100644 --- a/ios/chrome/browser/share_kit/model/share_kit_manage_configuration.h +++ b/ios/chrome/browser/share_kit/model/share_kit_manage_configuration.h
@@ -7,6 +7,8 @@ #import <UIKit/UIKit.h> +#import "base/memory/weak_ptr.h" + @protocol SceneCommands; enum class ShareKitFlowOutcome; class TabGroup; @@ -23,7 +25,7 @@ @property(nonatomic, copy) NSString* collabID; // Local tab group. -@property(nonatomic, assign) const TabGroup* tabGroup; +@property(nonatomic, assign) base::WeakPtr<const TabGroup> tabGroup; // The group image preview. @property(nonatomic, copy) UIImage* groupImage;
diff --git a/ios/chrome/browser/share_kit/model/share_kit_share_group_configuration.h b/ios/chrome/browser/share_kit/model/share_kit_share_group_configuration.h index e7204ea..20dcf842 100644 --- a/ios/chrome/browser/share_kit/model/share_kit_share_group_configuration.h +++ b/ios/chrome/browser/share_kit/model/share_kit_share_group_configuration.h
@@ -7,6 +7,8 @@ #import <UIKit/UIKit.h> +#import "base/memory/weak_ptr.h" + @protocol SceneCommands; enum class ShareKitFlowOutcome; class TabGroup; @@ -18,7 +20,7 @@ @property(nonatomic, weak) UIViewController* baseViewController; // Local tab group. -@property(nonatomic, assign) const TabGroup* tabGroup; +@property(nonatomic, assign) base::WeakPtr<const TabGroup> tabGroup; // The group image preview. @property(nonatomic, copy) UIImage* groupImage;
diff --git a/ios/chrome/browser/share_kit/model/test_share_kit_service.mm b/ios/chrome/browser/share_kit/model/test_share_kit_service.mm index 3d40b8a..ad4a5dc 100644 --- a/ios/chrome/browser/share_kit/model/test_share_kit_service.mm +++ b/ios/chrome/browser/share_kit/model/test_share_kit_service.mm
@@ -141,7 +141,7 @@ NSString* TestShareKitService::ShareTabGroup( ShareKitShareGroupConfiguration* config) { - const TabGroup* tab_group = config.tabGroup; + const TabGroup* tab_group = config.tabGroup.get(); if (!tab_group) { return nil; }
diff --git a/ios/chrome/browser/shared/public/features/features.h b/ios/chrome/browser/shared/public/features/features.h index 4be595c..cf2b3f09 100644 --- a/ios/chrome/browser/shared/public/features/features.h +++ b/ios/chrome/browser/shared/public/features/features.h
@@ -46,7 +46,7 @@ // Feature flag to control Tab Grid setup mode. BASE_DECLARE_FEATURE(kTabGridSetupMode); -extern const base::FeatureParam<int> kTabGridSetupModeParam; +extern const base::FeatureParam<std::string> kTabGridSetupModeParam; extern const char kTabGridSetupModeParamName[]; TabGridSetupMode GetTabGridSetupMode();
diff --git a/ios/chrome/browser/shared/public/features/features.mm b/ios/chrome/browser/shared/public/features/features.mm index cac028f..75bda45 100644 --- a/ios/chrome/browser/shared/public/features/features.mm +++ b/ios/chrome/browser/shared/public/features/features.mm
@@ -35,18 +35,25 @@ BASE_FEATURE(kTabGridSetupMode, base::FEATURE_DISABLED_BY_DEFAULT); -const char kTabGridSetupModeParamName[] = "mode"; +const char kTabGridSetupModeParamName[] = "tab_grid_setup_mode"; -const base::FeatureParam<int> kTabGridSetupModeParam( +const base::FeatureParam<std::string> kTabGridSetupModeParam( &kTabGridSetupMode, kTabGridSetupModeParamName, - static_cast<int>(TabGridSetupMode::kImmediate)); + "immediate"); TabGridSetupMode GetTabGridSetupMode() { if (!base::FeatureList::IsEnabled(kTabGridSetupMode)) { return TabGridSetupMode::kImmediate; } - return static_cast<TabGridSetupMode>(kTabGridSetupModeParam.Get()); + std::string value = kTabGridSetupModeParam.Get(); + if (value == "deferred") { + return TabGridSetupMode::kDeferred; + } + if (value == "lazy_for_testing") { + return TabGridSetupMode::kLazy_ForTesting; + } + return TabGridSetupMode::kImmediate; } BASE_FEATURE(kOmahaServiceRefactor, base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_grid_egtest.mm b/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_grid_egtest.mm index dff529c..2fdbf40 100644 --- a/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_grid_egtest.mm +++ b/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_grid_egtest.mm
@@ -393,9 +393,7 @@ AppLaunchConfiguration config = [self appConfigurationForTestCase]; config.relaunch_policy = ForceRelaunchByCleanShutdown; config.features_enabled_and_params.push_back( - {kTabGridSetupMode, - {{kTabGridSetupModeParamName, base::NumberToString(static_cast<int>( - TabGridSetupMode::kDeferred))}}}); + {kTabGridSetupMode, {{kTabGridSetupModeParamName, "deferred"}}}); [[AppLaunchManager sharedManager] ensureAppLaunchedWithConfiguration:config]; // The web page should be visible. @@ -440,9 +438,7 @@ AppLaunchConfiguration config = [self appConfigurationForTestCase]; config.relaunch_policy = ForceRelaunchByCleanShutdown; config.features_enabled_and_params.push_back( - {kTabGridSetupMode, - {{kTabGridSetupModeParamName, base::NumberToString(static_cast<int>( - TabGridSetupMode::kDeferred))}}}); + {kTabGridSetupMode, {{kTabGridSetupModeParamName, "deferred"}}}); [[AppLaunchManager sharedManager] ensureAppLaunchedWithConfiguration:config]; // Wait until the deferred BestEffort task has executed and set up the child @@ -484,10 +480,7 @@ AppLaunchConfiguration config = [self appConfigurationForTestCase]; config.relaunch_policy = ForceRelaunchByCleanShutdown; config.features_enabled_and_params.push_back( - {kTabGridSetupMode, - {{kTabGridSetupModeParamName, - base::NumberToString( - static_cast<int>(TabGridSetupMode::kLazy_ForTesting))}}}); + {kTabGridSetupMode, {{kTabGridSetupModeParamName, "lazy_for_testing"}}}); [[AppLaunchManager sharedManager] ensureAppLaunchedWithConfiguration:config]; @@ -515,10 +508,7 @@ AppLaunchConfiguration config = [self appConfigurationForTestCase]; config.relaunch_policy = ForceRelaunchByCleanShutdown; config.features_enabled_and_params.push_back( - {kTabGridSetupMode, - {{kTabGridSetupModeParamName, - base::NumberToString( - static_cast<int>(TabGridSetupMode::kLazy_ForTesting))}}}); + {kTabGridSetupMode, {{kTabGridSetupModeParamName, "lazy_for_testing"}}}); [[AppLaunchManager sharedManager] ensureAppLaunchedWithConfiguration:config];
diff --git a/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1 index dd43ab9d..a19b8c6 100644 --- a/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1 +++ b/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@ -4e1e260ac0ccfa6b45e907c46d644c0f968affe1 \ No newline at end of file +b16d78990c3526640cb11d10bee61e3a8dc832d0 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios_asan.zip.sha1 b/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios_asan.zip.sha1 index caef89d..8802895 100644 --- a/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios_asan.zip.sha1
@@ -1 +1 @@ -89df83065092f97390dfd30d16f650af6a50a481 \ No newline at end of file +183eab080d33708a043dffffe221e2712287b431 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 index be95495..89b10e0 100644 --- a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 +++ b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@ -da2e4bfda9e74db5b72ca36d01256186d872b2db \ No newline at end of file +6473d7cc2a3a4792a6bc9ff2239096e30a8463fe \ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios_asan.zip.sha1 b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios_asan.zip.sha1 index 7a06bba7..5aca79fb1 100644 --- a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios_asan.zip.sha1
@@ -1 +1 @@ -1adce25435113fc618b4a283e8a9aa3c71fb3d45 \ No newline at end of file +3259669f3127b894aeadc17b670c3606f8c91066 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 index c2d4eb2..b2bde156 100644 --- a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 +++ b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@ -fc6a11d11489bebd979694fb5fd7781a1d7b40d2 \ No newline at end of file +f97e7e2c6d4011087c937c7f84b20607461599d8 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios_asan.zip.sha1 b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios_asan.zip.sha1 index 041b31a..4719981 100644 --- a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios_asan.zip.sha1
@@ -1 +1 @@ -c789a8b2b8497330fc9f24dad5f93fdd489d5704 \ No newline at end of file +db1e61ab50afa2c92be438d2724f375021b59f23 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1 index f3d0e36..c43688d 100644 --- a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -f2118629e672967a00257b41859c0fbd1d782838 \ No newline at end of file +249d3a800e195980d2443ba66873757010852571 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios_asan.zip.sha1 index 9762276..57a2387 100644 --- a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@ -4b7c52d245d153810bd2f14788cae4a9b2a7029e \ No newline at end of file +bafd49740e238184878e099d181d896cce7535cc \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1 index 53cb122ab..84efeef 100644 --- a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -4feda8d119f78f7bc0f9b1c6b244bb16fb929569 \ No newline at end of file +9bf7fa60ecfc9252a6a65e0e74f63070f175d208 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator_asan.zip.sha1 index 7484efd..df57045 100644 --- a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator_asan.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@ -c3e5b0b40e4046dae7178dd2d0b51ff2e2e3a629 \ No newline at end of file +1a592eb4bdb2bfde6db2a122ba281c50c35a36e3 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 index 971b4677..c6102cc 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -c6a884c072fdb4050c40d530981063a1c96a17f6 \ No newline at end of file +c8c64074f4ce84a5b667cfc0ad2496e7674842b0 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios_asan.zip.sha1 index 9dae556..bfa68886 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@ -db7d1e4ebd33f503ffd60f6b6be5da3a5df4a88e \ No newline at end of file +0ef9a7d36e49af5ffdb4b9ef0ddae0e512f91948 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 index 1c7e877..3d243be 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -55bab3c1c0ff320026fdfb60d7610b3ac1457e15 \ No newline at end of file +7b75cdfd27254814f9b114421336cd5610e268e2 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator_asan.zip.sha1 index 216c2b2..664e83e 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator_asan.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@ -fba81ac3a77091c5ce8e1c8212bded9adc1d5f3c \ No newline at end of file +1d2f953b55f00aa3cbd936367bf1d63444b60135 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 index e222fba..757fbf2 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -badf2cdda24bec5cb8a876838b305cbc28bc332a \ No newline at end of file +3c67fd84f70b0384d63f253d2ec8e922249368d8 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios_asan.zip.sha1 index c2fb3616..68923914 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@ -51e646dd7b168e778759cc4fca299f5e35d05f31 \ No newline at end of file +4bb82c3c2b781ec03461b97c10d33f738745d056 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 index 37322075b..ef726e3 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -a695987edfd340946c95ae1ca726e960e4906761 \ No newline at end of file +538f145444a5e8e14ff7118346d187ced57f2f1f \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator_asan.zip.sha1 index ec83dfa..7c765c1 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator_asan.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@ -6f27a21343ecc50376b7529de03fa1cbf4e748d8 \ No newline at end of file +e574e983ec859d0417ba15bed1201e431ee1c345 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 index e13c13b..1be56f8 100644 --- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -a62fd75a48c489f4e71827bfda47529d1449270d \ No newline at end of file +95448e8b1fefe5c36cb08c159e3de1a3f67dc359 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 index 70ebb9ec..26aa8f1f 100644 --- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -184b9b3496b2009d50344ae7928ff96547d3a02f \ No newline at end of file +17022da47e2843be01c428039da581a47902ccef \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 index 3ac43b3..78f20555 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -f6fad744959166b3631a4cdd33aab722647fdade \ No newline at end of file +2c9894cf9b8fec66687886df2ef62c8d748c74cf \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios_asan.zip.sha1 index 1b06c77..8333809 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios_asan.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@ -28b9ed11d710053426dd445106ba62babb964225 \ No newline at end of file +37c08f5813859a6d27d9dc40efad3d53c09cfd2b \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 index dae5c5fa..50bb31cb 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -51aa8aa4d395978dc4cb9674d3063261205eb855 \ No newline at end of file +495f4aa7b8cb49686c68d38e168e819ec983beed \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator_asan.zip.sha1 index b7cf2d51..f991ec3 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator_asan.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@ -9d858d94dd45100f293b093cce605212f350904e \ No newline at end of file +ec2ce638c0e58447b72d7bc8e526285d1a23132d \ No newline at end of file
diff --git a/ios/web/js_messaging/BUILD.gn b/ios/web/js_messaging/BUILD.gn index 48c9b21..19b10c3 100644 --- a/ios/web/js_messaging/BUILD.gn +++ b/ios/web/js_messaging/BUILD.gn
@@ -77,6 +77,7 @@ "java_script_feature.mm", "java_script_feature_manager.mm", "script_message.mm", + "script_message_dict_value_impl.mm", "script_message_value_impl.mm", ] } @@ -217,6 +218,7 @@ "java_script_feature_unittest.mm", "page_script_util_unittest.mm", "scoped_wk_script_message_handler_unittest.mm", + "script_message_dict_value_impl_unittest.mm", "script_message_value_impl_unittest.mm", "web_frame_impl_unittest.mm", "web_frames_manager_impl_unittest.mm",
diff --git a/ios/web/js_messaging/script_message_dict_value_impl.mm b/ios/web/js_messaging/script_message_dict_value_impl.mm new file mode 100644 index 0000000..75ea8a90 --- /dev/null +++ b/ios/web/js_messaging/script_message_dict_value_impl.mm
@@ -0,0 +1,104 @@ +// 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 "base/strings/sys_string_conversions.h" +#import "ios/web/js_messaging/web_view_js_utils.h" +#import "ios/web/public/js_messaging/script_message_dict_value.h" +#import "ios/web/public/js_messaging/script_message_value.h" + +namespace { + +// Returns the object associated with `key` in `dict` if the type of that +// object matches `expected_type`. Otherwise returns `nullptr`. +id GetDictElementAndMatchType(NSDictionary* dict, + std::string_view key, + CFTypeID expected_type) { + id element = [dict objectForKey:base::SysUTF8ToNSString(key)]; + if (!element || CFGetTypeID((__bridge CFTypeRef)element) != expected_type) { + return nullptr; + } + + return element; +} + +} // namespace + +namespace web { + +ScriptMessageDictValue::ScriptMessageDictValue(ScriptMessageDictValue&&) = + default; +ScriptMessageDictValue& ScriptMessageDictValue::operator=( + ScriptMessageDictValue&&) = default; + +ScriptMessageDictValue::ScriptMessageDictValue(NSDictionary* value) + : data_(value) {} + +ScriptMessageDictValue::~ScriptMessageDictValue() = default; + +bool ScriptMessageDictValue::empty() const { + return [data_ count] == 0; +} + +size_t ScriptMessageDictValue::size() const { + return [data_ count]; +} + +bool ScriptMessageDictValue::contains(std::string_view key) const { + return [data_ objectForKey:base::SysUTF8ToNSString(key)] != nil; +} + +std::unique_ptr<ScriptMessageValue> ScriptMessageDictValue::Find( + std::string_view key) { + id element = [data_ objectForKey:base::SysUTF8ToNSString(key)]; + if (element == nil) { + return nullptr; + } + return std::make_unique<ScriptMessageValue>(element); +} + +std::optional<bool> ScriptMessageDictValue::FindBool( + std::string_view key) const { + id element = GetDictElementAndMatchType(data_, key, CFBooleanGetTypeID()); + if (!element) { + return std::nullopt; + } + return [element boolValue]; +} + +std::optional<int> ScriptMessageDictValue::FindInt(std::string_view key) const { + id element = GetDictElementAndMatchType(data_, key, CFNumberGetTypeID()); + if (!element) { + return std::nullopt; + } + return [element intValue]; +} + +std::optional<double> ScriptMessageDictValue::FindDouble( + std::string_view key) const { + id element = GetDictElementAndMatchType(data_, key, CFNumberGetTypeID()); + if (!element) { + return std::nullopt; + } + return [element doubleValue]; +} + +std::optional<std::string> ScriptMessageDictValue::FindString( + std::string_view key) const { + id element = GetDictElementAndMatchType(data_, key, CFStringGetTypeID()); + if (!element) { + return std::nullopt; + } + return base::SysNSStringToUTF8(element); +} + +std::unique_ptr<ScriptMessageDictValue> ScriptMessageDictValue::FindDict( + std::string_view key) const { + id element = GetDictElementAndMatchType(data_, key, CFDictionaryGetTypeID()); + if (!element) { + return nullptr; + } + return std::make_unique<ScriptMessageDictValue>((NSDictionary*)element); +} + +} // namespace web
diff --git a/ios/web/js_messaging/script_message_dict_value_impl_unittest.mm b/ios/web/js_messaging/script_message_dict_value_impl_unittest.mm new file mode 100644 index 0000000..953d1a8 --- /dev/null +++ b/ios/web/js_messaging/script_message_dict_value_impl_unittest.mm
@@ -0,0 +1,121 @@ +// 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 <Foundation/Foundation.h> + +#import "base/values.h" +#import "ios/web/public/js_messaging/script_message_dict_value.h" +#import "ios/web/public/js_messaging/script_message_value.h" +#import "testing/platform_test.h" + +namespace { +// Creates a populated dict for use in tests. +NSDictionary* test_dict() { + return @{ + @"boolKey" : @YES, + @"intKey" : @42, + @"doubleKey" : @3.14, + @"stringKey" : @"hello", + }; +} +} // namespace + +namespace web { + +using ScriptMessageDictValueTest = PlatformTest; + +TEST_F(ScriptMessageDictValueTest, EmptyFunctionIsTrueWhenDictIsEmpty) { + NSDictionary* empty_ns_dict = @{}; + ScriptMessageDictValue empty_dict(empty_ns_dict); + EXPECT_TRUE(empty_dict.empty()); +} + +TEST_F(ScriptMessageDictValueTest, DictSizeIsZeroWhenDictIsEmpty) { + NSDictionary* empty_ns_dict = @{}; + ScriptMessageDictValue empty_dict(empty_ns_dict); + EXPECT_EQ(0u, empty_dict.size()); +} + +TEST_F(ScriptMessageDictValueTest, EmptyFunctionIsFalseWhenDictIsNonempty) { + ScriptMessageDictValue dict(test_dict()); + EXPECT_FALSE(dict.empty()); +} + +TEST_F(ScriptMessageDictValueTest, DictSizeIsNonzeroWhenDictIsNonempty) { + ScriptMessageDictValue dict(test_dict()); + EXPECT_EQ(4u, dict.size()); +} + +TEST_F(ScriptMessageDictValueTest, ContainsReturnsTrueWhenAPresentKeyIsGiven) { + ScriptMessageDictValue dict(test_dict()); + EXPECT_TRUE(dict.contains("boolKey")); +} + +TEST_F(ScriptMessageDictValueTest, + ContainsReturnsFalseWhenANonExistentKeyIsGiven) { + ScriptMessageDictValue dict(test_dict()); + EXPECT_FALSE(dict.contains("nonExistentKey")); +} + +TEST_F(ScriptMessageDictValueTest, FindFunctionsSuccessfullyReturnValue) { + ScriptMessageDictValue dict(test_dict()); + EXPECT_EQ(true, dict.FindBool("boolKey").value_or(false)); + EXPECT_EQ(42, dict.FindInt("intKey").value_or(0)); + EXPECT_EQ(3.14, dict.FindDouble("doubleKey").value_or(0.0)); + // Double getter should work for int as well + EXPECT_EQ(42.0, dict.FindDouble("intKey").value_or(0.0)); + EXPECT_EQ("hello", dict.FindString("stringKey").value_or("")); +} + +TEST_F(ScriptMessageDictValueTest, + FindFunctionsReturnEmptyOptionalForNonexistentKeys) { + ScriptMessageDictValue dict(test_dict()); + EXPECT_FALSE(dict.FindBool("missing").has_value()); + EXPECT_FALSE(dict.FindInt("missing").has_value()); + EXPECT_FALSE(dict.FindDouble("missing").has_value()); + EXPECT_FALSE(dict.FindString("missing").has_value()); +} + +// Tests extraction of nested collections (Dict). +// TODO(crbug.com/509501985): Add List support. +TEST_F(ScriptMessageDictValueTest, DictShouldSupportNestedDicts) { + NSDictionary* ns_dict = @{ + @"dictKey" : @{@"innerKey" : @"innerVal"}, + @"stringKey" : @"notACollection", + }; + ScriptMessageDictValue dict(ns_dict); + + std::unique_ptr<ScriptMessageDictValue> inner_dict = dict.FindDict("dictKey"); + ASSERT_TRUE(inner_dict); + EXPECT_EQ("innerVal", inner_dict->FindString("innerKey").value_or("")); +} + +// Tests generic base::Value conversion via Find(). +TEST_F(ScriptMessageDictValueTest, GenericFindShouldReturnBaseValue) { + NSDictionary* ns_dict = @{ + @"stringKey" : @"hello", + }; + ScriptMessageDictValue dict(ns_dict); + + const std::optional<std::string> val = dict.FindString("stringKey"); + ASSERT_TRUE(val); + EXPECT_EQ("hello", val.value()); +} + +// Tests move operations. +TEST_F(ScriptMessageDictValueTest, DictShouldSupportMoveOperations) { + NSDictionary* ns_dict = @{@"key" : @"value"}; + ScriptMessageDictValue original(ns_dict); + + // Move construction + ScriptMessageDictValue moved_constructed(std::move(original)); + EXPECT_EQ("value", moved_constructed.FindString("key").value_or("")); + + // Move assignment + ScriptMessageDictValue moved_assigned(nullptr); + moved_assigned = std::move(moved_constructed); + EXPECT_EQ("value", moved_assigned.FindString("key").value_or("")); +} + +} // namespace web
diff --git a/ios/web/js_messaging/script_message_value_impl.mm b/ios/web/js_messaging/script_message_value_impl.mm index fb30d85..2b02a03 100644 --- a/ios/web/js_messaging/script_message_value_impl.mm +++ b/ios/web/js_messaging/script_message_value_impl.mm
@@ -7,6 +7,7 @@ #import "base/notreached.h" #import "base/strings/sys_string_conversions.h" #import "ios/web/js_messaging/web_view_js_utils.h" +#import "ios/web/public/js_messaging/script_message_dict_value.h" #import "ios/web/public/js_messaging/script_message_value.h" namespace web { @@ -25,6 +26,10 @@ : data_(base::Value(value)) {} ScriptMessageValue::ScriptMessageValue(bool value) : data_(base::Value(value)) {} +ScriptMessageValue::ScriptMessageValue(ScriptMessageDictValue value) + : data_(std::move(value)) {} +ScriptMessageValue::ScriptMessageValue(NSDictionary* value) + : data_(ScriptMessageDictValue(value)) {} ScriptMessageValue::~ScriptMessageValue() = default; @@ -35,6 +40,8 @@ if (std::holds_alternative<base::Value>(data_)) { return std::get<base::Value>(data_).type(); + } else if (std::holds_alternative<ScriptMessageDictValue>(data_)) { + return base::Value::Type::DICT; } NOTREACHED(); @@ -45,7 +52,13 @@ data_.emplace<base::Value>(base::Value()); } + CHECK(std::holds_alternative<base::Value>(data_)); return std::get<base::Value>(data_); } +const ScriptMessageDictValue& ScriptMessageValue::GetDict() const { + CHECK(type() == base::Value::Type::DICT); + return std::get<ScriptMessageDictValue>(data_); +} + } // namespace web
diff --git a/ios/web/js_messaging/script_message_value_impl_unittest.mm b/ios/web/js_messaging/script_message_value_impl_unittest.mm index a7fd5fc5..a881fc4 100644 --- a/ios/web/js_messaging/script_message_value_impl_unittest.mm +++ b/ios/web/js_messaging/script_message_value_impl_unittest.mm
@@ -42,6 +42,12 @@ EXPECT_EQ(3.14, message_value.GetValue().GetDouble()); } +TEST_F(ScriptMessageValueTest, ValueShouldSupportDictConstruction) { + NSDictionary* ns_dict = @{@"key" : @"value"}; + ScriptMessageValue message_value(ns_dict); + EXPECT_EQ(base::Value::Type::DICT, message_value.type()); +} + // Tests move construction and move assignment. TEST_F(ScriptMessageValueTest, MoveOperations) { ScriptMessageValue original(true);
diff --git a/ios/web/public/js_messaging/BUILD.gn b/ios/web/public/js_messaging/BUILD.gn index 60c5b69..1f3375a4 100644 --- a/ios/web/public/js_messaging/BUILD.gn +++ b/ios/web/public/js_messaging/BUILD.gn
@@ -21,6 +21,7 @@ "java_script_feature_util.h", "origin_filter.h", "script_message.h", + "script_message_dict_value.h", "script_message_value.h", "web_frame.h", "web_frame_user_data.h",
diff --git a/ios/web/public/js_messaging/script_message_dict_value.h b/ios/web/public/js_messaging/script_message_dict_value.h new file mode 100644 index 0000000..f6872b40 --- /dev/null +++ b/ios/web/public/js_messaging/script_message_dict_value.h
@@ -0,0 +1,60 @@ +// 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_WEB_PUBLIC_JS_MESSAGING_SCRIPT_MESSAGE_DICT_VALUE_H_ +#define IOS_WEB_PUBLIC_JS_MESSAGING_SCRIPT_MESSAGE_DICT_VALUE_H_ + +#include <Foundation/Foundation.h> + +#include <memory> +#include <optional> +#include <string_view> + +#include "base/values.h" + +namespace web { +class ScriptMessageValue; + +class ScriptMessageDictValue { + public: + ScriptMessageDictValue(ScriptMessageDictValue&&); + ScriptMessageDictValue& operator=(ScriptMessageDictValue&&); + + // Deleted to prevent accidental copying. + ScriptMessageDictValue(const ScriptMessageDictValue&) = delete; + ScriptMessageDictValue& operator=(const ScriptMessageDictValue&) = delete; + + explicit ScriptMessageDictValue(NSDictionary* value); + ~ScriptMessageDictValue(); + + // Returns true if there are no values in this dict and false otherwise. + bool empty() const; + // Returns the number of values in this dict. + size_t size() const; + + // Returns true if `key` is an entry in this dictionary. + bool contains(std::string_view key) const; + + // Finds the entry corresponding to `key` in this dictionary. Returns + // nullptr if there is no such entry. + std::unique_ptr<ScriptMessageValue> Find(std::string_view key); + + // Similar to `Find()` above, but returns `std::nullopt`/`nullptr` if the type + // of the entry does not match. + std::optional<bool> FindBool(std::string_view key) const; + std::optional<int> FindInt(std::string_view key) const; + // Returns a non-null value for both `Value::Type::DOUBLE` and + // `Value::Type::INT`, converting the latter to a double. + std::optional<double> FindDouble(std::string_view key) const; + std::optional<std::string> FindString(std::string_view key) const; + std::unique_ptr<ScriptMessageDictValue> FindDict(std::string_view key) const; + // TODO(crbug.com/509501985): Add List support. + + private: + NSDictionary* data_; +}; + +} // namespace web + +#endif // IOS_WEB_PUBLIC_JS_MESSAGING_SCRIPT_MESSAGE_DICT_VALUE_H_
diff --git a/ios/web/public/js_messaging/script_message_value.h b/ios/web/public/js_messaging/script_message_value.h index 0619905..c0cca7a 100644 --- a/ios/web/public/js_messaging/script_message_value.h +++ b/ios/web/public/js_messaging/script_message_value.h
@@ -4,6 +4,7 @@ #ifndef IOS_WEB_PUBLIC_JS_MESSAGING_SCRIPT_MESSAGE_VALUE_H_ #define IOS_WEB_PUBLIC_JS_MESSAGING_SCRIPT_MESSAGE_VALUE_H_ + #include <Foundation/Foundation.h> #include <optional> @@ -13,6 +14,7 @@ #include "base/notreached.h" #include "base/values.h" +#include "ios/web/public/js_messaging/script_message_dict_value.h" namespace web { @@ -31,17 +33,21 @@ explicit ScriptMessageValue(std::u16string_view value); explicit ScriptMessageValue(double value); explicit ScriptMessageValue(bool value); + explicit ScriptMessageValue(ScriptMessageDictValue value); + explicit ScriptMessageValue(NSDictionary* value); ~ScriptMessageValue(); // Type checker functions. base::Value::Type type() const; - // Access the underlying data structure. + // Accesses the underlying data structures, but fails with a `CHECK()` on a + // type mismatch. const base::Value& GetValue(); + const ScriptMessageDictValue& GetDict() const; private: // The object ScriptMessageValue encapsulates. - std::variant<std::monostate, base::Value> data_; + std::variant<std::monostate, base::Value, ScriptMessageDictValue> data_; }; } // namespace web
diff --git a/media/gpu/vaapi/vaapi_wrapper.cc b/media/gpu/vaapi/vaapi_wrapper.cc index 8e7fa60..519517d1 100644 --- a/media/gpu/vaapi/vaapi_wrapper.cc +++ b/media/gpu/vaapi/vaapi_wrapper.cc
@@ -2660,6 +2660,25 @@ VaapiStatus::Codes::kFailedToExportSurface); } + gfx::NativePixmapHandle handle; + CHECK_GE(descriptor.num_objects, 1u); + handle.modifier = descriptor.objects[0].drm_format_modifier; + std::vector<base::ScopedFD> fds; + for (size_t index = 0; index < descriptor.num_objects; ++index) { + const auto& object = UNSAFE_TODO(descriptor.objects[index]); + // The modifier should not change for different planes. + CHECK_EQ(handle.modifier, object.drm_format_modifier); + + // The file descriptor (FD) should be owned by us: per va/va.h, "the + // exported handles are owned by the caller." |fds| will own the file + // descriptors. Any FD's that are referenced by a plane will be moved into + // |handle.planes| for that plane. If an FD is referenced by two or more + // planes, it will be duplicated the minimal number of times to build + // |handle.planes|. If an FD is not referenced by any plane, it will be + // closed when |fds| goes out of scope, which is fine. + fds.emplace_back(object.fd); + } + // Translate the pixel format to a viz::SharedImageFormat. viz::SharedImageFormat si_format; switch (descriptor.fourcc) { @@ -2682,33 +2701,11 @@ si_format = viz::SinglePlaneFormat::kBGRA_8888; break; default: - // TODO(crbug.com/508312480): This might be leaking file descriptors - // allocated by vaExportSurfaceHandle. This should be investigated and - // fixed. return VaapiStatus{VaapiStatus::Codes::kFailedToExportSurface, "Cannot export surface with unknown FOURCC", "fourcc", FourccToString(descriptor.fourcc)}; } - gfx::NativePixmapHandle handle; - CHECK_GE(descriptor.num_objects, 1u); - handle.modifier = descriptor.objects[0].drm_format_modifier; - std::vector<base::ScopedFD> fds; - for (size_t index = 0; index < descriptor.num_objects; ++index) { - const auto& object = UNSAFE_TODO(descriptor.objects[index]); - // The modifier should not change for different planes. - CHECK_EQ(handle.modifier, object.drm_format_modifier); - - // The file descriptor (FD) should be owned by us: per va/va.h, "the - // exported handles are owned by the caller." |fds| will own the file - // descriptors. Any FD's that are referenced by a plane will be moved into - // |handle.planes| for that plane. If an FD is referenced by two or more - // planes, it will be duplicated the minimal number of times to build - // |handle.planes|. If an FD is not referenced by any plane, it will be - // closed when |fds| goes out of scope, which is fine. - fds.emplace_back(object.fd); - } - for (uint32_t index = 0; index < descriptor.num_layers; ++index) { const auto& layer = UNSAFE_TODO(descriptor.layers[index]); // According to va/va_drmcommon.h, if VA_EXPORT_SURFACE_SEPARATE_LAYERS is
diff --git a/net/disk_cache/backend_unittest.cc b/net/disk_cache/backend_unittest.cc index fd9c482..951630a7 100644 --- a/net/disk_cache/backend_unittest.cc +++ b/net/disk_cache/backend_unittest.cc
@@ -16,6 +16,7 @@ #include "base/functional/callback.h" #include "base/functional/callback_helpers.h" #include "base/memory/raw_ptr.h" +#include "base/memory_coordinator/memory_coordinator_features.h" #include "base/memory_coordinator/test_memory_consumer_registry.h" #include "base/metrics/field_trial.h" #include "base/run_loop.h" @@ -850,6 +851,9 @@ } TEST_F(DiskCacheBackendTest, MemoryListensToMemoryPressure) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeature(base::kStatefulMemoryPressure); + const int kLimit = 16 * 1024; const int kEntrySize = 256; SetMaxSize(kLimit);
diff --git a/net/disk_cache/memory/mem_backend_impl.cc b/net/disk_cache/memory/mem_backend_impl.cc index 9c6b996..4be377d71 100644 --- a/net/disk_cache/memory/mem_backend_impl.cc +++ b/net/disk_cache/memory/mem_backend_impl.cc
@@ -11,9 +11,11 @@ #include <utility> #include "base/byte_size.h" +#include "base/feature_list.h" #include "base/functional/bind.h" #include "base/logging.h" #include "base/memory_coordinator/memory_consumer.h" +#include "base/memory_coordinator/memory_coordinator_features.h" #include "base/memory_coordinator/utils.h" #include "base/numerics/safe_conversions.h" #include "base/system/sys_info.h" @@ -356,6 +358,9 @@ } void MemBackendImpl::OnUpdateMemoryLimit() { + if (!base::FeatureList::IsEnabled(base::kStatefulMemoryPressure)) { + return; + } // IMPORTANT: Ensure no memory is released during this call. // By using std::max, we ensure the new limit is at least the current size, // preventing growth without triggering immediate eviction. @@ -363,9 +368,18 @@ } void MemBackendImpl::OnReleaseMemory() { - // Now we actually evict entries to reach the target size. - current_max_size_ = CalculateTargetMemoryLimit(); - EvictTill(current_max_size_); + if (base::FeatureList::IsEnabled(base::kStatefulMemoryPressure)) { + // Now we actually evict entries to reach the target size. + current_max_size_ = CalculateTargetMemoryLimit(); + EvictTill(current_max_size_); + } else { + // Stateless behavior, evict to specific limits. + if (memory_limit() <= base::kCriticalMemoryPressureThreshold) { + EvictTill(max_size_ / 10); + } else if (memory_limit() <= base::kModerateMemoryPressureThreshold) { + EvictTill(max_size_ / 2); + } + } } } // namespace disk_cache
diff --git a/net/disk_cache/memory/mem_backend_impl_unittest.cc b/net/disk_cache/memory/mem_backend_impl_unittest.cc index d2e245c..a2685fb 100644 --- a/net/disk_cache/memory/mem_backend_impl_unittest.cc +++ b/net/disk_cache/memory/mem_backend_impl_unittest.cc
@@ -7,8 +7,11 @@ #include <memory> #include <string> +#include "base/memory_coordinator/memory_coordinator_features.h" #include "base/memory_coordinator/test_memory_consumer_registry.h" +#include "base/memory_coordinator/utils.h" #include "base/strings/string_number_conversions.h" +#include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" #include "net/base/io_buffer.h" #include "net/base/net_errors.h" @@ -96,13 +99,16 @@ } TEST_F(MemBackendImplTest, MemoryConsumer) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(base::kStatefulMemoryPressure); + // 1. Fill the cache. for (int i = 0; i < kNumEntries; ++i) { CreateAndWriteEntry("key" + base::NumberToString(i)); } // 2. Simulate moderate memory pressure (50% limit). - SimulateMemoryLimitAndRelease(50); + SimulateMemoryLimitAndRelease(base::kModerateMemoryPressureThreshold); // key0 to key4 should be evicted. for (int i = 0; i < 5; ++i) { @@ -123,13 +129,53 @@ EXPECT_TRUE(EntryExists("key9")); // 4. Simulate no memory pressure (100% limit). - SimulateMemoryLimitAndRelease(100); + SimulateMemoryLimitAndRelease(base::kNoMemoryPressureThreshold); + + // Should be able to add new entries. + CreateAndWriteEntry("key10"); +} + +TEST_F(MemBackendImplTest, MemoryConsumerStateless) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndDisableFeature(base::kStatefulMemoryPressure); + + // 1. Fill the cache. + for (int i = 0; i < kNumEntries; ++i) { + CreateAndWriteEntry("key" + base::NumberToString(i)); + } + + // 2. Simulate moderate memory pressure (50% limit). + SimulateMemoryLimitAndRelease(base::kModerateMemoryPressureThreshold); + + // key0 to key4 should be evicted. + for (int i = 0; i < 5; ++i) { + EXPECT_FALSE(EntryExists("key" + base::NumberToString(i))); + } + // key5 to key9 should remain. + for (int i = 5; i < kNumEntries; ++i) { + EXPECT_TRUE(EntryExists("key" + base::NumberToString(i))); + } + + // 3. Simulate critical memory pressure (0% limit). + SimulateMemoryLimitAndRelease(base::kCriticalMemoryPressureThreshold); + + // Only the most recent entry (key9) should remain. + for (int i = 0; i < 9; ++i) { + EXPECT_FALSE(EntryExists("key" + base::NumberToString(i))); + } + EXPECT_TRUE(EntryExists("key9")); + + // 4. Simulate no memory pressure (100% limit). + SimulateMemoryLimitAndRelease(base::kNoMemoryPressureThreshold); // Should be able to add new entries. CreateAndWriteEntry("key10"); } TEST_F(MemBackendImplTest, UpdateMemoryLimitDoesNotEvict) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(base::kStatefulMemoryPressure); + // 1. Fill the cache. for (int i = 0; i < kNumEntries; ++i) { CreateAndWriteEntry("key" + base::NumberToString(i)); @@ -137,7 +183,7 @@ // 2. Notify about the new limit (50%), but DO NOT request memory release. test_memory_consumer_registry_.NotifyUpdateMemoryLimitAsync( - 50, task_environment_.QuitClosure()); + base::kModerateMemoryPressureThreshold, task_environment_.QuitClosure()); task_environment_.RunUntilQuit(); // 3. Verify that no eviction has occurred yet. All entries should still @@ -161,6 +207,48 @@ } } +TEST_F(MemBackendImplTest, StatefulStickiness) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(base::kStatefulMemoryPressure); + + // 1. Fill cache. + for (int i = 0; i < kNumEntries; ++i) { + CreateAndWriteEntry("key" + base::NumberToString(i)); + } + + // 2. Trigger moderate memory pressure (50%). + SimulateMemoryLimitAndRelease(base::kModerateMemoryPressureThreshold); + + // 3. Add a new entry. + CreateAndWriteEntry("key10"); + + // Sticky: The limit is locked at 5 entries. + // Adding a 6th entry must evict the oldest one (key5). + EXPECT_FALSE(EntryExists("key5")); + EXPECT_TRUE(EntryExists("key10")); +} + +TEST_F(MemBackendImplTest, StatelessStickiness) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndDisableFeature(base::kStatefulMemoryPressure); + + // 1. Fill cache. + for (int i = 0; i < kNumEntries; ++i) { + CreateAndWriteEntry("key" + base::NumberToString(i)); + } + + // 2. Trigger moderate memory pressure (50%). + SimulateMemoryLimitAndRelease(base::kModerateMemoryPressureThreshold); + + // 3. Add a new entry. + CreateAndWriteEntry("key10"); + + // One-shot: The limit reset back to 10 entries. + // Adding a 6th entry succeeds without evicting key5. + EXPECT_TRUE(EntryExists("key5")); + EXPECT_TRUE(EntryExists("key10")); +} + } // namespace } // namespace disk_cache
diff --git a/net/dns/BUILD.gn b/net/dns/BUILD.gn index 9fc0b47..616c378 100644 --- a/net/dns/BUILD.gn +++ b/net/dns/BUILD.gn
@@ -595,6 +595,9 @@ "//testing/libfuzzer/proto:json_proto_converter", "//third_party/libprotobuf-mutator", ] + if (is_android) { + deps += [ "//third_party/icu:icu_assets" ] + } dict = "//testing/libfuzzer/fuzzers/dicts/json.dict" } @@ -605,6 +608,9 @@ "//net", "//net:net_fuzzer_test_support", ] + if (is_android) { + deps += [ "//third_party/icu:icu_assets" ] + } dict = "//net/data/fuzzer_dictionaries/net_dns_hosts_parse_fuzzer.dict" } @@ -618,6 +624,9 @@ "//testing/libfuzzer/proto:json_proto_converter", "//third_party/libprotobuf-mutator", ] + if (is_android) { + deps += [ "//third_party/icu:icu_assets" ] + } } fuzzer_test("net_dns_https_record_rdata_fuzzer") { @@ -627,6 +636,9 @@ "//net", "//net:net_fuzzer_test_support", ] + if (is_android) { + deps += [ "//third_party/icu:icu_assets" ] + } dict = "//net/data/fuzzer_dictionaries/net_dns_record_fuzzer.dict" } @@ -637,6 +649,9 @@ "//net", "//net:net_fuzzer_test_support", ] + if (is_android) { + deps += [ "//third_party/icu:icu_assets" ] + } dict = "//net/data/fuzzer_dictionaries/net_dns_nsswitch_reader_fuzzer.dict" } @@ -648,6 +663,9 @@ "//net:net_fuzzer_test_support", "//testing/libfuzzer:libfuzzer_base_wrappers", ] + if (is_android) { + deps += [ "//third_party/icu:icu_assets" ] + } dict = "//net/data/fuzzer_dictionaries/net_dns_record_fuzzer.dict" } @@ -658,6 +676,9 @@ "//net", "//net:net_fuzzer_test_support", ] + if (is_android) { + deps += [ "//third_party/icu:icu_assets" ] + } dict = "//net/data/fuzzer_dictionaries/net_dns_record_fuzzer.dict" } @@ -668,6 +689,9 @@ "//net", "//net:net_fuzzer_test_support", ] + if (is_android) { + deps += [ "//third_party/icu:icu_assets" ] + } dict = "//net/data/fuzzer_dictionaries/net_dns_record_fuzzer.dict" } @@ -679,6 +703,9 @@ "//net:net_fuzzer_test_support", "//net:test_support", ] + if (is_android) { + deps += [ "//third_party/icu:icu_assets" ] + } dict = "//net/data/fuzzer_dictionaries/net_host_resolver_manager_fuzzer.dict" libfuzzer_options = [ "max_len=4096" ] }
diff --git a/net/third_party/uri_template/BUILD.gn b/net/third_party/uri_template/BUILD.gn index 6c689fd..b234ef9 100644 --- a/net/third_party/uri_template/BUILD.gn +++ b/net/third_party/uri_template/BUILD.gn
@@ -38,5 +38,8 @@ "//net", "//net:net_fuzzer_test_support", ] + if (is_android) { + deps += [ "//third_party/icu:icu_assets" ] + } dict = "//net/data/fuzzer_dictionaries/net_uri_template_fuzzer.dict" }
diff --git a/pdf/pdf_ink_module.cc b/pdf/pdf_ink_module.cc index 05e1e79..56bb400 100644 --- a/pdf/pdf_ink_module.cc +++ b/pdf/pdf_ink_module.cc
@@ -185,7 +185,8 @@ return InkTextBoxAttributes(textbox, GetColorFromDict(text_attributes), css_font_size, typeface, alignment, orientation, - /*is_bold=*/is_bold, /*is_italic=*/is_italic); + /*is_bold=*/is_bold, /*is_italic=*/is_italic, + *data.FindString("text")); } ink::Rect GetEraserRect(const gfx::PointF& center) {
diff --git a/pdf/pdf_ink_module_unittest.cc b/pdf/pdf_ink_module_unittest.cc index 4d41817..37ae346 100644 --- a/pdf/pdf_ink_module_unittest.cc +++ b/pdf/pdf_ink_module_unittest.cc
@@ -948,7 +948,8 @@ return textbox_rect; } - // Matches `SampleTextAttributesDict()` and `SampleTextBoxRectDict()`. + // Matches `SampleTextAttributesDict()`, `SampleTextBoxRectDict()`, and + // `SampleFinishTextAnnotationData()`. static Matcher<const InkTextBoxAttributes&> SampleInkTextBoxAttributesMatcher() { return InkTextBoxAttributesEq( @@ -959,7 +960,8 @@ /*alignment=*/TextAlignment::kCenter, /*orientation=*/1, /*is_bold=*/true, - /*is_italic=*/true); + /*is_italic=*/true, + /*text=*/"hi"); } static base::BlobStorage SampleInkTextInfoBlob(FontId typeface_id) {
diff --git a/pdf/pdf_ink_text.cc b/pdf/pdf_ink_text.cc index 78a0cd3..c23af76 100644 --- a/pdf/pdf_ink_text.cc +++ b/pdf/pdf_ink_text.cc
@@ -5,6 +5,7 @@ #include "pdf/pdf_ink_text.h" #include <iterator> +#include <string> #include "base/check_op.h" @@ -111,7 +112,8 @@ TextAlignment alignment, int orientation, bool is_bold, - bool is_italic) + bool is_italic, + const std::string& text) : rect(rect), color(color), css_font_size(css_font_size), @@ -119,7 +121,8 @@ alignment(alignment), orientation(orientation), is_bold(is_bold), - is_italic(is_italic) {} + is_italic(is_italic), + text(text) {} InkTextBoxAttributes::~InkTextBoxAttributes() = default; InkTextInfo::InkTextInfo(FontId font_id,
diff --git a/pdf/pdf_ink_text.h b/pdf/pdf_ink_text.h index 18943e5..4ba03d0f 100644 --- a/pdf/pdf_ink_text.h +++ b/pdf/pdf_ink_text.h
@@ -7,6 +7,7 @@ #include <stdint.h> +#include <string> #include <vector> #include "pdf/mojom/pdf.mojom.h" @@ -42,7 +43,8 @@ TextAlignment alignment, int orientation, bool is_bold, - bool is_italic); + bool is_italic, + const std::string& text); ~InkTextBoxAttributes(); // `rect` is in CSS screen coordinates. @@ -55,6 +57,7 @@ int orientation; bool is_bold; bool is_italic; + std::string text; }; struct InkTextInfo {
diff --git a/pdf/pdf_view_web_plugin_unittest.cc b/pdf/pdf_view_web_plugin_unittest.cc index eac2a54..7144a8c 100644 --- a/pdf/pdf_view_web_plugin_unittest.cc +++ b/pdf/pdf_view_web_plugin_unittest.cc
@@ -3614,7 +3614,8 @@ /*alignment=*/TextAlignment::kLeft, /*orientation=*/0, /*is_bold=*/true, - /*is_italic=*/false); + /*is_italic=*/false, + /*text=*/"Hello"); plugin_->ink_module_client_for_testing()->DrawText( kPageIndex, kTextId, {}, kZoom, text_box_attributes); }
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc index fd2b37e6..257dbc42 100644 --- a/pdf/pdfium/pdfium_engine.cc +++ b/pdf/pdfium/pdfium_engine.cc
@@ -187,6 +187,9 @@ attributes.is_bold)); CHECK(FPDFPageObjMark_SetIntParam(doc, text_object, mark, "IsItalic", attributes.is_italic)); + + CHECK(FPDFPageObjMark_SetStringParam(doc, text_object, mark, "Text", + attributes.text.c_str())); } // Windows has native panning capabilities. No need to use our own.
diff --git a/pdf/pdfium/pdfium_engine_unittest.cc b/pdf/pdfium/pdfium_engine_unittest.cc index 0916e37..e8083a9 100644 --- a/pdf/pdfium/pdfium_engine_unittest.cc +++ b/pdf/pdfium/pdfium_engine_unittest.cc
@@ -8,6 +8,7 @@ #include <memory> #include <optional> +#include <string> #include <utility> #include "base/check_op.h" @@ -3080,7 +3081,8 @@ /*alignment=*/TextAlignment::kLeft, /*orientation=*/0, /*is_bold=*/false, - /*is_italic=*/false); + /*is_italic=*/false, + /*text=*/"Hello!"); } }; @@ -3166,6 +3168,9 @@ PDFiumPage& page = GetPDFiumPage(*engine, kPageIndex); CheckPdfRenderingIsBlank200x200(page.GetPage()); + constexpr char kExpectedText[] = "Hello!"; + constexpr char16_t kExpectedText16[] = u"Hello!"; + FontId font_id = AddDefaultFont(engine.get()); GlyphsAndPositions text_data1 = GetGlyphsForText("Hello", /*font_size=*/10.0f); @@ -3178,6 +3183,7 @@ // Draw some text with two runs to force multiple text objects. InkTextBoxAttributes attribute = SampleInkTextBoxAttributes(); attribute.is_bold = true; + attribute.text = kExpectedText; engine->DrawText( kPageIndex, InkTextId(1), {InkTextInfo(font_id, text_data1.glyphs, text_data1.glyph_positions, @@ -3225,6 +3231,8 @@ testing::Optional(1)); EXPECT_THAT(GetPageObjectMarkIntParam(mark, "IsItalic"), testing::Optional(0)); + EXPECT_THAT(GetPageObjectMarkStringParam(mark, "Text"), + testing::Optional(std::u16string(kExpectedText16))); } else { // Verify the remaining text objects do not have the full metadata. EXPECT_FALSE(GetPageObjectMarkIntParam(mark, "Version").has_value()); @@ -3239,6 +3247,7 @@ EXPECT_FALSE(GetPageObjectMarkIntParam(mark, "Orientation").has_value()); EXPECT_FALSE(GetPageObjectMarkIntParam(mark, "IsBold").has_value()); EXPECT_FALSE(GetPageObjectMarkIntParam(mark, "IsItalic").has_value()); + EXPECT_FALSE(GetPageObjectMarkStringParam(mark, "Text").has_value()); } } }
diff --git a/pdf/test/pdf_ink_test_helpers.h b/pdf/test/pdf_ink_test_helpers.h index 14a72bc..78ead48 100644 --- a/pdf/test/pdf_ink_test_helpers.h +++ b/pdf/test/pdf_ink_test_helpers.h
@@ -8,6 +8,7 @@ #include <stdint.h> #include <optional> +#include <string> #include <string_view> #include "base/containers/span.h" @@ -84,7 +85,7 @@ Matches(FloatEq(expected_f))(arg.F()); } -MATCHER_P8(InkTextBoxAttributesEq, +MATCHER_P9(InkTextBoxAttributesEq, rect, color, css_font_size, @@ -93,11 +94,13 @@ orientation, is_bold, is_italic, + text, "matches InkTextBoxAttributes") { return arg.rect == rect && arg.color == color && arg.css_font_size == css_font_size && arg.typeface == typeface && arg.alignment == alignment && arg.orientation == orientation && - arg.is_bold == is_bold && arg.is_italic == is_italic; + arg.is_bold == is_bold && arg.is_italic == is_italic && + arg.text == text; } MATCHER_P5(InkTextInfoEq,
diff --git a/remoting/base/protobuf_http_request_base.cc b/remoting/base/protobuf_http_request_base.cc index 0468e21..05f7c33 100644 --- a/remoting/base/protobuf_http_request_base.cc +++ b/remoting/base/protobuf_http_request_base.cc
@@ -24,7 +24,8 @@ struct ProtobufHttpRequestBase::RetryEntry { explicit RetryEntry( const ProtobufHttpRequestConfig::RetryPolicy& retry_policy) - : backoff_entry(retry_policy.backoff_policy) { + : backoff_entry(retry_policy.backoff_policy), + retriable_error_codes(retry_policy.retriable_error_codes) { retry_deadline = base::TimeTicks::Now() + retry_policy.retry_timeout; } @@ -33,6 +34,7 @@ net::BackoffEntry backoff_entry; base::OneShotTimer retry_timer; base::TimeTicks retry_deadline; + base::flat_set<HttpStatus::Code> retriable_error_codes; }; ProtobufHttpRequestBase::ProtobufHttpRequestBase( @@ -78,13 +80,7 @@ // SimpleURLLoader supports retries, but it doesn't support retrying on // network error, and uses max retries rather than an absolute deadline for // setting the limit. Hence we use our own retry logic. - - static constexpr auto kRetriableErrorCodes = - base::MakeFixedFlatSet<HttpStatus::Code>( - {HttpStatus::Code::ABORTED, HttpStatus::Code::UNAVAILABLE, - HttpStatus::Code::NETWORK_ERROR}); - - if (!retry_entry_ || !kRetriableErrorCodes.contains(code)) { + if (!retry_entry_ || !retry_entry_->retriable_error_codes.contains(code)) { return false; } retry_entry_->backoff_entry.InformOfRequest(false);
diff --git a/remoting/base/protobuf_http_request_config.cc b/remoting/base/protobuf_http_request_config.cc index e9013db2..3ff7458 100644 --- a/remoting/base/protobuf_http_request_config.cc +++ b/remoting/base/protobuf_http_request_config.cc
@@ -36,6 +36,8 @@ return *policy; } +ProtobufHttpRequestConfig::RetryPolicy::~RetryPolicy() = default; + ProtobufHttpRequestConfig::ProtobufHttpRequestConfig( const net::NetworkTrafficAnnotationTag& traffic_annotation) : traffic_annotation(traffic_annotation) {}
diff --git a/remoting/base/protobuf_http_request_config.h b/remoting/base/protobuf_http_request_config.h index 6abd9eab..7a33778 100644 --- a/remoting/base/protobuf_http_request_config.h +++ b/remoting/base/protobuf_http_request_config.h
@@ -8,6 +8,7 @@ #include <memory> #include <string> +#include "base/containers/flat_set.h" #include "base/memory/raw_ptr.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_refptr.h" @@ -38,10 +39,15 @@ // after which the request will no longer be retried. base::TimeDelta retry_timeout; + // The list of error codes that trigger a retry. + base::flat_set<HttpStatus::Code> retriable_error_codes = { + HttpStatus::Code::ABORTED, HttpStatus::Code::UNAVAILABLE, + HttpStatus::Code::NETWORK_ERROR}; + private: friend class base::RefCountedThreadSafe<RetryPolicy>; - ~RetryPolicy() = default; + ~RetryPolicy(); }; // Returns a simple RetryPolicy that retries for up to ~1 minute (counted
diff --git a/remoting/signaling/ftl_messaging_client.cc b/remoting/signaling/ftl_messaging_client.cc index e7fe6d4..d419e08 100644 --- a/remoting/signaling/ftl_messaging_client.cc +++ b/remoting/signaling/ftl_messaging_client.cc
@@ -209,7 +209,8 @@ void FtlMessagingClient::SendMessage( const SignalingAddress& destination_address, ftl::ChromotingMessage&& message, - DoneCallback on_done) { + DoneCallback on_done, + scoped_refptr<const ProtobufHttpRequestConfig::RetryPolicy> retry_policy) { std::string user_email; std::string registration_id; if (!destination_address.GetFtlInfo(&user_email, ®istration_id)) { @@ -240,12 +241,17 @@ request->add_dest_registration_ids(registration_id); } - // SendMessage is non-idempotent (potentially duplicate messages will be - // sent), so retries may not be safe. ExecuteRequest(kSendMessageTrafficAnnotation, kSendMessagePath, - /*enable_retries=*/false, std::move(request), - &FtlMessagingClient::OnSendMessageResponse, - std::move(on_done)); + std::move(request), &FtlMessagingClient::OnSendMessageResponse, + std::move(on_done), std::move(retry_policy)); +} + +void FtlMessagingClient::SendMessage( + const SignalingAddress& destination_address, + ftl::ChromotingMessage&& message, + DoneCallback on_done) { + SendMessage(destination_address, std::move(message), std::move(on_done), + nullptr); } void FtlMessagingClient::StartReceivingMessages(base::OnceClosure on_ready, @@ -266,15 +272,15 @@ void FtlMessagingClient::ExecuteRequest( const net::NetworkTrafficAnnotationTag& tag, const std::string& path, - bool enable_retries, std::unique_ptr<google::protobuf::MessageLite> request, CallbackFunctor callback_functor, - DoneCallback on_done) { + DoneCallback on_done, + scoped_refptr<const ProtobufHttpRequestConfig::RetryPolicy> retry_policy) { auto config = std::make_unique<ProtobufHttpRequestConfig>(tag); config->request_message = std::move(request); config->path = path; - if (enable_retries) { - config->UseSimpleRetryPolicy(); + if (retry_policy) { + config->retry_policy = std::move(retry_policy); } auto http_request = std::make_unique<ProtobufHttpRequest>(std::move(config)); http_request->SetResponseCallback(base::BindOnce( @@ -298,10 +304,10 @@ VLOG(1) << "Acking " << request.message_ids_size() << " messages"; ExecuteRequest(kAckMessagesTrafficAnnotation, kBatchAckMessagesPath, - /*enable_retries=*/true, std::make_unique<ftl::BatchAckMessagesRequest>(request), &FtlMessagingClient::OnBatchAckMessagesResponse, - std::move(on_done)); + std::move(on_done), + ProtobufHttpRequestConfig::GetSimpleRetryPolicy()); } void FtlMessagingClient::OnBatchAckMessagesResponse(
diff --git a/remoting/signaling/ftl_messaging_client.h b/remoting/signaling/ftl_messaging_client.h index a310b76..89e472e 100644 --- a/remoting/signaling/ftl_messaging_client.h +++ b/remoting/signaling/ftl_messaging_client.h
@@ -13,6 +13,7 @@ #include "base/memory/raw_ptr.h" #include "base/memory/scoped_refptr.h" #include "remoting/base/http_status.h" +#include "remoting/base/protobuf_http_request_config.h" #include "remoting/proto/ftl/v1/chromoting_message.pb.h" #include "remoting/proto/ftl/v1/ftl_messages.pb.h" #include "remoting/signaling/message_tracker.h" @@ -74,7 +75,14 @@ const MessageCallback& callback); // Sends |message| to |destination_address| and then calls |on_done| with the - // result of the operation. + // result of the operation. If non-null, |retry_policy| controls retries. + virtual void SendMessage( + const SignalingAddress& destination_address, + ftl::ChromotingMessage&& message, + DoneCallback on_done, + scoped_refptr<const ProtobufHttpRequestConfig::RetryPolicy> retry_policy); + + // Helper function that calls SendMessage() with retries disabled. virtual void SendMessage(const SignalingAddress& destination_address, ftl::ChromotingMessage&& message, DoneCallback on_done); @@ -104,12 +112,13 @@ std::unique_ptr<FtlMessageChannelStrategy> strategy); template <typename CallbackFunctor> - void ExecuteRequest(const net::NetworkTrafficAnnotationTag& tag, - const std::string& path, - bool enable_retries, - std::unique_ptr<google::protobuf::MessageLite> request, - CallbackFunctor callback_functor, - DoneCallback on_done); + void ExecuteRequest( + const net::NetworkTrafficAnnotationTag& tag, + const std::string& path, + std::unique_ptr<google::protobuf::MessageLite> request, + CallbackFunctor callback_functor, + DoneCallback on_done, + scoped_refptr<const ProtobufHttpRequestConfig::RetryPolicy> retry_policy); void OnSendMessageResponse(DoneCallback on_done, const remoting::HttpStatus& status,
diff --git a/remoting/signaling/ftl_signal_strategy.cc b/remoting/signaling/ftl_signal_strategy.cc index 2e1e77c2..6cfa98ea 100644 --- a/remoting/signaling/ftl_signal_strategy.cc +++ b/remoting/signaling/ftl_signal_strategy.cc
@@ -29,6 +29,20 @@ namespace remoting { +namespace { + +scoped_refptr<const ProtobufHttpRequestConfig::RetryPolicy> +GetNotFoundRetryPolicy() { + auto simple_policy = ProtobufHttpRequestConfig::GetSimpleRetryPolicy(); + auto policy = base::MakeRefCounted<ProtobufHttpRequestConfig::RetryPolicy>(); + policy->backoff_policy = simple_policy->backoff_policy; + policy->retry_timeout = simple_policy->retry_timeout; + policy->retriable_error_codes = {HttpStatus::Code::NOT_FOUND}; + return policy; +} + +} // namespace + class FtlSignalStrategy::Core { public: Core(std::unique_ptr<OAuthTokenGetter> oauth_token_getter, @@ -59,7 +73,10 @@ private: template <typename T> - bool Send(T&& message, const char* message_type); + bool Send(T&& message, + const char* message_type, + scoped_refptr<const ProtobufHttpRequestConfig::RetryPolicy> + retry_policy = nullptr); // Methods are called in the order below when Connect() is called. void OnGetOAuthTokenResponse(OAuthTokenGetter::Status status, const OAuthTokenInfo& token_info); @@ -68,9 +85,12 @@ void OnReceiveMessagesStreamStarted(); void OnReceiveMessagesStreamClosed(const HttpStatus& status); - void SendMessageImpl(const SignalingAddress& receiver, - ftl::ChromotingMessage&& message, - FtlMessagingClient::DoneCallback callback); + void SendMessageImpl( + const SignalingAddress& receiver, + ftl::ChromotingMessage&& message, + FtlMessagingClient::DoneCallback callback, + scoped_refptr<const ProtobufHttpRequestConfig::RetryPolicy> retry_policy = + nullptr); void OnSendMessageResponse(const SignalingAddress& receiver, const std::string& stanza_id, const HttpStatus& status); @@ -200,15 +220,29 @@ } bool FtlSignalStrategy::Core::SendMessage(JingleMessage&& message) { - return Send(std::move(message), "message"); + // Note that duplicate messages may be sent, but the client and host are + // responsible for filtering out duplicates. + scoped_refptr<const ProtobufHttpRequestConfig::RetryPolicy> policy; + if (message.action() == JingleMessage::ActionType::kSessionAccept) { + policy = GetNotFoundRetryPolicy(); + } + + return Send(std::move(message), "message", std::move(policy)); } bool FtlSignalStrategy::Core::SendReply(JingleMessageReply&& message) { - return Send(std::move(message), "reply"); + // Generally we don't want to retry replies either, but session-initiate + // replies have been observed to be rejected with NOT_FOUND, possible due to + // replicate delays in the back-end. Since we don't know here what message + // we are replying to, we consider NOT_FOUND to be retriable here. + return Send(std::move(message), "reply", GetNotFoundRetryPolicy()); } template <typename T> -bool FtlSignalStrategy::Core::Send(T&& message, const char* message_type) { +bool FtlSignalStrategy::Core::Send( + T&& message, + const char* message_type, + scoped_refptr<const ProtobufHttpRequestConfig::RetryPolicy> retry_policy) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (GetState() != CONNECTED) { @@ -229,10 +263,12 @@ // TODO: crbug.com/504910955 - Re-enable iq_stanza once parsing issues are // resolved. - SendMessageImpl( - destination_address, std::move(crd_message), + auto done_callback = base::BindOnce(&Core::OnSendMessageResponse, weak_factory_.GetWeakPtr(), - destination_address, message_id)); + destination_address, message_id); + + SendMessageImpl(destination_address, std::move(crd_message), + std::move(done_callback), std::move(retry_policy)); return GetState() == CONNECTED; } @@ -249,7 +285,8 @@ SendMessageImpl( destination_address, std::move(message), base::BindOnce(&Core::OnSendMessageResponse, weak_factory_.GetWeakPtr(), - destination_address, std::string())); + destination_address, std::string()), + /*retry_policy=*/nullptr); return true; } @@ -416,7 +453,8 @@ void FtlSignalStrategy::Core::SendMessageImpl( const SignalingAddress& receiver, ftl::ChromotingMessage&& message, - FtlMessagingClient::DoneCallback callback) { + FtlMessagingClient::DoneCallback callback, + scoped_refptr<const ProtobufHttpRequestConfig::RetryPolicy> retry_policy) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); std::string receiver_username; @@ -448,7 +486,7 @@ << "\n========================================================="; messaging_client_->SendMessage(receiver, std::move(message), - std::move(callback)); + std::move(callback), std::move(retry_policy)); } void FtlSignalStrategy::Core::OnSendMessageResponse(
diff --git a/remoting/signaling/ftl_signal_strategy_unittest.cc b/remoting/signaling/ftl_signal_strategy_unittest.cc index 7009229..af8380a 100644 --- a/remoting/signaling/ftl_signal_strategy_unittest.cc +++ b/remoting/signaling/ftl_signal_strategy_unittest.cc
@@ -178,7 +178,10 @@ MOCK_METHOD(void, SendMessage, - (const SignalingAddress&, ftl::ChromotingMessage&&, DoneCallback), + (const SignalingAddress&, + ftl::ChromotingMessage&&, + DoneCallback, + scoped_refptr<const ProtobufHttpRequestConfig::RetryPolicy>), (override)); void OnMessage(const ftl::Id& sender_id, @@ -478,7 +481,7 @@ EXPECT_CALL( *messaging_client_, SendMessage(Property(&SignalingAddress::id, kFakeRemoteFtlId), - SignalingMessageMatches(kFakeRemoteFtlId, kFakeLocalFtlId), + SignalingMessageMatches(kFakeRemoteFtlId, kFakeLocalFtlId), _, _)) .WillOnce(base::test::RunOnceCallback<2>(HttpStatus::OK())); signal_strategy_->SendMessage(std::move(jingle_message)); @@ -500,7 +503,7 @@ EXPECT_CALL(*token_getter_, InvalidateCache()).WillOnce(Return()); EXPECT_CALL( *messaging_client_, - SendMessage(Property(&SignalingAddress::id, kFakeRemoteFtlId), _, _)) + SendMessage(Property(&SignalingAddress::id, kFakeRemoteFtlId), _, _, _)) .WillOnce(base::test::RunOnceCallback<2>( HttpStatus(HttpStatus::Code::UNAUTHENTICATED, "unauthenticated"))); signal_strategy_->SendMessage(std::move(jingle_message)); @@ -530,7 +533,7 @@ EXPECT_CALL( *messaging_client_, - SendMessage(Property(&SignalingAddress::id, kFakeRemoteFtlId), _, _)) + SendMessage(Property(&SignalingAddress::id, kFakeRemoteFtlId), _, _, _)) .WillOnce(base::test::RunOnceCallback<2>( HttpStatus(HttpStatus::Code::UNAVAILABLE, "unavailable"))); signal_strategy_->SendMessage(std::move(jingle_message)); @@ -655,7 +658,7 @@ SignalingAddress::CreateFtlSignalingAddress( kFakeRemoteUsername, kFakeRemoteRegistrationId) .id()), - SignalingMessageMatches(message_payload), _)) + SignalingMessageMatches(message_payload), _, _)) .WillOnce(base::test::RunOnceCallback<2>(HttpStatus::OK())); signal_strategy_->SendFtlMessage( @@ -677,7 +680,7 @@ SignalingAddress::CreateFtlSignalingAddress( kFakeRemoteUsername, kFakeRemoteRegistrationId) .id()), - _, _)) + _, _, _)) .WillOnce(base::test::RunOnceCallback<2>( HttpStatus(HttpStatus::Code::UNAUTHENTICATED, "unauthenticated"))); @@ -712,7 +715,7 @@ SignalingAddress::CreateFtlSignalingAddress( kFakeRemoteUsername, kFakeRemoteRegistrationId) .id()), - _, _)) + _, _, _)) .WillOnce(base::test::RunOnceCallback<2>( HttpStatus(HttpStatus::Code::UNAVAILABLE, "unavailable"))); @@ -870,11 +873,82 @@ EXPECT_CALL( *messaging_client_, SendMessage(Property(&SignalingAddress::id, kFakeRemoteFtlId), - SignalingMessageMatches(kFakeRemoteFtlId, kFakeLocalFtlId), + SignalingMessageMatches(kFakeRemoteFtlId, kFakeLocalFtlId), _, _)) .WillOnce(base::test::RunOnceCallback<2>(HttpStatus::OK())); signal_strategy_->SendReply(std::move(reply)); } +TEST_F(FtlSignalStrategyTest, SendMessage_SessionAcceptRequestsNotFoundRetry) { + ExpectGetOAuthTokenSucceedsWithFakeCreds(); + registration_manager_->ExpectSignInGaiaSucceeds(); + signal_strategy_->Connect(); + messaging_client_->AcceptReceivingMessages(); + + JingleMessage message(SignalingAddress(kFakeRemoteFtlId), SessionAccept(), + "sid"); + message.message_id = "id"; + + EXPECT_CALL(*messaging_client_, SendMessage(_, _, _, _)) + .WillOnce([&](const SignalingAddress&, ftl::ChromotingMessage&&, + FtlMessagingClient::DoneCallback callback, + scoped_refptr<const ProtobufHttpRequestConfig::RetryPolicy> + retry_policy) { + ASSERT_TRUE(retry_policy); + EXPECT_TRUE(retry_policy->retriable_error_codes.contains( + HttpStatus::Code::NOT_FOUND)); + std::move(callback).Run(HttpStatus::OK()); + }); + + signal_strategy_->SendMessage(std::move(message)); +} + +TEST_F(FtlSignalStrategyTest, SendReply_RequestsNotFoundRetry) { + ExpectGetOAuthTokenSucceedsWithFakeCreds(); + registration_manager_->ExpectSignInGaiaSucceeds(); + signal_strategy_->Connect(); + messaging_client_->AcceptReceivingMessages(); + + JingleMessageReply reply; + reply.to = SignalingAddress(kFakeRemoteFtlId); + reply.message_id = "id"; + + EXPECT_CALL(*messaging_client_, SendMessage(_, _, _, _)) + .WillOnce([&](const SignalingAddress&, ftl::ChromotingMessage&&, + FtlMessagingClient::DoneCallback callback, + scoped_refptr<const ProtobufHttpRequestConfig::RetryPolicy> + retry_policy) { + ASSERT_TRUE(retry_policy); + EXPECT_TRUE(retry_policy->retriable_error_codes.contains( + HttpStatus::Code::NOT_FOUND)); + std::move(callback).Run(HttpStatus::OK()); + }); + + signal_strategy_->SendReply(std::move(reply)); +} + +TEST_F(FtlSignalStrategyTest, + SendMessage_OtherMessagesDoNotRequestNotFoundRetry) { + ExpectGetOAuthTokenSucceedsWithFakeCreds(); + registration_manager_->ExpectSignInGaiaSucceeds(); + signal_strategy_->Connect(); + messaging_client_->AcceptReceivingMessages(); + + JingleMessage message(SignalingAddress(kFakeRemoteFtlId), SessionInfo(), + "sid"); + message.message_id = "id"; + + EXPECT_CALL(*messaging_client_, SendMessage(_, _, _, _)) + .WillOnce([&](const SignalingAddress&, ftl::ChromotingMessage&&, + FtlMessagingClient::DoneCallback callback, + scoped_refptr<const ProtobufHttpRequestConfig::RetryPolicy> + retry_policy) { + ASSERT_FALSE(retry_policy); + std::move(callback).Run(HttpStatus::OK()); + }); + + signal_strategy_->SendMessage(std::move(message)); +} + } // namespace remoting
diff --git a/remoting/tools/magi-mode/PRESUBMIT.py b/remoting/tools/magi-mode/PRESUBMIT.py index 74204523..b6e9eed 100644 --- a/remoting/tools/magi-mode/PRESUBMIT.py +++ b/remoting/tools/magi-mode/PRESUBMIT.py
@@ -253,6 +253,27 @@ else: results.append(output_api.PresubmitPromptWarning(msg)) + # Scenario 5: Content mandates + if skill_md_path in affected_files_map: + skill_content = input_api.ReadFile(affected_files_map[skill_md_path]) + if 'TONE MANDATE (SIGNAL-TO-NOISE):' not in skill_content: + results.append( + output_api.PresubmitError( + 'File SKILL.md must contain the "TONE MANDATE (SIGNAL-TO-NOISE):"' + ' section.' + ) + ) + elif ( + 'Zero Preamble/Postamble' not in skill_content + or 'Artifacts Only' not in skill_content + ): + results.append( + output_api.PresubmitError( + 'File SKILL.md TONE MANDATE must explicitly enforce ' + '"Zero Preamble/Postamble" and "Artifacts Only".' + ) + ) + return results
diff --git a/remoting/tools/magi-mode/PRESUBMIT_test.py b/remoting/tools/magi-mode/PRESUBMIT_test.py index a16e840b..2e113f0 100755 --- a/remoting/tools/magi-mode/PRESUBMIT_test.py +++ b/remoting/tools/magi-mode/PRESUBMIT_test.py
@@ -131,6 +131,54 @@ warnings = [r for r in results if 'exceeds 80 characters' in r] self.assertEqual(len(warnings), 0) + def testMarkdownContentMandates(self): + # Missing Tone Mandate + content_missing = 'Some text\n' + self.mock_input.affected_files = [ + MockAffectedFile('remoting/tools/magi-mode/SKILL.md')] + self.mock_input.files_content = { + 'remoting/tools/magi-mode/SKILL.md': content_missing} + + magi_dir = os.path.normpath(os.path.join( + os.path.abspath('fake_repo'), 'remoting/tools/magi-mode')) + with patch('os.walk', return_value=[(magi_dir, [], ['SKILL.md'])]), \ + patch('os.path.getsize', return_value=100): + results = PRESUBMIT.CheckMarkdownFiles( + self.mock_input, self.mock_output) + + self.assertTrue(any('must contain the "TONE MANDATE ' + '(SIGNAL-TO-NOISE):" section' in r + for r in results)) + + # Missing Artifacts Only + content_partial = ('TONE MANDATE (SIGNAL-TO-NOISE):\n' + 'Zero Preamble/Postamble\n') + self.mock_input.files_content = { + 'remoting/tools/magi-mode/SKILL.md': content_partial} + with patch('os.walk', return_value=[(magi_dir, [], ['SKILL.md'])]), \ + patch('os.path.getsize', return_value=100): + results = PRESUBMIT.CheckMarkdownFiles( + self.mock_input, self.mock_output) + + self.assertTrue(any('must explicitly enforce "Zero Preamble/' + 'Postamble" and "Artifacts Only"' in r + for r in results)) + + # Valid + content_valid = ('TONE MANDATE (SIGNAL-TO-NOISE):\n' + 'Zero Preamble/Postamble\nArtifacts Only\n') + self.mock_input.files_content = { + 'remoting/tools/magi-mode/SKILL.md': content_valid} + with patch('os.walk', return_value=[(magi_dir, [], ['SKILL.md'])]), \ + patch('os.path.getsize', return_value=100): + results = PRESUBMIT.CheckMarkdownFiles( + self.mock_input, self.mock_output) + + self.assertFalse(any('must contain the "TONE MANDATE ' + '(SIGNAL-TO-NOISE):" section' in r + for r in results)) + self.assertFalse(any('must explicitly enforce' in r for r in results)) + def testJsonStateBlockValidation(self): # Valid state block valid_json = (
diff --git a/remoting/tools/magi-mode/SKILL.md b/remoting/tools/magi-mode/SKILL.md index e9db1d3..6a142deb 100644 --- a/remoting/tools/magi-mode/SKILL.md +++ b/remoting/tools/magi-mode/SKILL.md
@@ -49,6 +49,16 @@ verifying the files in the CL are expected, and the final staging/upload of CLs. +**TONE MANDATE (SIGNAL-TO-NOISE):** To eliminate conversational noise, conserve +tokens, and maximize parsing stability, the Orchestrator MUST instruct ALL +sub-agents (except itself) to adopt a neutral, data-driven tone. +* **Zero Preamble/Postamble:** Sub-agents MUST NOT use conversational filler, + greetings, or explanations of their work. +* **Artifacts Only:** If an agent's mandate is to generate JSON or C++ code, + its entire output MUST consist *only* of that raw data structure. +* **Reviewers:** Reviewers MUST act as rigorous, objective auditors focusing + strictly on technical facts and data. + **TOOL AGNOSTIC MANDATE:** The protocol instructions MUST remain tool-agnostic. Do not assume specific tool names (e.g., `update_topic`, `read_file`, `write_file`). Use generic terms like "read from disk," "save to disk," or @@ -201,6 +211,13 @@ * `EPHEMERAL_WITH_LOGS`: Return JSON natively AND save to disk. **Prompt Template:** > Role Details: Read your mandate from `[persona_file_path]`. + > Audit Mandate: You are a rigorous, objective auditor. Drop all + > politeness. Focus exclusively on technical data and facts. Be concise + > and pointed. + > Dynamic Strictness (Iteration [N]): [If N<=2: "Exhaustively reject for any + > flaw or deviation based on technical facts." | If N==3-4: "Accept minor + > nits. Reject only for functional/security bugs." | If N>=5: "Stall + > prevention. Accept unless catastrophic."] > Project Spec: Read the requirements from `project.magi.json`. > Priority: [Priority]. > Task: Review Draft [filename]. Save a JSON object with `verdict`
diff --git a/services/BUILD.gn b/services/BUILD.gn index 3af3ecd8..f3ae018 100644 --- a/services/BUILD.gn +++ b/services/BUILD.gn
@@ -43,6 +43,8 @@ "SerializeAttributionReportingEligibleHeader.IsEligibleValid", "TrustTokenKeyCommitmentFuzzer.ParsesOneIssuerCorrectly", "TrustTokenKeyCommitmentFuzzer.ParsesMultipleIssuersCorrectly", + "StructTraitsTest.DebugRendererSettingsFuzz", + "StructTraitsTest.RendererSettingsFuzz", "StructTraitsTest.BeginFrameArgsFuzz", "StructTraitsTest.BeginFrameAckFuzz", "StructTraitsTest.BeginFrameAckAsValueFuzz",
diff --git a/services/device/battery/battery_status_manager_mac.cc b/services/device/battery/battery_status_manager_mac.cc index 22e2be7..fb2c3f4 100644 --- a/services/device/battery/battery_status_manager_mac.cc +++ b/services/device/battery/battery_status_manager_mac.cc
@@ -9,13 +9,10 @@ #include <IOKit/ps/IOPowerSources.h> #include <memory> -#include <optional> #include <vector> #include "base/apple/foundation_util.h" #include "base/apple/scoped_cftyperef.h" -#include "base/feature_list.h" -#include "base/features.h" #include "base/functional/bind.h" #include "base/task/task_traits.h" #include "base/task/thread_pool.h" @@ -113,16 +110,12 @@ } } -std::vector<mojom::BatteryStatus> GetInternalBatteriesStates(bool may_block) { +std::vector<mojom::BatteryStatus> GetInternalBatteriesStates() { std::vector<mojom::BatteryStatus> internal_sources; - // This function is known to block but cannot always be tagged as such right - // now because it might run on the UI thread. When running on the ThreadPool - // though it should be appropriately tagged. - std::optional<base::ScopedBlockingCall> scoped_blocking_call; - if (may_block) { - scoped_blocking_call.emplace(FROM_HERE, base::BlockingType::MAY_BLOCK); - } + // IOPSCopyPowerSourcesInfo is known to block. + base::ScopedBlockingCall scoped_blocking_call(FROM_HERE, + base::BlockingType::MAY_BLOCK); base::apple::ScopedCFTypeRef<CFTypeRef> info(IOPSCopyPowerSourcesInfo()); base::apple::ScopedCFTypeRef<CFArrayRef> power_sources_list( @@ -172,14 +165,10 @@ void OnBatteryStatusChangedAsync(const BatteryCallback& callback) { base::ThreadPool::PostTaskAndReplyWithResult( FROM_HERE, {base::MayBlock()}, - base::BindOnce(&GetInternalBatteriesStates, true), + base::BindOnce(&GetInternalBatteriesStates), base::BindOnce(&HandleNewBatteryStatus, callback)); } -void OnBatteryStatusChanged(const BatteryCallback& callback) { - HandleNewBatteryStatus(callback, GetInternalBatteriesStates(false)); -} - class BatteryStatusObserver { public: explicit BatteryStatusObserver(const BatteryCallback& callback) @@ -220,11 +209,7 @@ private: static void CallOnBatteryStatusChanged(void* callback) { - if (base::FeatureList::IsEnabled(base::features::kReducePPMs)) { - OnBatteryStatusChangedAsync(*static_cast<BatteryCallback*>(callback)); - } else { - OnBatteryStatusChanged(*static_cast<BatteryCallback*>(callback)); - } + OnBatteryStatusChangedAsync(*static_cast<BatteryCallback*>(callback)); } BatteryCallback callback_;
diff --git a/services/device/serial/serial_device_enumerator_android.cc b/services/device/serial/serial_device_enumerator_android.cc index 06e4757..df04752 100644 --- a/services/device/serial/serial_device_enumerator_android.cc +++ b/services/device/serial/serial_device_enumerator_android.cc
@@ -12,7 +12,6 @@ #include "base/feature_list.h" #include "base/no_destructor.h" #include "components/device_event_log/device_event_log.h" -#include "device/base/features.h" #include "services/device/serial/serial_io_handler_android.h" // Must come after all headers that specialize FromJniType() / ToJniType(). @@ -25,9 +24,6 @@ : task_runner_(base::SequencedTaskRunner::GetCurrentDefault()) {} void SerialDeviceEnumeratorAndroid::Initialize() { - if (!base::FeatureList::IsEnabled(features::kWebSerialWiredDevicesAndroid)) { - return; - } JNIEnv* env = AttachCurrentThread(); j_serial_manager_.Reset( Java_ChromeSerialManager_create(env, reinterpret_cast<int64_t>(this)));
diff --git a/services/network/public/cpp/features.cc b/services/network/public/cpp/features.cc index 6027eb5..234405d9 100644 --- a/services/network/public/cpp/features.cc +++ b/services/network/public/cpp/features.cc
@@ -558,7 +558,7 @@ base::FEATURE_ENABLED_BY_DEFAULT); BASE_FEATURE(kCacheSharingForPervasiveResources, - base::FEATURE_DISABLED_BY_DEFAULT); + base::FEATURE_ENABLED_BY_DEFAULT); BASE_FEATURE(kSendSameSiteLaxForFedCM, base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/services/viz/privileged/mojom/BUILD.gn b/services/viz/privileged/mojom/BUILD.gn index df9b6c2..e61d1f80 100644 --- a/services/viz/privileged/mojom/BUILD.gn +++ b/services/viz/privileged/mojom/BUILD.gn
@@ -34,12 +34,14 @@ sources = [ "mojom_traits_unittest.cc" ] deps = [ + "//base/test:fuzztest_support", "//base/test:test_support", "//components/viz/common", "//media/capture/mojom:video_capture", "//services/service_manager/public/cpp", "//services/viz/privileged/mojom/compositing", "//testing/gtest", + "//third_party/fuzztest", "//ui/gfx:test_support", ] }
diff --git a/services/viz/privileged/mojom/DEPS b/services/viz/privileged/mojom/DEPS index 3675567..23fca17 100644 --- a/services/viz/privileged/mojom/DEPS +++ b/services/viz/privileged/mojom/DEPS
@@ -2,3 +2,9 @@ "+components/viz", "+ui/gfx/mojom/color_space_mojom_traits.h", ] + +specific_include_rules = { + ".*unittest\.cc": [ + "+third_party/fuzztest/src/fuzztest/fuzztest.h", + ], +}
diff --git a/services/viz/privileged/mojom/mojom_traits_unittest.cc b/services/viz/privileged/mojom/mojom_traits_unittest.cc index 989aa93..326b531 100644 --- a/services/viz/privileged/mojom/mojom_traits_unittest.cc +++ b/services/viz/privileged/mojom/mojom_traits_unittest.cc
@@ -4,15 +4,159 @@ #include <utility> +#include "build/build_config.h" +#include "components/viz/common/buildflags.h" #include "components/viz/common/display/renderer_settings.h" #include "services/viz/privileged/mojom/compositing/renderer_settings.mojom.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/fuzztest/src/fuzztest/fuzztest.h" #include "ui/gfx/mojom/color_space_mojom_traits.h" namespace viz { namespace { +#if BUILDFLAG(IS_OZONE) +auto AnyOverlayStrategy() { + return fuzztest::ElementOf({OverlayStrategy::kFullscreen, + OverlayStrategy::kSingleOnTop, + OverlayStrategy::kUnderlay +#if BUILDFLAG(ENABLE_CAST_OVERLAY_STRATEGY) + , + OverlayStrategy::kUnderlayCast +#endif + }); +} +#endif + +auto AnyOcclusionCullerSettings() { + return fuzztest::Map( + [](int maximum_occluder_complexity, int quad_split_limit, + int minimum_fragments_reduced, int occluder_minium_visible_quad_size, + bool generate_complex_occluder_for_rounded_corners, + int minumum_quad_size_with_rounded_corners) { + RendererSettings::OcclusionCullerSettings settings; + settings.maximum_occluder_complexity = maximum_occluder_complexity; + settings.quad_split_limit = quad_split_limit; + settings.minimum_fragments_reduced = minimum_fragments_reduced; + settings.occluder_minium_visible_quad_size = + occluder_minium_visible_quad_size; + settings.generate_complex_occluder_for_rounded_corners = + generate_complex_occluder_for_rounded_corners; + settings.minumum_quad_size_with_rounded_corners = + minumum_quad_size_with_rounded_corners; + return settings; + }, + fuzztest::Arbitrary<int>(), fuzztest::Arbitrary<int>(), + fuzztest::Arbitrary<int>(), fuzztest::Arbitrary<int>(), + fuzztest::Arbitrary<bool>(), fuzztest::Arbitrary<int>()); +} + +auto AnyRendererSettings() { + return fuzztest::Map( + [](bool allow_antialiasing, bool force_antialiasing, + bool force_blending_with_shaders, bool partial_swap_enabled, + bool should_clear_root_render_pass, + bool release_overlay_resources_after_gpu_query, + bool dont_round_texture_sizes_for_pixel_tests, int highp_threshold_min, + bool auto_resize_output_surface, bool requires_alpha_channel, + bool disable_render_pass_bypassing, + bool force_non_scanout_backing_for_pixel_tests, + int slow_down_compositing_scale_factor, + RendererSettings::OcclusionCullerSettings occlusion_culler_settings +#if BUILDFLAG(IS_OZONE) + , + const std::vector<OverlayStrategy>& overlay_strategies +#endif +#if BUILDFLAG(IS_MAC) + , + int64_t display_id +#endif + ) { + RendererSettings settings; + settings.allow_antialiasing = allow_antialiasing; + settings.force_antialiasing = force_antialiasing; + settings.force_blending_with_shaders = force_blending_with_shaders; + settings.partial_swap_enabled = partial_swap_enabled; + settings.should_clear_root_render_pass = should_clear_root_render_pass; + settings.release_overlay_resources_after_gpu_query = + release_overlay_resources_after_gpu_query; + settings.dont_round_texture_sizes_for_pixel_tests = + dont_round_texture_sizes_for_pixel_tests; + settings.highp_threshold_min = highp_threshold_min; + settings.auto_resize_output_surface = auto_resize_output_surface; + settings.requires_alpha_channel = requires_alpha_channel; + settings.disable_render_pass_bypassing = disable_render_pass_bypassing; + settings.force_non_scanout_backing_for_pixel_tests = + force_non_scanout_backing_for_pixel_tests; + settings.slow_down_compositing_scale_factor = + slow_down_compositing_scale_factor; + settings.occlusion_culler_settings = occlusion_culler_settings; +#if BUILDFLAG(IS_OZONE) + settings.overlay_strategies = overlay_strategies; +#endif +#if BUILDFLAG(IS_MAC) + settings.display_id = display_id; +#endif + return settings; + }, + fuzztest::Arbitrary<bool>(), fuzztest::Arbitrary<bool>(), + fuzztest::Arbitrary<bool>(), fuzztest::Arbitrary<bool>(), + fuzztest::Arbitrary<bool>(), fuzztest::Arbitrary<bool>(), + fuzztest::Arbitrary<bool>(), fuzztest::Arbitrary<int>(), + fuzztest::Arbitrary<bool>(), fuzztest::Arbitrary<bool>(), + fuzztest::Arbitrary<bool>(), fuzztest::Arbitrary<bool>(), + fuzztest::Arbitrary<int>(), AnyOcclusionCullerSettings() +#if BUILDFLAG(IS_OZONE) + , + fuzztest::VectorOf(AnyOverlayStrategy()) +#endif +#if BUILDFLAG(IS_MAC) + , + fuzztest::Arbitrary<int64_t>() +#endif + ); +} + +auto AnyDebugRendererSettings() { + return fuzztest::Map( + [](bool tint_composited_content, bool tint_composited_content_modulate, + bool show_overdraw_feedback, bool show_dc_layer_debug_borders, + bool show_aggregated_damage) { + DebugRendererSettings settings; + settings.tint_composited_content = tint_composited_content; + settings.tint_composited_content_modulate = + tint_composited_content_modulate; + settings.show_overdraw_feedback = show_overdraw_feedback; + settings.show_dc_layer_debug_borders = show_dc_layer_debug_borders; + settings.show_aggregated_damage = show_aggregated_damage; + return settings; + }, + fuzztest::Arbitrary<bool>(), fuzztest::Arbitrary<bool>(), + fuzztest::Arbitrary<bool>(), fuzztest::Arbitrary<bool>(), + fuzztest::Arbitrary<bool>()); +} + +} // namespace + +void RendererSettingsFuzz(const RendererSettings& input) { + RendererSettings output; + mojom::RendererSettings::Deserialize( + mojom::RendererSettings::Serialize(&input), &output); +} +FUZZ_TEST(StructTraitsTest, RendererSettingsFuzz) + .WithDomains(AnyRendererSettings()); + +void DebugRendererSettingsFuzz(const DebugRendererSettings& input) { + DebugRendererSettings output; + mojom::DebugRendererSettings::Deserialize( + mojom::DebugRendererSettings::Serialize(&input), &output); +} +FUZZ_TEST(StructTraitsTest, DebugRendererSettingsFuzz) + .WithDomains(AnyDebugRendererSettings()); + +namespace { + using StructTraitsTest = testing::Test; TEST_F(StructTraitsTest, RendererSettings) {
diff --git a/services/webnn/webnn_context_impl.cc b/services/webnn/webnn_context_impl.cc index a1c2441f..9456b2b6 100644 --- a/services/webnn/webnn_context_impl.cc +++ b/services/webnn/webnn_context_impl.cc
@@ -120,9 +120,6 @@ WebNNContextImpl::~WebNNContextImpl() { for (auto impl : tensor_impls_) { - // Close all tensor pipes explicitly so no response callbacks are pending as - // Mojo forbids callbacks that are pending during destruction. - impl->ResetMojoReceiver(); // Delete non-interop tensor instances from the tracker as they can't // unregister themselves since they're ref-counted and might outlive the // context. @@ -147,6 +144,20 @@ } void WebNNContextImpl::OnDisconnect() { + // Explicitly reset all tensor and graph receivers before destruction since + // destroying bound receivers can cause Mojo to DCHECK due to pending + // callbacks or if destruction occurs on a different runner than the bound + // runner. + for (auto impl : tensor_impls_) { + impl->ResetMojoReceiver(); + } + + for (auto impl : graph_impls_) { + impl->ResetMojoReceiver(); + } + + ResetMojoReceiver(); + base::OnceClosure remove_task; #if BUILDFLAG(WEBNN_USE_TFLITE) || BUILDFLAG(WEBNN_USE_LITERT) if (is_tflite_context_provider_) { @@ -506,13 +517,9 @@ } void WebNNContextImpl::OnLost(const std::string& reason) { - RunOrScheduleTaskWithThisContext(base::BindOnce( - [](const std::string& reason, WebNNContextImpl& self) { - self.GetMojoReceiver().ResetWithReason( - /*custom_reason_code=*/0, reason); - self.OnDisconnect(); - }, - reason)); + DCHECK(task_runner()->RunsTasksInCurrentSequence()); + ResetMojoReceiver(reason); + OnDisconnect(); } void WebNNContextImpl::RunOrScheduleTaskWithThisContext(
diff --git a/services/webnn/webnn_graph_builder_impl_unittest.cc b/services/webnn/webnn_graph_builder_impl_unittest.cc index 0687e6d..09cf4c8 100644 --- a/services/webnn/webnn_graph_builder_impl_unittest.cc +++ b/services/webnn/webnn_graph_builder_impl_unittest.cc
@@ -245,6 +245,10 @@ graph_builder_remote_.BindNewEndpointAndPassReceiver()); } void TearDown() override { + // Give WebNNContext a chance to disconnect. + webnn_context_.reset(); + webnn_test_environment_.RunUntilIdle(); + WebNNContextProviderImpl::SetBackendForTesting(nullptr); }
diff --git a/services/webnn/webnn_graph_impl.cc b/services/webnn/webnn_graph_impl.cc index 57871cb..e5d5a9b 100644 --- a/services/webnn/webnn_graph_impl.cc +++ b/services/webnn/webnn_graph_impl.cc
@@ -110,6 +110,7 @@ WebNNGraphImpl::~WebNNGraphImpl() = default; void WebNNGraphImpl::OnDisconnect() { + ResetMojoReceiver(); context_->RemoveWebNNGraphImpl(handle()); }
diff --git a/services/webnn/webnn_graph_impl_backend_test.cc b/services/webnn/webnn_graph_impl_backend_test.cc index a360729f..e112955c 100644 --- a/services/webnn/webnn_graph_impl_backend_test.cc +++ b/services/webnn/webnn_graph_impl_backend_test.cc
@@ -443,10 +443,9 @@ } void WebNNGraphImplBackendTest::TearDown() { - webnn_context_.reset(); - EXPECT_TRUE(base::test::RunUntil([&]() { return true; })); // Give WebNNContext a chance to run disconnect. - provider_remote_.reset(); + webnn_context_.reset(); + webnn_test_environment_.RunUntilIdle(); } mojo::AssociatedRemote<mojom::WebNNGraphBuilder>
diff --git a/services/webnn/webnn_graph_impl_fuzzer.cc b/services/webnn/webnn_graph_impl_fuzzer.cc index 4f54d4f..372b80d 100644 --- a/services/webnn/webnn_graph_impl_fuzzer.cc +++ b/services/webnn/webnn_graph_impl_fuzzer.cc
@@ -1366,10 +1366,9 @@ } void WebNNGraphImplFuzzerBase::TearDown() { - context_.reset(); - EXPECT_TRUE(base::test::RunUntil([&]() { return true; })); // Give WebNNContext a chance to run disconnect. - provider_remote_.reset(); + context_.reset(); + GetGlobalFuzzEnvironment().GetWebNNTestEnvironment().RunUntilIdle(); } mojo::AssociatedRemote<mojom::WebNNGraphBuilder>
diff --git a/services/webnn/webnn_graph_impl_unittest.cc b/services/webnn/webnn_graph_impl_unittest.cc index 158948c..47ed9ceb 100644 --- a/services/webnn/webnn_graph_impl_unittest.cc +++ b/services/webnn/webnn_graph_impl_unittest.cc
@@ -339,6 +339,10 @@ } void TearDown() override { + // Give WebNNContext a chance to disconnect. + webnn_context_.reset(); + webnn_test_environment_.RunUntilIdle(); + WebNNContextProviderImpl::SetBackendForTesting(nullptr); }
diff --git a/services/webnn/webnn_object_impl.h b/services/webnn/webnn_object_impl.h index f11ac99..243e6f4 100644 --- a/services/webnn/webnn_object_impl.h +++ b/services/webnn/webnn_object_impl.h
@@ -50,7 +50,13 @@ // responses. void ResetMojoReceiver() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - mojo_receiver_.reset(); + GetMojoReceiver().reset(); + } + + // Similar to the method above, but also specifies a disconnect reason. + void ResetMojoReceiver(std::string_view description) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + GetMojoReceiver().ResetWithReason(/*custom_reason_code=*/0, description); } protected: @@ -58,31 +64,40 @@ template <typename MojoPendingReceiverType> WebNNObjectBase(MojoPendingReceiverType pending_receiver, scoped_refptr<base::SequencedTaskRunner> task_runner) - : mojo_receiver_(this, - std::move(pending_receiver), - std::move(task_runner)) { + : task_runner_(std::move(task_runner)), + mojo_receiver_(this, std::move(pending_receiver), task_runner_) { mojo_receiver_.set_disconnect_handler(base::BindOnce( &WebNNObjectType::OnDisconnect, weak_factory_.GetWeakPtr())); } ~WebNNObjectBase() override { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + // The receiver must be explicitly reset via ResetMojoReceiver() on + // `task_runner_` before destruction. Implicitly destroying a bound + // receiver may DCHECK in Mojo if destruction occurs on a different runner. + DCHECK(!mojo_receiver_.is_bound()) + << "Receiver must be reset before destruction."; } // Returns the AssociatedReceiver bound to this implementation. - // Only legal to call from within the stack frame of a message dispatch. MojoReceiverType& GetMojoReceiver() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(task_runner_); + DCHECK(task_runner_->RunsTasksInCurrentSequence()); return mojo_receiver_; } protected: // This SequenceChecker is bound to the sequence where WebNNObjectBase is - // constructed. All messages dispatches must occur on this sequence. + // constructed. All message dispatches must occur on this sequence. SEQUENCE_CHECKER(sequence_checker_); const WebNNTokenType handle_; + // The task runner on which the Mojo receiver is bound and must be used to + // reset. + const scoped_refptr<base::SequencedTaskRunner> task_runner_; + MojoReceiverType mojo_receiver_ GUARDED_BY_CONTEXT(sequence_checker_); base::WeakPtrFactory<WebNNObjectType> weak_factory_
diff --git a/services/webnn/webnn_tensor_impl.cc b/services/webnn/webnn_tensor_impl.cc index 07952163..4419a6a 100644 --- a/services/webnn/webnn_tensor_impl.cc +++ b/services/webnn/webnn_tensor_impl.cc
@@ -227,6 +227,7 @@ } void WebNNTensorImpl::OnDisconnect() { + ResetMojoReceiver(); context_->RemoveWebNNTensorImpl(handle()); }
diff --git a/services/webnn/webnn_tensor_impl_backend_test.cc b/services/webnn/webnn_tensor_impl_backend_test.cc index b77e783..54f2c8f 100644 --- a/services/webnn/webnn_tensor_impl_backend_test.cc +++ b/services/webnn/webnn_tensor_impl_backend_test.cc
@@ -123,9 +123,8 @@ #endif // BUILDFLAG(WEBNN_USE_TFLITE) || BUILDFLAG(WEBNN_USE_LITERT) void WebNNTensorImplBackendTest::TearDown() { - base::RunLoop().RunUntilIdle(); // Give WebNNContext a chance to disconnect. - webnn_provider_remote_.reset(); + webnn_test_environment_.RunUntilIdle(); } base::expected<CreateContextSuccess, webnn::mojom::Error::Code>
diff --git a/testing/perf/cbb_ref_info/edge/dev/windows.json b/testing/perf/cbb_ref_info/edge/dev/windows.json index 47e203b3..bb548c9c 100644 --- a/testing/perf/cbb_ref_info/edge/dev/windows.json +++ b/testing/perf/cbb_ref_info/edge/dev/windows.json
@@ -2,5 +2,5 @@ "browser": "edge", "channel": "dev", "platform": "windows", - "version": "149.0.3993.0" + "version": "149.0.4009.0" } \ No newline at end of file
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 6071b8d..6305ae6 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -4730,26 +4730,6 @@ ] } ], - "CacheSharingForPervasiveResources": [ - { - "platforms": [ - "android", - "android_webview", - "chromeos", - "linux", - "mac", - "windows" - ], - "experiments": [ - { - "name": "Enabled", - "enable_features": [ - "CacheSharingForPervasiveResources" - ] - } - ] - } - ], "Canvas2DAutoFlushParams": [ { "platforms": [ @@ -8341,7 +8321,7 @@ { "name": "Enabled_20260427", "params": { - "mode": "1" + "tab_grid_setup_mode": "deferred" }, "enable_features": [ "TabGridSetupMode" @@ -8690,6 +8670,24 @@ ] } ], + "DesktopOmniboxHideAimUrl": [ + { + "platforms": [ + "chromeos", + "linux", + "mac", + "windows" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "HideAimEntrypointForUrlSuggestions" + ] + } + ] + } + ], "DesktopOmniboxRichAutocompletionMinChar": [ { "platforms": [ @@ -16501,19 +16499,17 @@ ] } ], - "NetworkServiceThreadIncreasedPriority": [ + "NetworkServiceThreadIncreasedPriorityV2": [ { "platforms": [ "android" ], "experiments": [ { - "name": "WhileLoading_20260309", + "name": "WhileLoadingAndDuringStartup", "enable_features": [ + "NetworkServiceIncreasedPriorityDuringStartup", "NetworkServiceIncreasedPriorityWhileLoading" - ], - "disable_features": [ - "NetworkServiceIncreasedPriorityAlways" ] } ] @@ -19064,6 +19060,23 @@ ] } ], + "PreemptiveSodaDownload": [ + { + "platforms": [ + "linux", + "mac", + "windows" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "PreemptiveSodaDownload" + ] + } + ] + } + ], "PrefetchBlockUntilHeadTimeoutForWebViewPrefetch": [ { "platforms": [ @@ -25923,21 +25936,6 @@ ] } ], - "WebSerialWiredDevicesAndroid": [ - { - "platforms": [ - "android" - ], - "experiments": [ - { - "name": "Enabled_20260302", - "enable_features": [ - "WebSerialWiredDevicesAndroid" - ] - } - ] - } - ], "WebSigninLoadingDialog": [ { "platforms": [
diff --git a/third_party/angle b/third_party/angle index 80b4ac8..3cd478b 160000 --- a/third_party/angle +++ b/third_party/angle
@@ -1 +1 @@ -Subproject commit 80b4ac89a93da6906d7d7ab93d08bb36b84b8bf6 +Subproject commit 3cd478b595cb98a6f1283876aadea5fc0a9543f8
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc index f123082..09d2e12 100644 --- a/third_party/blink/common/features.cc +++ b/third_party/blink/common/features.cc
@@ -2494,9 +2494,6 @@ BASE_FEATURE(kSubSampleWindowProxyUsageMetrics, base::FEATURE_ENABLED_BY_DEFAULT); -BASE_FEATURE(kSupportOpeningDraggedLinksInSameTab, - base::FEATURE_DISABLED_BY_DEFAULT); - BASE_FEATURE(kTaskAttributionTraceMicrotaskTaskState, base::FEATURE_ENABLED_BY_DEFAULT);
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h index 1c2c027..2852fb2b 100644 --- a/third_party/blink/public/common/features.h +++ b/third_party/blink/public/common/features.h
@@ -1870,8 +1870,6 @@ // Subsample a very chatty UKM metric. BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kSubSampleWindowProxyUsageMetrics); -BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kSupportOpeningDraggedLinksInSameTab); - // When enabled, task state traces are emitted for microtasks when the // "task_attribution" trace category is enabled. BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(
diff --git a/third_party/blink/public/mojom/use_counter/metrics/webdx_feature.mojom b/third_party/blink/public/mojom/use_counter/metrics/webdx_feature.mojom index b43081d..f91362f6 100644 --- a/third_party/blink/public/mojom/use_counter/metrics/webdx_feature.mojom +++ b/third_party/blink/public/mojom/use_counter/metrics/webdx_feature.mojom
@@ -498,6 +498,7 @@ kWebgl2 = 434, kDigitalCredentials = 435, kMediaPseudos = 436, + kGapDecorations = 437, // Add new features immediately above this line. Don't change assigned // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc index 9b0c8a4..e0e5724a 100644 --- a/third_party/blink/renderer/core/dom/element.cc +++ b/third_party/blink/renderer/core/dom/element.cc
@@ -1177,8 +1177,19 @@ cloned_shadow_root.SetKeepCustomElementRegistryNull( shadow_root->ShouldKeepCustomElementRegistryNull()); - // TODO(crbug.com/448174611): Re-process the shadowrootadoptedstylesheets - // attribute value on the cloned shadow root. + // Re-resolve the shadowrootadoptedstylesheets attribute against the + // cloned shadow root so that `adoptedStyleSheets` is populated. Note that + // this will not preserve any modifications made to the + // `adoptedStyleSheets`. + if (RuntimeEnabledFeatures::ShadowRootAdoptedStyleSheetEnabled( + factory.GetExecutionContext())) { + const AtomicString& adopted_stylesheets_value = + shadow_root->AdoptedStylesheetsAttributeValue(); + if (!adopted_stylesheets_value.IsNull()) { + cloned_shadow_root.ProcessAdoptedStylesheetAttribute( + adopted_stylesheets_value); + } + } // 6.6 If the clone children flag is set, then for each child child of // node’s shadow root, in tree order: append the result of cloning child
diff --git a/third_party/blink/renderer/core/frame/scroll_into_view_options.idl b/third_party/blink/renderer/core/frame/scroll_into_view_options.idl index 3ff462c1..efee845 100644 --- a/third_party/blink/renderer/core/frame/scroll_into_view_options.idl +++ b/third_party/blink/renderer/core/frame/scroll_into_view_options.idl
@@ -1,8 +1,8 @@ -enum ScrollLogicalPosition { "start", "center", "end", "nearest" }; +enum ScrollLogicalPosition { "start", "center", "end", "nearest", "auto" }; enum ScrollContainer { "all", "nearest" }; dictionary ScrollIntoViewOptions : ScrollOptions { - ScrollLogicalPosition block = "start"; - [ImplementedAs=inlinePosition] ScrollLogicalPosition inline = "nearest"; + ScrollLogicalPosition block = "auto"; + [ImplementedAs=inlinePosition] ScrollLogicalPosition inline = "auto"; [RuntimeEnabled=ScrollIntoViewNearest] ScrollContainer container = "all"; };
diff --git a/third_party/blink/renderer/core/html/parser/html_construction_site.cc b/third_party/blink/renderer/core/html/parser/html_construction_site.cc index d340b2ca..32541905 100644 --- a/third_party/blink/renderer/core/html/parser/html_construction_site.cc +++ b/third_party/blink/renderer/core/html/parser/html_construction_site.cc
@@ -613,6 +613,21 @@ void HTMLConstructionSite::InsertHTMLBodyStartTagInBody( AtomicHTMLToken* token) { MergeAttributesFromTokenIntoElement(token, open_elements_.BodyElement()); + // The customelementregistry attribute detection in CreateElement does not + // apply here because this path does not call CreateElement. This method is + // called when a <body> start tag is encountered while a body element already + // exists on the open elements stack (e.g., an implicit body was created by + // DefaultForAfterHead). In that case, the parser only merges attributes onto + // the existing body element rather than creating a new one, so we must + // handle the customelementregistry attribute explicitly. + if (RuntimeEnabledFeatures::ScopedCustomElementRegistryEnabled() && + token->GetAttributeItem(html_names::kCustomelementregistryAttr)) { + Element* body = open_elements_.BodyElement(); + body->SetCustomElementRegistry(nullptr); + if (document_) { + document_->SetScopedCustomElementRegistryUsed(); + } + } } void HTMLConstructionSite::SetDefaultCompatibilityMode() {
diff --git a/third_party/blink/renderer/core/layout/box_fragment_builder.cc b/third_party/blink/renderer/core/layout/box_fragment_builder.cc index 2717fef5..a4afbb8 100644 --- a/third_party/blink/renderer/core/layout/box_fragment_builder.cc +++ b/third_party/blink/renderer/core/layout/box_fragment_builder.cc
@@ -4,6 +4,7 @@ #include "third_party/blink/renderer/core/layout/box_fragment_builder.h" +#include "third_party/blink/public/mojom/use_counter/metrics/webdx_feature.mojom-blink.h" #include "third_party/blink/renderer/core/layout/block_break_token.h" #include "third_party/blink/renderer/core/layout/block_node.h" #include "third_party/blink/renderer/core/layout/break_token.h" @@ -826,4 +827,12 @@ #endif +void BoxFragmentBuilder::SetGapGeometry(const GapGeometry* gap_geometry) { + if (gap_geometry) { + layout_object_->GetDocument().CountWebDXFeature( + mojom::blink::WebDXFeature::kGapDecorations); + } + gap_geometry_ = gap_geometry; +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/box_fragment_builder.h b/third_party/blink/renderer/core/layout/box_fragment_builder.h index ed170df0..3bd93ec 100644 --- a/third_party/blink/renderer/core/layout/box_fragment_builder.h +++ b/third_party/blink/renderer/core/layout/box_fragment_builder.h
@@ -641,9 +641,7 @@ use_last_baseline_for_inline_baseline_ = true; } - void SetGapGeometry(const GapGeometry* gap_geometry) { - gap_geometry_ = gap_geometry; - } + void SetGapGeometry(const GapGeometry* gap_geometry); const GapGeometry* GetGapGeometry() const { return gap_geometry_; }
diff --git a/third_party/blink/renderer/core/layout/layout_utils.cc b/third_party/blink/renderer/core/layout/layout_utils.cc index 7dc92fe1..44076dd 100644 --- a/third_party/blink/renderer/core/layout/layout_utils.cc +++ b/third_party/blink/renderer/core/layout/layout_utils.cc
@@ -207,71 +207,83 @@ LayoutUnit block_size = fragment_geometry.border_box_size.block_size; bool is_initial_block_size_indefinite = block_size == kIndefiniteSize; if (is_initial_block_size_indefinite) { - LayoutUnit intrinsic_block_size; - // Intrinsic block-size is only defined if the node is unfragmented. - if (!physical_fragment.IsFirstForNode() || - physical_fragment.GetBreakToken()) { - intrinsic_block_size = kIndefiniteSize; - } else { - intrinsic_block_size = layout_result.IntrinsicBlockSize(); - } - - // Grid/flex/fieldset/grid-lanes can have their children calculate their - // size based on their parent's final block-size. E.g. - // - // <div style="display: flex;"> - // <div style="display: flex;"> <!-- or "display: grid;" --> - // <!-- Child will stretch to the parent's block-size --> - // <div></div> - // </div> - // </div> - // <div style="display: flex;"> - // <div style="display: flex; flex-direction: column;"> - // <!-- Child will grow to the parent's fixed block-size --> - // <div style="flex: 1;"></div> - // </div> - // </div> - // - // If the previous |layout_result| was produced by a space which had a - // fixed block-size we can't use |intrinsic_block_size| for determining - // the new block-size. - // - // TODO(ikilpatrick): Similar to %-block-size descendants we could store a - // bit on the |LayoutResult| which indicates if it had a child which - // sized itself based on the parent's block-size. - // We should consider this optimization if we are missing this cache often - // within this branch (and could have re-used the result). - // TODO(ikilaptrick): This may occur for other layout modes, e.g. - // custom-layout. - if (old_space.IsFixedBlockSize() || - (old_space.IsBlockAutoBehaviorStretch() && - style.LogicalHeight().HasAuto())) { - if (node.IsFlexibleBox() || node.IsGrid() || node.IsGridLanes() || - node.IsFieldsetContainer()) { - intrinsic_block_size = kIndefiniteSize; + LayoutUnit intrinsic_block_size = [&]() { + // Intrinsic block-size is only defined if the node is unfragmented. + if (!physical_fragment.IsFirstForNode() || + physical_fragment.GetBreakToken()) { + return kIndefiniteSize; } - } - // Grid/flex/grid-lanes can have their intrinsic block-size depend on the - // %-block-size. This occurs when: - // - A column flex-box has "max-height: 100%" (or similar) on itself. - // - A row flex-box has "height: 100%" (or similar) and children which - // stretch to this size. - // - A grid/grid-lanes with "grid-template-rows: repeat(auto-fill, 50px)" - // or similar. - // - // Similar to above we can't use the |intrinsic_block_size| for determining - // the new block-size. - // - // TODO(dgrogan): We can hit the cache here for row flexboxes when they - // don't have stretchy children. - if (physical_fragment.DependsOnPercentageBlockSize() && - new_space.PercentageResolutionBlockSize() != - old_space.PercentageResolutionBlockSize()) { - if (node.IsFlexibleBox() || node.IsGrid() || node.IsGridLanes()) { - intrinsic_block_size = kIndefiniteSize; + if (physical_fragment.IsFragmentationContextRoot() && + style.LogicalMaxHeight().HasPercentOrStretch() && + style.LogicalHeight().HasAuto()) { + // If this is a multicol container, and `block-size` is auto, + // `max-block-size:stretch` (or a percentage value) may have caused the + // block-size of the multicol container to shrink. This affects the + // so-called "intrinsic" block-size, so that it's unusable for cache + // hitting in this case. + return kIndefiniteSize; } - } + + // Grid/flex/fieldset/grid-lanes can have their children calculate their + // size based on their parent's final block-size. E.g. + // + // <div style="display: flex;"> + // <div style="display: flex;"> <!-- or "display: grid;" --> + // <!-- Child will stretch to the parent's block-size --> + // <div></div> + // </div> + // </div> + // <div style="display: flex;"> + // <div style="display: flex; flex-direction: column;"> + // <!-- Child will grow to the parent's fixed block-size --> + // <div style="flex: 1;"></div> + // </div> + // </div> + // + // If the previous |layout_result| was produced by a space which had a + // fixed block-size we can't use |intrinsic_block_size| for determining + // the new block-size. + // + // TODO(ikilpatrick): Similar to %-block-size descendants we could store a + // bit on the |LayoutResult| which indicates if it had a child which + // sized itself based on the parent's block-size. + // We should consider this optimization if we are missing this cache often + // within this branch (and could have re-used the result). + // TODO(ikilaptrick): This may occur for other layout modes, e.g. + // custom-layout. + if (old_space.IsFixedBlockSize() || + (old_space.IsBlockAutoBehaviorStretch() && + style.LogicalHeight().HasAuto())) { + if (node.IsFlexibleBox() || node.IsGrid() || node.IsGridLanes() || + node.IsFieldsetContainer()) { + return kIndefiniteSize; + } + } + + // Grid/flex/grid-lanes can have their intrinsic block-size depend on the + // %-block-size. This occurs when: + // - A column flex-box has "max-height: 100%" (or similar) on itself. + // - A row flex-box has "height: 100%" (or similar) and children which + // stretch to this size. + // - A grid/grid-lanes with "grid-template-rows: repeat(auto-fill, 50px)" + // or similar. + // + // Similar to above we can't use the |intrinsic_block_size| for + // determining the new block-size. + // + // TODO(dgrogan): We can hit the cache here for row flexboxes when they + // don't have stretchy children. + if (physical_fragment.DependsOnPercentageBlockSize() && + new_space.PercentageResolutionBlockSize() != + old_space.PercentageResolutionBlockSize()) { + if (node.IsFlexibleBox() || node.IsGrid() || node.IsGridLanes()) { + return kIndefiniteSize; + } + } + + return layout_result.IntrinsicBlockSize(); + }(); block_size = ComputeBlockSizeForFragment( new_space, node, fragment_geometry.border + fragment_geometry.padding,
diff --git a/third_party/blink/renderer/core/loader/progress_tracker.cc b/third_party/blink/renderer/core/loader/progress_tracker.cc index 280c3ef..22b1013 100644 --- a/third_party/blink/renderer/core/loader/progress_tracker.cc +++ b/third_party/blink/renderer/core/loader/progress_tracker.cc
@@ -116,6 +116,10 @@ MaybeSendProgress(); } +void ProgressTracker::DidNavigationApiIntercept() { + MaybeSendProgress(); +} + void ProgressTracker::SendFinalProgress() { if (progress_value_ == 1) return;
diff --git a/third_party/blink/renderer/core/loader/progress_tracker.h b/third_party/blink/renderer/core/loader/progress_tracker.h index 35c82bc..ef0cef8 100644 --- a/third_party/blink/renderer/core/loader/progress_tracker.h +++ b/third_party/blink/renderer/core/loader/progress_tracker.h
@@ -69,6 +69,7 @@ void FinishedParsing(); void DidFirstContentfulPaint(); + void DidNavigationApiIntercept(); void WillStartLoading(uint64_t identifier, ResourceLoadPriority); void IncrementProgress(uint64_t identifier, const ResourceResponse&);
diff --git a/third_party/blink/renderer/core/loader/progress_tracker_test.cc b/third_party/blink/renderer/core/loader/progress_tracker_test.cc index c9f62e1..dde6c96 100644 --- a/third_party/blink/renderer/core/loader/progress_tracker_test.cc +++ b/third_party/blink/renderer/core/loader/progress_tracker_test.cc
@@ -179,4 +179,31 @@ EXPECT_EQ(1.0, WaitForNextProgressChange()); } +TEST_F(ProgressTrackerTest, NavigationApiInterceptBeforeCompletion) { + Progress().ProgressStarted(); + EXPECT_EQ(0.0, LastProgress()); + + Progress().DidFirstContentfulPaint(); + EXPECT_EQ(0.8, WaitForNextProgressChange()); + + Progress().DidNavigationApiIntercept(); + EXPECT_EQ(0.8, LastProgress()); + + Progress().ProgressCompleted(); + EXPECT_EQ(1.0, WaitForNextProgressChange()); +} + +TEST_F(ProgressTrackerTest, NavigationApiInterceptAfterCompletion) { + Progress().ProgressStarted(); + EXPECT_EQ(0.0, LastProgress()); + Progress().ProgressCompleted(); + EXPECT_EQ(1.0, WaitForNextProgressChange()); + + Progress().ProgressStarted(); + Progress().DidNavigationApiIntercept(); + EXPECT_EQ(0.7, WaitForNextProgressChange()); + Progress().ProgressCompleted(); + EXPECT_EQ(1.0, WaitForNextProgressChange()); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/navigation_api/navigate_event.cc b/third_party/blink/renderer/core/navigation_api/navigate_event.cc index 218e29ab..b68f925 100644 --- a/third_party/blink/renderer/core/navigation_api/navigate_event.cc +++ b/third_party/blink/renderer/core/navigation_api/navigate_event.cc
@@ -518,6 +518,9 @@ dispatch_params_->should_skip_screenshot, dispatch_params_->involvement, dispatch_params_->interaction_id, dispatch_params_->is_browser_initiated, dispatch_params_->is_synchronously_committed_same_document); + if (LocalDOMWindow* window = DomWindow()) { + window->GetFrame()->Loader().Progress().DidNavigationApiIntercept(); + } React(script_state); } @@ -623,9 +626,14 @@ delayed_load_start_task_handle_.Cancel(); if (!defaultPrevented()) { switch (intercept_state_) { - case InterceptState::kIntercepted: - DomWindow()->GetFrame()->Client()->DidFailAsyncSameDocumentCommit(); + case InterceptState::kIntercepted: { + LocalFrame* frame = DomWindow()->GetFrame(); + if (frame->IsLoading()) { + frame->Loader().Progress().ProgressCompleted(); + } + frame->Client()->DidFailAsyncSameDocumentCommit(); break; + } case InterceptState::kCommitted: DomWindow()->GetFrame()->Loader().Progress().ProgressCompleted(); break;
diff --git a/third_party/blink/renderer/core/page/drag_controller.cc b/third_party/blink/renderer/core/page/drag_controller.cc index 1b3e931..0569273 100644 --- a/third_party/blink/renderer/core/page/drag_controller.cc +++ b/third_party/blink/renderer/core/page/drag_controller.cc
@@ -344,8 +344,6 @@ bool has_transient_user_activation = LocalFrame::HasTransientUserActivation( document_under_mouse_ ? document_under_mouse_->GetFrame() : nullptr); - const bool is_single_link = urls.size() == 1 && !drag_data->ContainsFiles(); - bool should_focus_tab = true; for (const String& url : urls) { ResourceRequest resource_request(url); @@ -363,19 +361,12 @@ FrameLoadRequest request(nullptr, resource_request); // Open the dropped URL in a new tab to avoid potential data-loss in the - // current tab. See https://crbug.com/451659. The feature - // kSupportOpeningDraggedLinksInSameTab explores allowing links to be - // opened in the same tab if the drop data indicates that should be the - // case. - if (!base::FeatureList::IsEnabled( - blink::features::kSupportOpeningDraggedLinksInSameTab) || - !is_single_link) { - // First tab should be focused, the rest should be background tabs. - request.SetNavigationPolicy( - should_focus_tab - ? NavigationPolicy::kNavigationPolicyNewForegroundTab - : NavigationPolicy::kNavigationPolicyNewBackgroundTab); - } + // current tab. See https://crbug.com/451659. + // First tab should be focused, the rest should be background tabs. + request.SetNavigationPolicy( + should_focus_tab + ? NavigationPolicy::kNavigationPolicyNewForegroundTab + : NavigationPolicy::kNavigationPolicyNewBackgroundTab); local_root.Navigate(request, WebFrameLoadType::kStandard); should_focus_tab = false; }
diff --git a/third_party/blink/renderer/core/paint/box_fragment_painter_test.cc b/third_party/blink/renderer/core/paint/box_fragment_painter_test.cc index 4fa9766..4024c77 100644 --- a/third_party/blink/renderer/core/paint/box_fragment_painter_test.cc +++ b/third_party/blink/renderer/core/paint/box_fragment_painter_test.cc
@@ -8,6 +8,7 @@ #include "components/viz/common/surfaces/tracked_element_rects.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/public/mojom/use_counter/metrics/webdx_feature.mojom-blink.h" #include "third_party/blink/renderer/core/layout/block_node.h" #include "third_party/blink/renderer/core/layout/hit_test_location.h" #include "third_party/blink/renderer/core/layout/inline/inline_cursor.h" @@ -414,4 +415,148 @@ 1, 2, tracked_element_data))); } +TEST_P(BoxFragmentPainterTest, GapDecorationsUseCountShorthand) { + SetBodyInnerHTML(R"HTML( + <style> + .container { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 10px; + column-rule: 1px solid red; + } + </style> + <div class="container"> + <div>A</div> + <div>B</div> + </div> + )HTML"); + UpdateAllLifecyclePhasesForTest(); + EXPECT_TRUE(GetDocument().IsWebDXFeatureCounted( + mojom::blink::WebDXFeature::kGapDecorations)); +} + +TEST_P(BoxFragmentPainterTest, GapDecorationsUseCountLonghand) { + SetBodyInnerHTML(R"HTML( + <style> + .container { + display: flex; + flex-wrap: wrap; + width: 200px; + gap: 10px; + column-rule-style: solid; + column-rule-width: 1px; + column-rule-color: red; + } + </style> + <div class="container"> + <div style="width: 80px">A</div> + <div style="width: 80px">B</div> + </div> + )HTML"); + UpdateAllLifecyclePhasesForTest(); + EXPECT_TRUE(GetDocument().IsWebDXFeatureCounted( + mojom::blink::WebDXFeature::kGapDecorations)); +} + +TEST_P(BoxFragmentPainterTest, GapDecorationsUseCountRowRule) { + SetBodyInnerHTML(R"HTML( + <style> + .container { + display: grid; + grid-template-columns: 1fr 1fr; + grid-template-rows: auto auto; + gap: 10px; + row-rule: 1px solid red; + } + </style> + <div class="container"> + <div>A</div> + <div>B</div> + <div>C</div> + <div>D</div> + </div> + )HTML"); + UpdateAllLifecyclePhasesForTest(); + EXPECT_TRUE(GetDocument().IsWebDXFeatureCounted( + mojom::blink::WebDXFeature::kGapDecorations)); +} + +TEST_P(BoxFragmentPainterTest, GapDecorationsUseCountNotCounted) { + SetBodyInnerHTML(R"HTML( + <style> + .container { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 10px; + } + </style> + <div class="container"> + <div>A</div> + <div>B</div> + </div> + )HTML"); + UpdateAllLifecyclePhasesForTest(); + EXPECT_FALSE(GetDocument().IsWebDXFeatureCounted( + mojom::blink::WebDXFeature::kGapDecorations)); +} + +TEST_P(BoxFragmentPainterTest, GapDecorationsUseCountStyleOnly) { + SetBodyInnerHTML(R"HTML( + <style> + .container { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 10px; + column-rule-style: solid; + } + </style> + <div class="container"> + <div>A</div> + <div>B</div> + </div> + )HTML"); + UpdateAllLifecyclePhasesForTest(); + EXPECT_TRUE(GetDocument().IsWebDXFeatureCounted( + mojom::blink::WebDXFeature::kGapDecorations)); +} + +TEST_P(BoxFragmentPainterTest, GapDecorationsUseCountWidthOnlyNotCounted) { + SetBodyInnerHTML(R"HTML( + <style> + .container { + display: flex; + flex-wrap: wrap; + width: 200px; + gap: 10px; + column-rule-width: 3px; + } + </style> + <div class="container"> + <div style="width: 80px">A</div> + <div style="width: 80px">B</div> + </div> + )HTML"); + UpdateAllLifecyclePhasesForTest(); + EXPECT_FALSE(GetDocument().IsWebDXFeatureCounted( + mojom::blink::WebDXFeature::kGapDecorations)); +} + +TEST_P(BoxFragmentPainterTest, GapDecorationsUseCountColorOnlyNotCounted) { + SetBodyInnerHTML(R"HTML( + <style> + .container { + columns: 2; + column-gap: 10px; + column-rule-color: red; + } + </style> + <div class="container"> + <p>Some text content to fill the columns.</p> + </div> + )HTML"); + UpdateAllLifecyclePhasesForTest(); + EXPECT_FALSE(GetDocument().IsWebDXFeatureCounted( + mojom::blink::WebDXFeature::kGapDecorations)); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/scroll/programmatic_scroll_animator.cc b/third_party/blink/renderer/core/scroll/programmatic_scroll_animator.cc index d885211..cbff6af1 100644 --- a/third_party/blink/renderer/core/scroll/programmatic_scroll_animator.cc +++ b/third_party/blink/renderer/core/scroll/programmatic_scroll_animator.cc
@@ -19,9 +19,12 @@ ScrollableArea* scrollable_area) : scrollable_area_(scrollable_area) {} -ProgrammaticScrollAnimator::~ProgrammaticScrollAnimator() { - if (on_finish_) +ProgrammaticScrollAnimator::~ProgrammaticScrollAnimator() = default; + +void ProgrammaticScrollAnimator::Dispose() { + if (on_finish_) { std::move(on_finish_).Run(ScrollableArea::ScrollCompletionMode::kFinished); + } } void ProgrammaticScrollAnimator::ResetAnimationState() {
diff --git a/third_party/blink/renderer/core/scroll/programmatic_scroll_animator.h b/third_party/blink/renderer/core/scroll/programmatic_scroll_animator.h index cf7e9865..a1823bf 100644 --- a/third_party/blink/renderer/core/scroll/programmatic_scroll_animator.h +++ b/third_party/blink/renderer/core/scroll/programmatic_scroll_animator.h
@@ -10,6 +10,7 @@ #include "third_party/blink/renderer/core/scroll/scroll_animator_compositor_coordinator.h" #include "third_party/blink/renderer/core/scroll/scrollable_area.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" +#include "third_party/blink/renderer/platform/heap/prefinalizer.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" namespace blink { @@ -24,6 +25,8 @@ // ScrollAnimatorMac. class ProgrammaticScrollAnimator : public ScrollAnimatorCompositorCoordinator { + USING_PRE_FINALIZER(ProgrammaticScrollAnimator, Dispose); + public: explicit ProgrammaticScrollAnimator(ScrollableArea*); ProgrammaticScrollAnimator(const ProgrammaticScrollAnimator&) = delete; @@ -31,6 +34,8 @@ delete; ~ProgrammaticScrollAnimator() override; + void Dispose(); + void ScrollToOffsetWithoutAnimation(const ScrollOffset&, cc::ScrollSourceType); void AnimateToOffset(const ScrollOffset&,
diff --git a/third_party/blink/renderer/core/scroll/scroll_into_view_util.cc b/third_party/blink/renderer/core/scroll/scroll_into_view_util.cc index 10fd02a..ef84c4a 100644 --- a/third_party/blink/renderer/core/scroll/scroll_into_view_util.cc +++ b/third_party/blink/renderer/core/scroll/scroll_into_view_util.cc
@@ -597,11 +597,18 @@ behavior = mojom::blink::ScrollBehavior::kInstant; } - auto align_x = ResolveToPhysicalAlignment(options.inlinePosition().AsEnum(), - options.block().AsEnum(), + V8ScrollLogicalPosition::Enum block_align = + options.block().AsEnum() == V8ScrollLogicalPosition::Enum::kAuto + ? V8ScrollLogicalPosition::Enum::kStart + : options.block().AsEnum(); + V8ScrollLogicalPosition::Enum inline_align = + options.inlinePosition().AsEnum() == V8ScrollLogicalPosition::Enum::kAuto + ? V8ScrollLogicalPosition::Enum::kNearest + : options.inlinePosition().AsEnum(); + + auto align_x = ResolveToPhysicalAlignment(inline_align, block_align, kHorizontalScroll, computed_style); - auto align_y = ResolveToPhysicalAlignment(options.inlinePosition().AsEnum(), - options.block().AsEnum(), + auto align_y = ResolveToPhysicalAlignment(inline_align, block_align, kVerticalScroll, computed_style); mojom::blink::ScrollIntoViewParamsPtr params =
diff --git a/third_party/blink/renderer/core/scroll/scroll_promise_resolver.h b/third_party/blink/renderer/core/scroll/scroll_promise_resolver.h index d1f1360..9f5b159 100644 --- a/third_party/blink/renderer/core/scroll/scroll_promise_resolver.h +++ b/third_party/blink/renderer/core/scroll/scroll_promise_resolver.h
@@ -9,6 +9,7 @@ #include "third_party/blink/renderer/bindings/core/v8/script_promise.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" #include "third_party/blink/renderer/bindings/core/v8/v8_scroll_result.h" +#include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" #include "third_party/blink/renderer/platform/heap/persistent.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h" @@ -36,7 +37,7 @@ } void MarkInterrupted() { - scroll_promise_resolver_->SetScrollIsInterrupted(); + scroll_promise_resolver_->scroll_is_interrupted_ = true; } private: @@ -91,14 +92,33 @@ void ResolvePromiseIfIdle() { CHECK(script_promise_is_created_); CHECK(resolver_); - if (num_active_scrolls_ == 0) { - auto* result = ScrollResult::Create(); - result->setInterrupted(scroll_is_interrupted_); - resolver_->Resolve(result); - } - } - void SetScrollIsInterrupted() { scroll_is_interrupted_ = true; } + if (num_active_scrolls_ > 0) { + // Not idle yet, so defer resolving the promise. + return; + } + + auto* execution_context = resolver_->GetExecutionContext(); + if (!execution_context) { + // When the execution context is gone, not resolving the promise is fine + // because JS can't be waiting on it. In fact we can't even resolve it, + // see https://crbug.com/504073879. + return; + } + + execution_context->GetTaskRunner(TaskType::kDOMManipulation) + ->PostTask( + FROM_HERE, + blink::BindOnce( + [](ScriptPromiseResolver<ScrollResult>* resolver, + bool scroll_is_interrupted) { + auto* result = ScrollResult::Create(); + result->setInterrupted(scroll_is_interrupted); + resolver->Resolve(result); + }, + Persistent<ScriptPromiseResolver<ScrollResult>>(resolver_), + scroll_is_interrupted_)); + } Member<ScriptPromiseResolver<ScrollResult>> resolver_; wtf_size_t num_active_scrolls_ = 0;
diff --git a/third_party/blink/renderer/core/scroll/scrollable_area.cc b/third_party/blink/renderer/core/scroll/scrollable_area.cc index b0e2425b..75a9b81 100644 --- a/third_party/blink/renderer/core/scroll/scrollable_area.cc +++ b/third_party/blink/renderer/core/scroll/scrollable_area.cc
@@ -1310,6 +1310,19 @@ reason, previous_snap_targets, GetSnapContainerData()->GetTargetSnapAreaElementIds()); + ScrollOffset target_offset = ScrollPositionToOffset(snap_point.value()); + + // If we're targeting the same offset in an existing animation, then we + // should just continue running that animation. Otherwise, we will cancel the + // animation but not set the scroll offset (due to a same-target early out in + // ProgrammaticScrollAnimator). + if (scroll_behavior == mojom::blink::ScrollBehavior::kSmooth && + ExistingProgrammaticScrollAnimator() && + ExistingProgrammaticScrollAnimator()->HasRunningAnimation() && + ExistingProgrammaticScrollAnimator()->TargetOffset() == target_offset) { + return true; + } + // We should set the scrollsnapchanging targets of a snap container the first // time it is laid out to avoid a spurious scrollsnapchanging event firing the // first time the scroller is scrolled.
diff --git a/third_party/blink/renderer/core/svg/svg_animate_element.cc b/third_party/blink/renderer/core/svg/svg_animate_element.cc index 9694518..d7455b5b 100644 --- a/third_party/blink/renderer/core/svg/svg_animate_element.cc +++ b/third_party/blink/renderer/core/svg/svg_animate_element.cc
@@ -708,6 +708,12 @@ return false; } + // from-by with empty from: assumes that nothing additive will have a + // "usable" empty value, so we can't compute to (from + by). + if (GetAnimationMode() == kFromByAnimation && from_string.empty()) { + return false; + } + from_property_ = from_parsed_value.property; from_property_value_type_ = from_parsed_value.property_value_type; to_property_ = to_parsed_value.property;
diff --git a/third_party/blink/renderer/core/svg/svg_animation_element.cc b/third_party/blink/renderer/core/svg/svg_animation_element.cc index f736584..0735245 100644 --- a/third_party/blink/renderer/core/svg/svg_animation_element.cc +++ b/third_party/blink/renderer/core/svg/svg_animation_element.cc
@@ -312,11 +312,11 @@ if (hasAttribute(svg_names::kValuesAttr)) { return kValuesAnimation; } - if (!ToValue().empty()) { - return FromValue().empty() ? kToAnimation : kFromToAnimation; + if (!ToValue().IsNull()) { + return FromValue().IsNull() ? kToAnimation : kFromToAnimation; } - if (!ByValue().empty()) { - return FromValue().empty() ? kByAnimation : kFromByAnimation; + if (!ByValue().IsNull()) { + return FromValue().IsNull() ? kByAnimation : kFromByAnimation; } return kNoAnimation; }
diff --git a/third_party/blink/renderer/core/svg/svg_path.cc b/third_party/blink/renderer/core/svg/svg_path.cc index 2e1bc2cb..54a1a32 100644 --- a/third_party/blink/renderer/core/svg/svg_path.cc +++ b/third_party/blink/renderer/core/svg/svg_path.cc
@@ -169,13 +169,25 @@ const auto& to = To<SVGPath>(*to_value); const SVGPathByteStream& to_stream = to.ByteStream(); - // If no 'to' value is given, nothing to animate. - if (!to_stream.size()) - return; - const auto& from = To<SVGPath>(*from_value); const SVGPathByteStream& from_stream = from.ByteStream(); + // Additive with empty to (includes both-empty): can't add empty result to + // base. No animation. + if (to_stream.IsEmpty() && parameters.is_additive) { + return; + } + + // Non-additive with incompatible empty endpoint: use discrete animation. + // Empty from with additive (by-animation) falls through to + // BlendPathByteStreams which treats it as a zero-valued path matching to's + // structure. + if (!parameters.is_additive && + (from_stream.IsEmpty() || to_stream.IsEmpty())) { + path_value_ = percentage < 0.5 ? from.PathValue() : to.PathValue(); + return; + } + std::optional<SVGPathByteStream> new_stream = BlendPathByteStreams(from_stream, to_stream, percentage);
diff --git a/third_party/blink/renderer/modules/webaudio/audio_context.cc b/third_party/blink/renderer/modules/webaudio/audio_context.cc index dc501ff..eabebeb 100644 --- a/third_party/blink/renderer/modules/webaudio/audio_context.cc +++ b/third_party/blink/renderer/modules/webaudio/audio_context.cc
@@ -321,10 +321,11 @@ switch (status) { case media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_OK: if (audio_context_ && !audio_context_->IsContextCleared()) { - // Update AudioContext's sink ID and fire the 'onsinkchange' event - audio_context_->NotifySetSinkIdIsDone(sink_descriptor_); + // Update AudioContext's sink ID, resolve the promise, and queue the + // 'onsinkchange' event + audio_context_->NotifySetSinkIdIsDone(sink_descriptor_, script_state, + this); } - Resolve(); return; case media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND: Reject(V8ThrowDOMException::CreateOrEmpty( @@ -1664,25 +1665,54 @@ } void AudioContext::NotifySetSinkIdIsDone( - WebAudioSinkDescriptor pending_sink_descriptor) { + WebAudioSinkDescriptor pending_sink_descriptor, + ScriptState* script_state, + SetSinkIdResolver* resolver) { DCHECK_CALLED_ON_VALID_SEQUENCE(main_thread_sequence_checker_); sink_descriptor_ = pending_sink_descriptor; - // This performs steps 11 and 12 from the second part of the setSinkId() - // algorithm: - // https://webaudio.github.io/web-audio-api/#dom-audiocontext-setsinkid-domstring-or-audiosinkoptions-sinkid - UpdateV8SinkId(); - DispatchEvent(*Event::Create(event_type_names::kSinkchange)); if (sink_transition_flag_was_running_) { destination()->GetAudioDestinationHandler().StartRendering(); - SetContextState(V8AudioContextState::Enum::kRunning); - sink_transition_flag_was_running_ = false; } // The sink ID was given and has been accepted; it will be used as an output // audio device. is_sink_id_given_ = true; + + // This performs steps 11 and 12 from the second part of the setSinkId() + // algorithm: + // https://webaudio.github.io/web-audio-api/#dom-audiocontext-setsinkid-domstring-or-audiosinkoptions-sinkid + UpdateV8SinkId(); + + DCHECK(resolver); + resolver->Resolve(); + + // Dispatch the sinkchange event in a separate task to allow the microtasks + // queued by the promise resolution above to execute first. + ExecutionContext* execution_context = ExecutionContext::From(script_state); + DCHECK(execution_context); + execution_context->GetTaskRunner(TaskType::kMediaElementEvent) + ->PostTask(FROM_HERE, + blink::BindOnce(&AudioContext::DispatchSinkChangeEvent, + WrapWeakPersistent(this), + WrapPersistent(script_state))); +} + +void AudioContext::DispatchSinkChangeEvent(ScriptState* script_state) { + DCHECK_CALLED_ON_VALID_SEQUENCE(main_thread_sequence_checker_); + if (IsContextCleared() || !script_state->ContextIsValid()) { + return; + } + + ScriptState::Scope scope(script_state); + + DispatchEvent(*Event::Create(event_type_names::kSinkchange)); + + if (sink_transition_flag_was_running_) { + SetContextState(V8AudioContextState::Enum::kRunning); + sink_transition_flag_was_running_ = false; + } } void AudioContext::InitializeMediaDeviceService() {
diff --git a/third_party/blink/renderer/modules/webaudio/audio_context.h b/third_party/blink/renderer/modules/webaudio/audio_context.h index b15ba38..d36e7a82 100644 --- a/third_party/blink/renderer/modules/webaudio/audio_context.h +++ b/third_party/blink/renderer/modules/webaudio/audio_context.h
@@ -232,7 +232,9 @@ WebAudioSinkDescriptor GetSinkDescriptor() const { return sink_descriptor_; } void NotifySetSinkIdBegins(); - void NotifySetSinkIdIsDone(WebAudioSinkDescriptor); + void NotifySetSinkIdIsDone(WebAudioSinkDescriptor, + ScriptState*, + SetSinkIdResolver*); HeapDeque<Member<SetSinkIdResolver>>& GetSetSinkIdResolver() { return set_sink_id_resolvers_; @@ -263,6 +265,10 @@ void set_clock_for_testing(const base::TickClock* clock); private: + // Dispatches the `sinkchange` event in a separate task. This is necessary to + // ensure that the microtasks queued by the setSinkId() promise resolution + // execute *before* the synchronous event dispatch, as required by the spec. + void DispatchSinkChangeEvent(ScriptState* script_state); friend class AudioContextAutoplayTest; friend class AudioContextTest; friend class AudioContextStatsTest;
diff --git a/third_party/blink/renderer/modules/webaudio/audio_param_handler.cc b/third_party/blink/renderer/modules/webaudio/audio_param_handler.cc index 04d90973..0cb475f 100644 --- a/third_party/blink/renderer/modules/webaudio/audio_param_handler.cc +++ b/third_party/blink/renderer/modules/webaudio/audio_param_handler.cc
@@ -401,7 +401,7 @@ HandleNaNValues(values, DefaultValue()); } - vector_math::Vclip(values, 1, &min_value, &max_value, values, 1); + vector_math::Vclip(values, 1, min_value, max_value, values, 1); // Clear the channel memory to avoid holding a reference to the external // `values` buffer, which may be garbage collected. @@ -1288,7 +1288,7 @@ sample_rate, control_rate, render_quantum_frames); // Clamp the values now to the nominal range - vector_math::Vclip(values, 1, &min_value, &max_value, values, 1); + vector_math::Vclip(values, 1, min_value, max_value, values, 1); return last_value; }
diff --git a/third_party/blink/renderer/modules/webaudio/offline_audio_context_test.cc b/third_party/blink/renderer/modules/webaudio/offline_audio_context_test.cc index fa63dd6..53de234b 100644 --- a/third_party/blink/renderer/modules/webaudio/offline_audio_context_test.cc +++ b/third_party/blink/renderer/modules/webaudio/offline_audio_context_test.cc
@@ -13,6 +13,11 @@ #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/testing/page_test_base.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" +#include "third_party/blink/public/web/web_heap.h" +#include "third_party/blink/renderer/bindings/core/v8/script_promise_tester.h" +#include "third_party/blink/renderer/platform/instrumentation/instance_counters.h" +#include "third_party/blink/renderer/modules/webaudio/audio_buffer.h" +#include "third_party/blink/renderer/bindings/modules/v8/v8_audio_buffer.h" namespace blink { @@ -96,4 +101,49 @@ "WebAudioConfigurableRenderQuantum", false); } +TEST_F(OfflineAudioContextTest, OfflineRenderingThreadSafetyAndNoLeak) { + V8TestingScope scope; + + // Synchronously collect any uncollected garbage from previous tests to + // establish a clean baseline. Since InstanceCounters is a process-wide + // global counter, this GC run isolates our leak check and guarantees + // that the starting count is stable. This follows Chrome's official + // automated leak detector pattern (blink_leak_detector.cc), which + // queries kAudioHandlerCounter to find leaks. + WebHeap::CollectAllGarbageForTesting(); + + int initial_handler_count = + InstanceCounters::CounterValue(InstanceCounters::kAudioHandlerCounter); + + { + OfflineAudioContextOptions* options = OfflineAudioContextOptions::Create(); + options->setNumberOfChannels(1); + // Render 10 render quanta (1280 frames) to fully exercise the background + // thread rendering loop. + options->setLength(1280); + options->setSampleRate(44100.0); + + OfflineAudioContext* context = OfflineAudioContext::Create( + GetFrame().DomWindow(), options, ASSERT_NO_EXCEPTION); + + ScriptPromise<AudioBuffer> promise = context->startOfflineRendering( + scope.GetScriptState(), ASSERT_NO_EXCEPTION); + + ScriptPromiseTester tester(scope.GetScriptState(), promise); + tester.WaitUntilSettled(); + + EXPECT_TRUE(tester.IsFulfilled()); + } + + // Force complete garbage collection of both Blink Oilpan and V8 heaps + // immediately. When it returns, all unreferenced contexts and nodes are + // guaranteed to have been destroyed. + WebHeap::CollectAllGarbageForTesting(); + + // Verify that the count of active AudioHandlers returns to our baseline. + int final_handler_count = + InstanceCounters::CounterValue(InstanceCounters::kAudioHandlerCounter); + EXPECT_EQ(final_handler_count, initial_handler_count); +} + } // namespace blink
diff --git a/third_party/blink/renderer/modules/webaudio/offline_audio_destination_handler.cc b/third_party/blink/renderer/modules/webaudio/offline_audio_destination_handler.cc index 6db772e..247a7a7 100644 --- a/third_party/blink/renderer/modules/webaudio/offline_audio_destination_handler.cc +++ b/third_party/blink/renderer/modules/webaudio/offline_audio_destination_handler.cc
@@ -220,7 +220,8 @@ PostCrossThreadTask( *main_thread_task_runner_, FROM_HERE, CrossThreadBindOnce(&OfflineAudioDestinationHandler::NotifySuspend, - GetWeakPtr(), Context()->CurrentSampleFrame())); + WrapRefCounted(this), + Context()->CurrentSampleFrame())); } void OfflineAudioDestinationHandler::FinishOfflineRendering() { @@ -230,7 +231,7 @@ PostCrossThreadTask( *main_thread_task_runner_, FROM_HERE, CrossThreadBindOnce(&OfflineAudioDestinationHandler::NotifyComplete, - GetWeakPtr())); + WrapRefCounted(this))); } void OfflineAudioDestinationHandler::NotifySuspend(size_t frame) {
diff --git a/third_party/blink/renderer/modules/webaudio/offline_audio_destination_handler.h b/third_party/blink/renderer/modules/webaudio/offline_audio_destination_handler.h index 461facf..992fb798 100644 --- a/third_party/blink/renderer/modules/webaudio/offline_audio_destination_handler.h +++ b/third_party/blink/renderer/modules/webaudio/offline_audio_destination_handler.h
@@ -103,17 +103,6 @@ // from AudioWorkletThread will be used until the rendering is finished. void PrepareTaskRunnerForRendering(); - // For cross-thread posting, this object uses two different targets. - // 1. rendering thread -> main thread: WeakPtr - // When the main thread starts deleting this object, a task posted with - // a WeakPtr from the rendering thread will be cancelled. - // 2. main thread -> rendering thread: scoped_refptr - // `render_thread_` is owned by this object, so it is safe to target with - // `WrapRefCounted()` instead of `GetWeakPtr()`. - base::WeakPtr<OfflineAudioDestinationHandler> GetWeakPtr() { - return weak_factory_.GetWeakPtr(); - } - // This AudioHandler renders into this SharedAudioBuffer. std::unique_ptr<SharedAudioBuffer> shared_render_target_; // Temporary AudioBus for each render quantum. @@ -139,7 +128,6 @@ scoped_refptr<base::SingleThreadTaskRunner> render_thread_task_runner_; scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_; - base::WeakPtrFactory<OfflineAudioDestinationHandler> weak_factory_{this}; }; } // namespace blink
diff --git a/third_party/blink/renderer/modules/webaudio/wave_shaper_handler.cc b/third_party/blink/renderer/modules/webaudio/wave_shaper_handler.cc index a8439d7..f0e5f04 100644 --- a/third_party/blink/renderer/modules/webaudio/wave_shaper_handler.cc +++ b/third_party/blink/renderer/modules/webaudio/wave_shaper_handler.cc
@@ -429,8 +429,8 @@ 1, frames_to_process); // Clip virtual_index, in place. - vector_math::Vclip(virtual_index, 1, 0, curve_length - 1, virtual_index, 1, - frames_to_process); + vector_math::Vclip(virtual_index_.as_span(), 1, 0, curve_length - 1, + virtual_index_.as_span(), 1, frames_to_process); // index = floor(virtual_index) DCHECK_LE(frames_to_process, index_.size());
diff --git a/third_party/blink/renderer/modules/xr/xr_canvas_input_provider.cc b/third_party/blink/renderer/modules/xr/xr_canvas_input_provider.cc index 2113f5d..7f1cb43 100644 --- a/third_party/blink/renderer/modules/xr/xr_canvas_input_provider.cc +++ b/third_party/blink/renderer/modules/xr/xr_canvas_input_provider.cc
@@ -27,6 +27,10 @@ if (!input_provider_->ShouldProcessEvents()) return; + if (!event->isTrusted()) { + return; + } + auto* pointer_event = To<PointerEvent>(event); DCHECK(pointer_event); if (!pointer_event->isPrimary())
diff --git a/third_party/blink/renderer/platform/audio/vector_math.cc b/third_party/blink/renderer/platform/audio/vector_math.cc index 1c4f0130..86ecade 100644 --- a/third_party/blink/renderer/platform/audio/vector_math.cc +++ b/third_party/blink/renderer/platform/audio/vector_math.cc
@@ -106,51 +106,45 @@ dest_stride, frames_to_process); } -void Vclip(base::span<const float> source_p, +void Vclip(base::span<const float> source, int source_stride, - const float* low_threshold_p, - const float* high_threshold_p, - base::span<float> dest_p, + float low_threshold, + float high_threshold, + base::span<float> dest, int dest_stride) { - float low_threshold = *low_threshold_p; - float high_threshold = *high_threshold_p; - #if DCHECK_IS_ON() // Do the same DCHECKs that |ClampTo| would do so that optimization paths do // not have to do them. - for (size_t i = 0u; i < dest_p.size(); ++i) { - DCHECK(!std::isnan(source_p[i])); + for (size_t i = 0u; i < dest.size(); ++i) { + DCHECK(!std::isnan(source[i])); } // This also ensures that thresholds are not NaNs. DCHECK_LE(low_threshold, high_threshold); #endif - impl::Vclip(source_p.data(), source_stride, &low_threshold, &high_threshold, - dest_p.data(), dest_stride, dest_p.size()); + impl::Vclip(source.data(), source_stride, &low_threshold, &high_threshold, + dest.data(), dest_stride, dest.size()); } -void Vclip(const float* source_p, +void Vclip(base::span<const float> source, int source_stride, - float low_threshold_p, - float high_threshold_p, - float* dest_p, + float low_threshold, + float high_threshold, + base::span<float> dest, int dest_stride, uint32_t frames_to_process) { - float low_threshold = low_threshold_p; - float high_threshold = high_threshold_p; - #if DCHECK_IS_ON() // Do the same DCHECKs that |ClampTo| would do so that optimization paths do // not have to do them. for (size_t i = 0u; i < frames_to_process; ++i) { - UNSAFE_TODO(DCHECK(!std::isnan(source_p[i]))); + DCHECK(!std::isnan(source[i])); } // This also ensures that thresholds are not NaNs. DCHECK_LE(low_threshold, high_threshold); #endif - impl::Vclip(source_p, source_stride, &low_threshold, &high_threshold, dest_p, - dest_stride, frames_to_process); + impl::Vclip(source.data(), source_stride, &low_threshold, &high_threshold, + dest.data(), dest_stride, frames_to_process); } void Vmaxmgv(const float* source_p,
diff --git a/third_party/blink/renderer/platform/audio/vector_math.h b/third_party/blink/renderer/platform/audio/vector_math.h index 46c2ef9..ef96067 100644 --- a/third_party/blink/renderer/platform/audio/vector_math.h +++ b/third_party/blink/renderer/platform/audio/vector_math.h
@@ -169,18 +169,18 @@ // // where y = clip(x, low, high) = max(low, min(x, high)), effectively making // low <= y <= high. -PLATFORM_EXPORT void Vclip(base::span<const float> source_p, +PLATFORM_EXPORT void Vclip(base::span<const float> source, int source_stride, - const float* low_threshold_p, - const float* high_threshold_p, - base::span<float> dest_p, + float low_threshold, + float high_threshold, + base::span<float> dest, int dest_stride); -PLATFORM_EXPORT void Vclip(const float* source_p, +PLATFORM_EXPORT void Vclip(base::span<const float> source, int source_stride, - float low_threshold_p, - float high_threshold_p, - float* dest_p, + float low_threshold, + float high_threshold, + base::span<float> dest, int dest_stride, uint32_t frames_to_process);
diff --git a/third_party/blink/renderer/platform/audio/vector_math_test.cc b/third_party/blink/renderer/platform/audio/vector_math_test.cc index 940b343..91868b6 100644 --- a/third_party/blink/renderer/platform/audio/vector_math_test.cc +++ b/third_party/blink/renderer/platform/audio/vector_math_test.cc
@@ -365,7 +365,7 @@ expected_dest[i] = ClampTo(source[i], low_threshold, high_threshold); } for (auto& dest : GetSecondaryVectors(GetDestination(1u), source)) { - Vclip(source.as_span(), source.stride(), &low_threshold, &high_threshold, + Vclip(source.as_span(), source.stride(), low_threshold, high_threshold, dest.as_span(), dest.stride()); EXPECT_EQ(expected_dest, dest); }
diff --git a/third_party/blink/renderer/platform/blink_platform_unittests_bundle_data.filelist b/third_party/blink/renderer/platform/blink_platform_unittests_bundle_data.filelist index 2b00b7a..6c6bf1f 100644 --- a/third_party/blink/renderer/platform/blink_platform_unittests_bundle_data.filelist +++ b/third_party/blink/renderer/platform/blink_platform_unittests_bundle_data.filelist
@@ -161,6 +161,7 @@ ../../web_tests/external/wpt/jpegxl/resources/green_queen_modular_e3.jxl ../../web_tests/external/wpt/jpegxl/resources/green_queen_vardct_e3.jxl ../../web_tests/external/wpt/jpegxl/resources/has_permutation.jxl +../../web_tests/external/wpt/jpegxl/resources/hdr_alpha.jxl ../../web_tests/external/wpt/jpegxl/resources/hdr_hlg_test.jxl ../../web_tests/external/wpt/jpegxl/resources/hdr_pq_test.jxl ../../web_tests/external/wpt/jpegxl/resources/issue648_palette0.jxl @@ -169,6 +170,7 @@ ../../web_tests/external/wpt/jpegxl/resources/orientation8_rotate_90_ccw.jxl ../../web_tests/external/wpt/jpegxl/resources/progressive-lf.jxl ../../web_tests/external/wpt/jpegxl/resources/progressive_ac.jxl +../../web_tests/external/wpt/jpegxl/resources/sdr_alpha.jxl ../../web_tests/external/wpt/jpegxl/resources/smallest_valid.jxl ../../web_tests/external/wpt/jpegxl/resources/spline_on_first_frame.jxl ../../web_tests/external/wpt/jpegxl/resources/with_icc.jxl
diff --git a/third_party/blink/renderer/platform/peerconnection/video_codec_factory.cc b/third_party/blink/renderer/platform/peerconnection/video_codec_factory.cc index 9a9ca423..e958c0b 100644 --- a/third_party/blink/renderer/platform/peerconnection/video_codec_factory.cc +++ b/third_party/blink/renderer/platform/peerconnection/video_codec_factory.cc
@@ -58,7 +58,10 @@ webrtc::VideoDecoderFactory* factory, const webrtc::Environment& env, const webrtc::SdpVideoFormat& format) { - if (!factory || !factory->QueryCodecSupport(format, false).is_supported) { + if (!factory || !factory + ->QueryCodecSupport(format, /*reference_scaling=*/false, + /*resolution=*/std::nullopt) + .is_supported) { return nullptr; } return factory->Create(env, format);
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index f858c7b..76f3bc91 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -2026,7 +2026,7 @@ // // https://drafts.csswg.org/css-values-5/#request-url-modifiers name: "CSSURLRequestModifiers", - status: "experimental", + status: "stable", }, // Support for `user-select:contain`. {
diff --git a/third_party/blink/web_tests/MSANExpectations b/third_party/blink/web_tests/MSANExpectations index 42f6b9f1..26f20748 100644 --- a/third_party/blink/web_tests/MSANExpectations +++ b/third_party/blink/web_tests/MSANExpectations
@@ -177,9 +177,6 @@ # Gardener 2025-12-23 crbug.com/471103692 [ Linux ] external/wpt/webaudio/the-audio-api/the-mediastreamaudiosourcenode-interface/mediastreamaudiosourcenode-from-context-with-different-rate.https.html [ Pass Timeout ] -# Gardener 2026-02-24 -crbug.com/459235322 [ Linux ] webaudio/OfflineAudioContext/offlineaudiocontext-promise-basic.html [ Pass Timeout ] - # Times out under MSan, similar to crbug.com/459235322. crbug.com/480249475 [ Linux ] external/wpt/css/css-pseudo/input-element-pseudo-open.optional.html [ Pass Timeout ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index eb1c10da..b0ab5a1 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -2764,6 +2764,14 @@ crbug.com/507904104 virtual/produce-compile-hints/external/wpt/fetch/fetch-later/quota/same-origin-iframe/empty-payload.https.window.html [ Failure ] # ====== New tests from wpt-importer added here ====== +external/wpt/content-security-policy/inheritance/auxiliary-blank-document.html [ Timeout ] +external/wpt/fullscreen/api/keyboard-lock-cross-origin-iframe.tentative.sub.html [ Skip Timeout ] +[ Win ] external/wpt/navigation-api/ordering-and-transition/anchor-download-intercept-reject.html?currententrychange [ Pass Timeout ] +[ Win ] external/wpt/navigation-api/ordering-and-transition/navigate-intercept.html?currententrychange [ Pass Timeout ] +[ Win ] external/wpt/navigation-api/precommit-handler/precommitHandler-window-stop-before-commit.html [ Pass Timeout ] +external/wpt/webdriver/tests/bidi/network/continue_request/cookies.py [ Failure ] +virtual/jxl-enabled/external/wpt/jpegxl/hdr-alpha-reftest.html [ Failure ] +virtual/jxl-enabled/external/wpt/jpegxl/sdr-alpha-reftest.html [ Failure ] crbug.com/508645094 [ Win ] external/wpt/css/css-transitions/idlharness-2.html [ Pass Timeout ] crbug.com/508631189 [ Win ] external/wpt/svg/types/scripted/SVGAnimatedEnumeration-SVGTextPathElement.html [ Pass Timeout ] crbug.com/508634577 external/wpt/webdriver/tests/classic/external/webauthn/add_credential/add.py [ Failure ] @@ -9792,4 +9800,4 @@ crbug.com/510116037 [ Linux ] external/wpt/client-hints/critical-ch/request-count.https.window.html [ Failure ] crbug.com/510116037 [ Linux ] external/wpt/client-hints/critical-ch/subresource.https.window.html [ Failure ] -crbug.com/506273267 virtual/permission-element/external/wpt/html/semantics/permission-element/usermedia/set-constraints-combinations.tentative.https.html [ Failure Pass ] \ No newline at end of file +crbug.com/506273267 virtual/permission-element/external/wpt/html/semantics/permission-element/usermedia/set-constraints-combinations.tentative.https.html [ Failure Pass ]
diff --git a/third_party/blink/web_tests/TestLists/content_shell.filter b/third_party/blink/web_tests/TestLists/content_shell.filter index 84de29e..41c54749 100644 --- a/third_party/blink/web_tests/TestLists/content_shell.filter +++ b/third_party/blink/web_tests/TestLists/content_shell.filter
@@ -63,15 +63,6 @@ external/wpt/css/compositing/mix-blend-mode/mix-blend-mode-with-transform-and-preserve-3D.html external/wpt/css/compositing/root-element-opacity-change.html external/wpt/css/compositing/svg/mix-blend-mode-svg-rectangle.html -external/wpt/css/CSS2/backgrounds/background-applies-to-006.xht -external/wpt/css/CSS2/backgrounds/background-applies-to-012.xht -external/wpt/css/CSS2/backgrounds/background-color-applies-to-006.xht -external/wpt/css/CSS2/backgrounds/background-color-applies-to-012.xht -external/wpt/css/CSS2/backgrounds/background-image-applies-to-006.xht -external/wpt/css/CSS2/backgrounds/background-image-applies-to-012.xht -external/wpt/css/CSS2/backgrounds/background-position-applies-to-012.xht -external/wpt/css/CSS2/backgrounds/background-repeat-applies-to-006.xht -external/wpt/css/CSS2/backgrounds/background-repeat-applies-to-012.xht external/wpt/css/CSS2/borders/border-applies-to-006.xht external/wpt/css/CSS2/borders/border-applies-to-012.xht external/wpt/css/CSS2/borders/border-color-applies-to-006.xht
diff --git a/third_party/blink/web_tests/cssom/scroll-promise-after-gc.html b/third_party/blink/web_tests/cssom/scroll-promise-after-gc.html index 979aff3..9bfc5fad 100644 --- a/third_party/blink/web_tests/cssom/scroll-promise-after-gc.html +++ b/third_party/blink/web_tests/cssom/scroll-promise-after-gc.html
@@ -3,23 +3,43 @@ <script src="../resources/testharness.js"></script> <script src="../resources/testharnessreport.js"></script> <style> + iframe { + height: 120px; + } + .filler { height: 6000px } #scroller { overflow: scroll; - width: 100px; height: 100px; } </style> +<iframe></iframe> <div id="scroller"> <div class="filler"></div> </div> <script> "use strict"; - promise_test(async () => { - const scroller = document.getElementById("scroller"); + const scroller = document.getElementById("scroller"); + async function confirmPromiseSettles(scroll_promise) { + return new Promise(resolve => { + async function waitForFrames(num) { + if (num <= 0) { + assert_unreached("Pending scroll promise"); + resolve(); + return; + } + requestAnimationFrame(() => waitForFrames(num-1)); + } + waitForFrames(10); + scroll_promise.then(resolve); + }); + } + + promise_test(async () => { + scroller.scrollTop = 0; const offset = 5000; let promise = scroller.scrollBy({ top: offset, behavior: "smooth" }); @@ -34,4 +54,30 @@ assert_equals(scroller.scrollTop, offset, "Smooth scroll ends through await"); }, "Scroll promise handling after garbage collection"); + + promise_test(async () => { + scroller.scrollTop = 0; + + let scroll_promise = scroller.scrollBy({ top: 1000, behavior: "smooth" }); + scroller.remove(); + window.gc(); + + await confirmPromiseSettles(scroll_promise); + }, "Scroll promise handling after scroller removal and garbage collection"); + + promise_test(async () => { + const iframe = document.getElementsByTagName("iframe")[0]; + + iframe.contentDocument.body.appendChild(scroller); + scroller.scrollTop = 0; + scroller.style.setProperty("overflow", "scroll"); + scroller.style.setProperty("height", "100px"); + scroller.firstElementChild.style.setProperty("height", "6000px"); + + let scroll_promise = scroller.scrollBy({ top: 1000, behavior: "smooth" }); + iframe.remove(); + window.gc(); + + await confirmPromiseSettles(scroll_promise); + }, "Scroll promise handling after iframe removal and garbage collection"); </script>
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 da3249e..4aae36d 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
@@ -1020,6 +1020,13 @@ null, {} ] + ], + "transform-properties-from-none-to-none-crash.html": [ + "a2f4f7aa03d9f7c2593ccefa3f768cf2b6e320c0", + [ + null, + {} + ] ] }, "display-via-custom-prop-animation-crash.html": [ @@ -3507,6 +3514,13 @@ {} ] ], + "highlight-image-multiple-crash.html": [ + "395804ace8878f8a22ee5f0c4cf9e6efe738b202", + [ + null, + {} + ] + ], "highlight-overlap-with-aria-invalid-crash.html": [ "a85c5cc02d7d63ac4332d07655fd7af45c6660da", [ @@ -7669,6 +7683,15 @@ ] } }, + "collections": { + "childnodes-messagechannel-crash.html": [ + "f118eff6f940cf7c95bafb2936fd2af90b7dd683", + [ + null, + {} + ] + ] + }, "events": { "keypress-dispatch-crash.html": [ "3207adbd8c891903b1c6edd65edc41de9b9e7312", @@ -7715,6 +7738,13 @@ ] ], "crashtests": { + "attribute-index-when-no-attributes.html": [ + "628fdd81e4946041b4b75e1105eeb5fb27593ae8", + [ + null, + {} + ] + ], "childNodes-last_visited-unwrap-crash.html": [ "9c16a38ac2767b52a9b86eff4a400fea241b6732", [ @@ -7926,6 +7956,13 @@ {} ] ], + "delete-after-removing-first-child.html": [ + "3abc98258f0e0d9450f890b1ec4b6076930361ae", + [ + null, + {} + ] + ], "delete-around-orphan-rb.html": [ "f79c3092c7edd95081ceed14c92ed6069a0828c7", [ @@ -9022,6 +9059,19 @@ } } }, + "editing": { + "dnd": { + "crashtests": { + "DataTransfer-getData-RefCell-already-borrowed.html": [ + "1bfdce40390f81cbff6083269664a88ed5245184", + [ + null, + {} + ] + ] + } + } + }, "interaction": { "focus": { "focus-after-attach-shadow-crash.html": [ @@ -11383,7 +11433,7 @@ ] ], "selection-modify-line-boundary-around-empty-details.html": [ - "815a819c3367b7441be40b2294c9a2998bfcb632", + "ff7760e2209b9e55e4fbc55c8d6e4298b4e576b2", [ null, {} @@ -12453,6 +12503,15 @@ ] ] }, + "filelist-section": { + "filelist_multiple_selected_files-manual.html": [ + "2efaa059fa48978e999a2a23ef28669e45b00c54", + [ + null, + {} + ] + ] + }, "url": { "url_createobjecturl_file_img-manual.html": [ "534c1de9968da89036e57ff52a8ac6feb8d5b377", @@ -22176,6 +22235,15 @@ } }, "editing-0": { + "autocorrection": { + "autocorrect-off-touch-keyboard-manual.html": [ + "ae98fbe9f41f42bc8807cbb47af1385c0b3c70a1", + [ + null, + {} + ] + ] + }, "contenteditable": { "spellcheck-insertReplacementText-input-event-manual.html": [ "61736269634fc7135a09529f364de9457b6d9c11", @@ -29726,6 +29794,19 @@ {} ] ], + "number-input-link-crash-print.html": [ + "656167038df18d21604462d46573f57c42621221", + [ + null, + [ + [ + "/css/reference/blank.html", + "!=" + ] + ], + {} + ] + ], "page-overflow-crash-print.html": [ "e295c569d2d634867bab43741baf23c905918fc3", [ @@ -79652,7 +79733,7 @@ ] ], "anchor-position-multicol-011.html": [ - "eab57bfdb841bc488708ad001f2534cdae2a5188", + "ce0ec15280f76818bb83e4a43ab11113c6a5016c", [ null, [ @@ -80042,7 +80123,7 @@ ] ], "anchor-scroll-implicit-001.html": [ - "e0b6ded3b9b9a11eac337169559e3bdd43b1ac4a", + "a6652c4811249461b2d06685d305d93bf71c4a5e", [ null, [ @@ -80055,7 +80136,7 @@ ] ], "anchor-scroll-implicit-002.html": [ - "f70235b8e2a117c2e65a9a03d5d67c15692bde71", + "040d09ef428505739fa12914b1049493af4e6a8a", [ null, [ @@ -93357,6 +93438,93 @@ } ] ], + "border-shape-outline-auto-forms.html": [ + "de6953215fecdac27ef425d6de629fecf01176ad", + [ + null, + [ + [ + "/css/css-borders/border-shape/border-shape-outline-auto-forms-ref.html", + "==" + ] + ], + { + "fuzzy": [ + [ + null, + [ + [ + 0, + 5 + ], + [ + 0, + 50 + ] + ] + ] + ] + } + ] + ], + "border-shape-outline-auto-with-border.html": [ + "131ac90f6fe2c7d06970cd0a05754d39c7af784e", + [ + null, + [ + [ + "/css/css-borders/border-shape/border-shape-outline-auto-with-border-ref.html", + "==" + ] + ], + { + "fuzzy": [ + [ + null, + [ + [ + 0, + 5 + ], + [ + 0, + 50 + ] + ] + ] + ] + } + ] + ], + "border-shape-outline-auto.html": [ + "583ff4662543d22d3b4d6b51e3aa4ddee209b425", + [ + null, + [ + [ + "/css/css-borders/border-shape/border-shape-outline-auto-ref.html", + "==" + ] + ], + { + "fuzzy": [ + [ + null, + [ + [ + 0, + 5 + ], + [ + 0, + 50 + ] + ] + ] + ] + } + ] + ], "border-shape-outline-double-path.html": [ "73aade72bc8533603555e588ddabab45bb28e863", [ @@ -158710,6 +158878,19 @@ ] ] }, + "column-subgrid-ignores-width-001.html": [ + "3ca0602159ce7ebf1020719716254a69cba4e599", + [ + null, + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + {} + ] + ], "column-subgrid-standalone-row-axis-size-001.html": [ "6eed203dfde17e8a7d3d5dc5fc078c1ad520517d", [ @@ -158842,6 +159023,19 @@ ] ] }, + "row-subgrid-ignores-height-001.html": [ + "43d583e78d5057373255b0ef12bea0f54226f07e", + [ + null, + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + {} + ] + ], "row-subgrid-standalone-column-axis-size-001.html": [ "f3838b3e41523aaf713466ece51163e82cdc1540", [ @@ -158856,6 +159050,32 @@ ] ], "track-sizing": { + "auto-track-sizing-001.html": [ + "a993a93bc77d20a1aac192d80d14b37eb9100288", + [ + null, + [ + [ + "/css/css-grid/subgrid/auto-track-sizing-002-ref.html", + "==" + ] + ], + {} + ] + ], + "auto-track-sizing-002.html": [ + "9afe7a8c6ea45288d79ecfb2d4c692c4cf824c71", + [ + null, + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + {} + ] + ], "column-subgrid-extra-margin-001.html": [ "fcd9d3f195a110b8866f0c0bf4f61f5b8ddc08ad", [ @@ -164468,7 +164688,7 @@ }, "css-highlight-api": { "highlight-image.html": [ - "b5d44e06b29735d6a5ab9fbfc9d1f92917fd4ff3", + "e45b0db38248fef7b133effec03c468ddcb9bff4", [ null, [ @@ -165688,6 +165908,32 @@ {} ] ], + "custom-highlight-painting-insert-node-001.html": [ + "f0a11c2dfd42ceca9d1675afaaaf68e90e6355be", + [ + null, + [ + [ + "/css/css-highlight-api/painting/custom-highlight-painting-insert-node-001-ref.html", + "==" + ] + ], + {} + ] + ], + "custom-highlight-painting-insert-node-002.html": [ + "f4a590d12d4ec17ad8ba49a6f5170b72f518f066", + [ + null, + [ + [ + "/css/css-highlight-api/painting/custom-highlight-painting-insert-node-001-ref.html", + "==" + ] + ], + {} + ] + ], "custom-highlight-painting-invalidation-001.html": [ "aef391ec0f3c749554bc2cf284b18ff78f8bc525", [ @@ -168773,7 +169019,7 @@ ], "image-orientation": { "image-orientation-background-image.html": [ - "866e94596020286cf67f2083bc6dc64258af3506", + "46aa1b009cb7af02285661c7bc4f9a1e0772cac1", [ null, [ @@ -168793,7 +169039,7 @@ ], [ 0, - 50 + 60 ] ] ] @@ -169260,7 +169506,7 @@ ] ], "image-orientation-list-style-image.html": [ - "ac735626dbd1ec8a0743cf480bddc40d85e93149", + "059317ecde7c7722a0671a3742df82e7a02587a5", [ null, [ @@ -169280,7 +169526,7 @@ ], [ 0, - 50 + 60 ] ] ] @@ -211100,7 +211346,7 @@ ] ], "ruby-overhang-dynamic.html": [ - "cd138bbca3d9255acac79c34733257ad68e72b67", + "b41cd2b740666f2c521dee27c7dd715a0cdf82b7", [ null, [ @@ -211112,6 +211358,19 @@ {} ] ], + "ruby-overhang-none.html": [ + "4c8432d3284bccf342693a49add7bea15379be3c", + [ + null, + [ + [ + "/css/css-ruby/ruby-overhang-none-ref.html", + "==" + ] + ], + {} + ] + ], "ruby-overhang-spaces-001.html": [ "5ad945abd1606bc2bb3086ccd7e387dc14151891", [ @@ -211177,19 +211436,6 @@ {} ] ], - "ruby-overhang.html": [ - "5c8cfd1685427b32dcc08e12c45a257f6aa7fbec", - [ - null, - [ - [ - "/css/css-ruby/ruby-overhang-ref.html", - "==" - ] - ], - {} - ] - ], "ruby-reflow-001-opaqueruby.html": [ "77feb2e6b8dcdd514114dbec9867529e3bda0323", [ @@ -236864,6 +237110,19 @@ {} ] ], + "grow-dynamic.html": [ + "c403a3f44d6520465bc61cc7d8d3237174fd4ab2", + [ + null, + [ + [ + "/css/css-text/text-fit/grow-dynamic-ref.html", + "==" + ] + ], + {} + ] + ], "grow-per-line-all-line-height.html": [ "df1e17bee11bb08452e7a98015f687daceb8a6fa", [ @@ -236929,6 +237188,19 @@ {} ] ], + "shrink-dynamic.html": [ + "9a8a5e6ae8fef2f678ca6a076d4c8a991cad746a", + [ + null, + [ + [ + "/css/css-text/text-fit/shrink-dynamic-ref.html", + "==" + ] + ], + {} + ] + ], "shrink-per-line-all.html": [ "01b33e015735795fa07b505ca07b63a5e6ff53fb", [ @@ -278373,6 +278645,19 @@ {} ] ], + "html-attr-case-insensitivity.html": [ + "39ba432a73d4eae5fb56de3d71027c72a001fa86", + [ + null, + [ + [ + "/css/css-values/html-attr-case-insensitivity-ref.html", + "==" + ] + ], + {} + ] + ], "ic-unit-001.html": [ "5045e0108e5edec8ca8ee6f09b07d52abc02e6b9", [ @@ -299150,7 +299435,7 @@ ] ], "line-box-height-vlr-003.xht": [ - "40ac9fca129522d6d225c18ced6d2b580cb6cdcd", + "fdaca89390e8d061ac7d9f4b586883531702a388", [ null, [ @@ -299163,7 +299448,7 @@ ] ], "line-box-height-vlr-005.xht": [ - "a40a1dd5c5af53a2bf5d9f26fcd4a9f4f28fb9f2", + "39caae31e3ecd21cf7ad2c93889dac5e9097a532", [ null, [ @@ -299176,7 +299461,7 @@ ] ], "line-box-height-vlr-007.xht": [ - "eb65d2c18d2eb5b6e87b25097d359cd511890da9", + "5bb763df9cfc3d0a9c73745f420aace44d78c777", [ null, [ @@ -299189,7 +299474,7 @@ ] ], "line-box-height-vlr-009.xht": [ - "444f53e2e7f36272ddbd175ad39a1c9b2a71dda9", + "2fa2881c1c11e552de653932dffb02ab7532b1bd", [ null, [ @@ -299202,7 +299487,7 @@ ] ], "line-box-height-vlr-011.xht": [ - "3d4ecdf9fa48d516a2f5506320cf8d35b4019132", + "73626a0e909ad655f74f270caf5ea1f7f0682a70", [ null, [ @@ -299215,7 +299500,7 @@ ] ], "line-box-height-vlr-013.xht": [ - "c617555a53c2be29522c4e3a248d79d2330ce64d", + "2e340b4a4d9a05fd09426dd5e9f9227bf3dfa176", [ null, [ @@ -299228,7 +299513,7 @@ ] ], "line-box-height-vlr-021.xht": [ - "b3fe884fb229c815eeeeecc3318f1dedaca05505", + "c23c8b9e147bd75a35c8194aefaea1f9cd31d1ff", [ null, [ @@ -299241,7 +299526,7 @@ ] ], "line-box-height-vlr-023.xht": [ - "235125b52ef83af34fb812ad41fbf0d62df9e705", + "8e8e4522c224d02b74c92550112c300e89a32d12", [ null, [ @@ -299254,7 +299539,7 @@ ] ], "line-box-height-vrl-002.xht": [ - "726385e485c2612e8f61ba9ecd15f7e66f9ffe9d", + "6fdad5aa3d6170185bb5659cec0cab1ae94f6720", [ null, [ @@ -299267,7 +299552,7 @@ ] ], "line-box-height-vrl-004.xht": [ - "2755c555e4489454ed436b4b1ebad019e0724c7f", + "ada7956c2e3e99ed5f35cee4a10875a78bfb214d", [ null, [ @@ -299280,7 +299565,7 @@ ] ], "line-box-height-vrl-006.xht": [ - "24f2c464526e0a39eb7219c9ced551039614b931", + "717c47c03df8c456b7c25abeca5c5683355fb4b4", [ null, [ @@ -299293,7 +299578,7 @@ ] ], "line-box-height-vrl-008.xht": [ - "afcf6f7eddcabf328568a04aa388e814fe21843f", + "0bdc43781c02a442ba90ff95e305d2cec054ebc3", [ null, [ @@ -299306,7 +299591,7 @@ ] ], "line-box-height-vrl-010.xht": [ - "5c361efa3c9dc8acc73934d21f93bce2ff2b799b", + "3e71230d9dd70804e75a81908f6dcb54c91ab5b1", [ null, [ @@ -299319,7 +299604,7 @@ ] ], "line-box-height-vrl-012.xht": [ - "6e1b687b039ec6ea6496e515ac932907121b1099", + "5ef21dbd1c1aebe3f532211f897de84358cdebfd", [ null, [ @@ -329467,7 +329752,7 @@ ] ], "input-text-indent.html": [ - "ab301a2319ccb59e0e61d9a27cbd20ba2b8d121b", + "65011f9f259f8a5136eac85bf7bc843e578507e6", [ null, [ @@ -335243,7 +335528,7 @@ ] ], "interestfor-pseudo-element-appearance.tentative.html": [ - "612216383a1eeb5e8a6f7f73e5ae83fc3e4c145c", + "19344a65ed3f6ca52a411a4bf5323a26926d1acd", [ null, [ @@ -342223,6 +342508,19 @@ {} ] ], + "hdr-alpha-reftest.html": [ + "90c50ec37d49cad95366c491ef4894ecc6d8bd44", + [ + null, + [ + [ + "/jpegxl/hdr-alpha-reftest-ref.html", + "==" + ] + ], + {} + ] + ], "html-embed-object-iframe.html": [ "a4fc7f549de5c92d642ea34da5608ed4a1c76bff", [ @@ -342411,6 +342709,19 @@ } ] ], + "sdr-alpha-reftest.html": [ + "5e7dc266f87beed6318d797e447822b743268694", + [ + null, + [ + [ + "/jpegxl/sdr-alpha-reftest-ref.html", + "==" + ] + ], + {} + ] + ], "smallest-valid-reftest.html": [ "2fcf7e9b28616eed4c55afcc6f46898f937b88a5", [ @@ -347809,6 +348120,21 @@ {} ] ], + "nested-hover-pseudo-class-removal.html": [ + "8b66c86ffec395c12d9b05b3107ae92e4ac979ed", + [ + null, + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + { + "testdriver": true + } + ] + ], "shadow-style-invalidation-vw-units.html": [ "3f73f213adf3afb8581206fa62d2045c9a2d4f94", [ @@ -354176,26 +354502,13 @@ {} ] ], - "textpath-path-attr-empty-no-fallback.tentative.svg": [ - "6c64c8c5170563826c9914fb167ef062ab39ff8e", + "textpath-path-attr-empty-fallback.svg": [ + "ff8a41331ff76e42554bdeacc0f31f5af72a7776", [ null, [ [ - "/svg/text/reftests/textpath-path-attr-empty-ref.tentative.svg", - "==" - ] - ], - {} - ] - ], - "textpath-path-attr-invalid-no-fallback.tentative.svg": [ - "013672c9979e57844af78ff085eec3e010809b1d", - [ - null, - [ - [ - "/svg/text/reftests/textpath-path-attr-empty-ref.tentative.svg", + "/svg/text/reftests/textpath-path-attr-ref.svg", "==" ] ], @@ -354203,7 +354516,7 @@ ] ], "textpath-path-attr-invalid-path-fallback.svg": [ - "957692547ef226c96f8254e6d63e7ba3b306d206", + "d20b2bdf935953cfee15099ba6c258bc4e2a8818", [ null, [ @@ -354216,7 +354529,7 @@ ] ], "textpath-path-attr-precedence-over-href.svg": [ - "c34e7d48dd428c40ae0f9dd4e4b1f2178b413d62", + "b3c38a315c498e4766271e9dc97d4125d343b2f5", [ null, [ @@ -354228,8 +354541,8 @@ {} ] ], - "textpath-path-attr-use-up-to-first-error.tentative.svg": [ - "13e58d53670b806612c8b5f79685fb75511134d9", + "textpath-path-attr-use-up-to-first-error.svg": [ + "82d2487e9c645d6db828647afb42aa09d98090ca", [ null, [ @@ -354242,7 +354555,7 @@ ] ], "textpath-path-attr.svg": [ - "eea6a7160f93406d3c8e62eb70c87f2b4652d975", + "ea266e9b5b130f6bc1a72ad62279b7220861f88b", [ null, [ @@ -359362,12 +359675,20 @@ [] ] }, + "supports-modern.tentative.https.any-expected.txt": [ + "ae0f7f8cfd13ed7ea649272761b77f0407a233fc", + [] + ], + "supports-modern.tentative.https.any.worker-expected.txt": [ + "ae0f7f8cfd13ed7ea649272761b77f0407a233fc", + [] + ], "supports.tentative.https.any-expected.txt": [ - "bc6c56d1ceda165404f99e5ee08fac64a07e5be0", + "961123bc0208c895bc74b6ad70b51cdbff6004b1", [] ], "supports.tentative.https.any.worker-expected.txt": [ - "bc6c56d1ceda165404f99e5ee08fac64a07e5be0", + "961123bc0208c895bc74b6ad70b51cdbff6004b1", [] ], "tools": { @@ -359595,10 +359916,6 @@ }, "ai": { "language-model": { - "language-model-prompt.tentative.https.window-expected.txt": [ - "967626566516180b4f48180df1dd625a4f59e538", - [] - ], "resources": { "iframe-helper.html": [ "5e8cb90d0068ab88e31d1cb984bff8ce487e1d89", @@ -359624,7 +359941,7 @@ [] ], "util.js": [ - "ae279ffb3cca25224758ca8e08cf6dd8f9e27915", + "c9c8449bc37228d6d139c997acb2daac15873956", [] ] }, @@ -364349,11 +364666,11 @@ [] ], "postmessage-opener.html": [ - "7ee11bc78de53414cb7dde5b3ce59272bf823911", + "945adbdbfd638eef885314b39dbef6d3b580dd0d", [] ], "postmessage-top.html": [ - "242063a80e2980388f9881c097a9b387929f4396", + "79ca9741b55816307f2a12972ce6340d1e769402", [] ], "srcdoc-child-frame.html": [ @@ -365188,14 +365505,6 @@ "util.js": [ "e813b8b13e505745c45c7ff4959d59eafad0c7d5", [] - ], - "worker-report-hash.js": [ - "83cdb6ec3b426435e15d588a7b3f3af2a07a2487", - [] - ], - "worker-report-hash.js.headers": [ - "e0cbd93b3292317a65ec817e0d3f2da8898befd9", - [] ] } } @@ -373803,6 +374112,10 @@ "a6e290c582a66260336d9b8984295c0a51021304", [] ], + "position-anchor-basics-expected.txt": [ + "dc4d957643a766626562fc351b43ebd9216b8341", + [] + ], "position-anchor-dynamic-unset-visibility-hidden-ref.html": [ "bc966742157aedd4525b987b00b74724edcc43fd", [] @@ -376738,6 +377051,18 @@ "9c9aad052c8c544dc98c36b7a473e7349b4f8b9d", [] ], + "border-shape-outline-auto-forms-ref.html": [ + "31dcae70cb48c6debed0ccda6febafba3efda0d6", + [] + ], + "border-shape-outline-auto-ref.html": [ + "c76c1915281c32ef6afc2c3eaea1b6b3077f6955", + [] + ], + "border-shape-outline-auto-with-border-ref.html": [ + "10add4549b19c05bbade41568f747b136ba6c867", + [] + ], "border-shape-outline-double-path-ref.html": [ "25eb00128981791293de0e3b11c6a9402ecd256a", [] @@ -376838,10 +377163,6 @@ "66105e1b89730663da7dd5701f0ded58c50f044f", [] ], - "corner-computed-expected.txt": [ - "f81f01cad29b8407546c7709a4bb7f663da4902c", - [] - ], "corner-shape-backdrop-filter-overflow-ref.html": [ "4aabd7e8e353f90f3ceeaf590eca42854c9552b7", [] @@ -376894,14 +377215,6 @@ "4576240ef3288a954c9a627cbafd640eacd95444", [] ], - "corner-valid-expected.txt": [ - "7d2024130e1c30cbdbce514eaafb3a59f8411795", - [] - ], - "corners-invalid-expected.txt": [ - "97159bd9957254e95d4b4f8cae53bb40fb1d24e2", - [] - ], "render-corner-shape-ref.html": [ "d43106f2786dfb7563516bc003cc99b7c661e180", [] @@ -379138,14 +379451,6 @@ "cc27fb65b243b919e73c1a20fea82fbf7c6a4586", [] ], - "style-query-no-cycle-expected.txt": [ - "707460938b61f7c361364d6b292f1ab6b6f2e069", - [] - ], - "style-query-registered-custom-em-change-expected.txt": [ - "43f9cf1d5f35f985488188edb401ff26e7f8a319", - [] - ], "support": { "cq-testcommon.js": [ "8d1e03f2073fd2073bdbd0270ec9aa112030e55d", @@ -392290,11 +392595,11 @@ [] ], "flex-gap-decorations-fragmentation-005-ref.html": [ - "8441da751c46807baf11fb90231c0994d8f0414a", + "2de66ac4f320e4646d98fa6068720f1aa1fecb73", [] ], "flex-gap-decorations-fragmentation-006-ref.html": [ - "fcc0f3390299bf7f451e401e19a51cc4c0ac2929", + "a6611851a0a66f40d0f354176b17bde7fdc62cff", [] ], "flex-gap-decorations-fragmentation-007-ref.html": [ @@ -396638,6 +396943,10 @@ "cdab7615e4c5fe3f419c2b225bb6e4f7ee7d5f76", [] ], + "custom-highlight-painting-insert-node-001-ref.html": [ + "d538c550bad83b7cd8cce31d08388ed344877d8b", + [] + ], "custom-highlight-painting-invalidation-007-ref.html": [ "88f3d0f3d65cf46cc56fae34166d6c38db170eb2", [] @@ -406306,10 +406615,6 @@ "b96648717897f152af2e20027f341654fa163fd9", [] ], - "ruby-overhang-valid-expected.txt": [ - "90662ecb902fed2b438ef765fba53df80a5826e4", - [] - ], "ruby-position-valid-expected.txt": [ "fb9d02f463fbae680f351bb6b7f8e771d38cdfb9", [] @@ -406565,8 +406870,8 @@ "6106d56faf758a77c4329a8b00c7863ae0f844f2", [] ], - "ruby-overhang-ref.html": [ - "09b3d4608a77546739bee3b9cd4a5862057a6c03", + "ruby-overhang-none-ref.html": [ + "7da60b10d54a49348c39781d8aace10d228567b4", [] ], "ruby-overhang-spaces-001-ref.html": [ @@ -406785,6 +407090,10 @@ "65195af621adc4fb9ce78387c01247c322f89da8", [] ], + "prefer-targeted-element-both-axes-iframe.html": [ + "fdea771b15676df78f4c091502ac5375e8586eda", + [] + ], "prefer-targeted-element-iframe.html": [ "35b0684b26febc6255702b0560a46cb816596725", [] @@ -412249,7 +412558,7 @@ [] ], "text-autospace-preformatted-001-ref.html": [ - "d3679fc164beaf15b1596a7ad4b36c58b431b6be", + "3d8234f2ea30a911d5ce89f3da5e5abbe0d305f8", [] ], "text-autospace-supplementary-ideograph-ref.html": [ @@ -412298,6 +412607,10 @@ "a7f5e93138769a5515372fa8cf293c3ffa47b4d3", [] ], + "grow-dynamic-ref.html": [ + "7b3e49fede8427173a8f37fbe6fa1b6ebb9cc3c3", + [] + ], "grow-per-line-all-line-height-ref.html": [ "cad68c01e3b118dc85da8c27d3325c658eb621a3", [] @@ -412318,6 +412631,10 @@ "c91a6a47a99d5c7d2ed64daf774eef02d49c0569", [] ], + "shrink-dynamic-ref.html": [ + "9317b6666356b55c0e22f9ac1db15c2391e229a7", + [] + ], "shrink-per-line-all-ref.html": [ "870840d627fe9f49c7fa4059de0bc00ba55627e3", [] @@ -419113,6 +419430,10 @@ "888a51ea9b6ac04fb065ee5d84a18be8fe765aca", [] ], + "html-attr-case-insensitivity-ref.html": [ + "b20171db1b98aaf2e33a391505a9e05c7c1d16c0", + [] + ], "inline-cache-base-uri": { "inline-cache-base-uri.css": [ "df719dd6cc5ed6996ffd0762f9ee380394cab9de", @@ -426465,7 +426786,7 @@ [] ], "sound-state-expected.txt": [ - "ae2a58d0c249d6c0f159a404c151a6f83b9bfbe2", + "eaa0be79b8668b177382a4f4ece7e59ccb00b0ba", [] ], "support": { @@ -427193,10 +427514,6 @@ } }, "registries": { - "ShadowRoot-init-declarative-expected.txt": [ - "89735359072021bcd2f0eada39d68ac5b1b0bc51", - [] - ], "WEB_FEATURES.yml": [ "627c7bbb9d0cb8827e0b839a6a65555c6dc3c266", [] @@ -427809,7 +428126,7 @@ ] }, "test-suite-design.md": [ - "88c5f4af9bfb36ef0ee44ee513001f013f881697", + "6dd9294d66ef8d9e0e3c9dd3b3ff48c5fdb5e07d", [] ], "wpt_lint_rules.py": [ @@ -427817,6 +428134,10 @@ [] ], "writing-tests": { + "aamtest.md": [ + "273dff7c9f96e07772a9cefe6c3c79202e6cdf5b", + [] + ], "ahem.md": [ "30a3fcde26cd48910549c23dc0cd0fbc05e7b3c7", [] @@ -437194,6 +437515,10 @@ "ad5edf79866273d0debb2dbc438e6dec6f305cd3", [] ], + "keyboard-lock-inner.sub.html": [ + "840124e1f1aa19c115b9fa9ab5b1730984ddddd8", + [] + ], "navigate.sub.html": [ "4630c2e1c5fda7f6a5da4d49c9f71daad9af0edc", [] @@ -438113,15 +438438,7 @@ "da279ebf82f73d7eac9266cd71cce1185504066f", [] ] - }, - "window-open-popup-during-load-expected.txt": [ - "fc56a525c7608189996adccd820cbc95ab556ddd", - [] - ], - "window-open-popup-during-pageshow-expected.txt": [ - "fc56a525c7608189996adccd820cbc95ab556ddd", - [] - ] + } }, "resources": { "blank.html": [ @@ -449234,7 +449551,7 @@ [] ], "input-text-indent-ref.html": [ - "b4dc8a8c9470b701016aac9309fa4a2f4114ed41", + "8b4f2d90a5a2e6e0e7494659617e363cffa67179", [] ], "input-type-change-from-image-1-ref.html": [ @@ -450772,6 +451089,12 @@ [] ] } + }, + "user-interface": { + "muted-expected.txt": [ + "b3e85f3fde84a466c1713d1d3e710be255e794f9", + [] + ] } }, "resources": { @@ -451504,7 +451827,7 @@ [] ], "sizes-iframed.sub.html": [ - "8ad656749abcfb4a8a149dda6d479ec1a775048e", + "4aa353dce76de7d58097afb654f82aced90a7ca0", [] ] } @@ -452969,7 +453292,7 @@ [] ], "interestfor-pseudo-element-appearance-ref.html": [ - "255ddac5d770e4c2bb88cae02af2f351bdf9c3e1", + "a402bd2ac597b22aed1cd5cb2801c053612efacd", [] ], "interestfor-pseudo-element-dynamic-ref.html": [ @@ -452981,6 +453304,10 @@ [] ], "resources": { + "interest-button-styles.css": [ + "82bbc1f9bf7408cc3a5188cd42d1d9c4e1c2ad75", + [] + ], "invoker-utils.js": [ "2a5e7498f2c7725e743db905345d3a65297feebd", [] @@ -454863,7 +455190,7 @@ [] ], "cross-origin.py": [ - "abac1901b7d678964811197b5486365e40053f35", + "bd2a9b804539fa00b0e855edda9aa9bf28dedfdb", [] ], "exports-cocoa.js": [ @@ -455039,15 +455366,15 @@ [] ], "ignore-content-type.any-expected.txt": [ - "c97a7246f67152fa19970ecec58ba7a2b26fac8b", + "dbb18d9ecd54f1e55f987e0e473a29d1d2a8e4e6", [] ], "ignore-content-type.any.sharedworker-expected.txt": [ - "c97a7246f67152fa19970ecec58ba7a2b26fac8b", + "dbb18d9ecd54f1e55f987e0e473a29d1d2a8e4e6", [] ], "ignore-content-type.any.worker-expected.txt": [ - "c97a7246f67152fa19970ecec58ba7a2b26fac8b", + "dbb18d9ecd54f1e55f987e0e473a29d1d2a8e4e6", [] ], "ignore-extension.any-expected.txt": [ @@ -455063,7 +455390,7 @@ [] ], "integrity-expected.txt": [ - "48b101bb3badacbff32ef5c65bde5aed58145cb8", + "a795128f6a0389e8c9371f886a84193d595fe52a", [] ], "integrity-matches.js": [ @@ -455095,15 +455422,15 @@ [] ], "repeated-imports.any-expected.txt": [ - "7703bf8bd6538c88b5383beff18a9f5b08f176f4", + "331d92304142f822c1b1ccb4d1d7a39eba117896", [] ], "repeated-imports.any.sharedworker-expected.txt": [ - "7703bf8bd6538c88b5383beff18a9f5b08f176f4", + "331d92304142f822c1b1ccb4d1d7a39eba117896", [] ], "repeated-imports.any.worker-expected.txt": [ - "7703bf8bd6538c88b5383beff18a9f5b08f176f4", + "331d92304142f822c1b1ccb4d1d7a39eba117896", [] ], "serve-js-then-text.py": [ @@ -455519,7 +455846,7 @@ ], "charset": { "README.md": [ - "eaa708507cb42702603c72da1c29b1c3fc9006a9", + "33a78e6a1318866521312248012ab6c642279dde", [] ], "inheritance-bogus-meta-expected.txt": [ @@ -455696,6 +456023,30 @@ "e88aae9e4db26e467cde9bd734f5ce4a81d48395", [] ], + "html5lib_tests7_run_type=uri-expected.txt": [ + "f315446b102914bb6e76a59634c63616f86f1ae5", + [] + ], + "html5lib_tests7_run_type=write-expected.txt": [ + "f315446b102914bb6e76a59634c63616f86f1ae5", + [] + ], + "html5lib_tests7_run_type=write_single-expected.txt": [ + "f315446b102914bb6e76a59634c63616f86f1ae5", + [] + ], + "html5lib_webkit02_run_type=uri-expected.txt": [ + "973dea4d79f3fc67484358b2ddf16c5ad0c03ac2", + [] + ], + "html5lib_webkit02_run_type=write-expected.txt": [ + "973dea4d79f3fc67484358b2ddf16c5ad0c03ac2", + [] + ], + "html5lib_webkit02_run_type=write_single-expected.txt": [ + "973dea4d79f3fc67484358b2ddf16c5ad0c03ac2", + [] + ], "inhead-noscript-head-expected.txt": [ "9b05679a190f8260ad0dc6870f41e0ee10813fb6", [] @@ -461120,6 +461471,10 @@ "cf2a9a5ef403c4415fe74bf8fae2c7bd2d3ba24c", [] ], + "hdr-alpha-reftest-ref.html": [ + "26e0d3dac0ba2a06c6f74230c6b102ed1be349e4", + [] + ], "html-embed-object-iframe-ref.html": [ "acaa6a238497686ca164dbed17cde78ad0359dc0", [] @@ -461305,6 +461660,14 @@ "c5def3bbe5f2de1cfed122c6709c8807a92e227f", [] ], + "hdr_alpha.jxl": [ + "68226864c8b81fef4facad21f9c602e1d5d1d8c9", + [] + ], + "hdr_alpha.png": [ + "320c0f4843bc913f3a838e1b87c7e8e19ea6fc96", + [] + ], "hdr_hlg_test.jxl": [ "c7a1f342d7c39bf4f376a93ef888cfc45ad22158", [] @@ -461373,6 +461736,14 @@ "3cf484d968fff55fb51cfe6c4b24a386bde21c6f", [] ], + "sdr_alpha.jxl": [ + "9982d7295dc3a9a5480a38a7b0e16bf11f38eec0", + [] + ], + "sdr_alpha.png": [ + "37c22d64e65ba3916125b7017923dc11aed13be5", + [] + ], "smallest_valid.jxl": [ "615989a5ca12529c5a5566d73f0b9ba5a2364f2c", [] @@ -461398,6 +461769,10 @@ [] ] }, + "sdr-alpha-reftest-ref.html": [ + "2b22c7a2984ee76528b2a987018ccbb94b91db99", + [] + ], "smallest-valid-reftest-ref.html": [ "1c72b20dc82bb9f8f309da2273393b5a117bef81", [] @@ -461642,7 +462017,7 @@ } }, "lint.ignore": [ - "408729b9df62f009faa94428bd6d39c417dcea93", + "7b21a36c4585f5e914f365f858ec66da84f2e8fb", [] ], "loading": { @@ -465343,6 +465718,10 @@ "3f15c73b11ad450d7f876c1ce3b167ab2ed614f4", [] ], + "autofocus_same-checkpoint-expected.txt": [ + "4e68ee1b68fe649c0dc666fa806f6763064a459f", + [] + ], "resources": { "helpers.mjs": [ "fd611e806292e8165e96604bc8e1fcb405326292", @@ -465507,14 +465886,98 @@ "628b22ec48b7d0e93504eba7c734a74a916279ae", [] ], + "anchor-download-intercept-reject_currententrychange-expected.txt": [ + "79b976e3d8e6fed94821b7ded76ea2f3c60d4406", + [] + ], + "anchor-download-intercept-reject_no-currententrychange-expected.txt": [ + "b646f357444a48a7783371c8538c8f5aa113efeb", + [] + ], + "anchor-download-intercept_currententrychange-expected.txt": [ + "ca30c0c131216590902c2cdae8a2077dffb6955f", + [] + ], + "anchor-download-intercept_no-currententrychange-expected.txt": [ + "3ee4d276e473ecc27ceef6eaf6ee6642299f44c1", + [] + ], "back-cross-document-event-order-expected.txt": [ "67bdfe967ff1f2f9ea10bc3fbd2ab5a2d75ae00c", [] ], + "location-href-intercept-reject_currententrychange-expected.txt": [ + "6f5cd8862e6ff8a5977c5a91a29d25137864fdb1", + [] + ], + "location-href-intercept-reject_no-currententrychange-expected.txt": [ + "bbc7ede5362946c7f5c5286fa6ea04dac463fb81", + [] + ], + "location-href-intercept_currententrychange-expected.txt": [ + "76c0770d53b63ddee6bc9422c6ad62a6839f9f93", + [] + ], + "location-href-intercept_no-currententrychange-expected.txt": [ + "6b89912302c810d3277c724817ba4fa31b745e10", + [] + ], "navigate-cross-document-event-order-expected.txt": [ "b0cf970d08c52160b6da8b7261463f9d0729c2be", [] ], + "navigate-in-transition-finished_currententrychange-expected.txt": [ + "010add63f617998613b463da63f65099bde02944", + [] + ], + "navigate-in-transition-finished_no-currententrychange-expected.txt": [ + "5e18b22409cbbdc41682ec565c58c4a010a26fa9", + [] + ], + "navigate-intercept_currententrychange-expected.txt": [ + "7748f79551416254932afb010e8bcb34c7bbd8a8", + [] + ], + "navigate-intercept_no-currententrychange-expected.txt": [ + "0acee3958a7807c08065d8ca53212c218e5fd397", + [] + ], + "navigate-same-document-intercept-reject_currententrychange-expected.txt": [ + "81a0c84989a64f39c4303d8d64f3f5734bd4e38c", + [] + ], + "navigate-same-document-intercept-reject_no-currententrychange-expected.txt": [ + "744c8623574dc16a79b823324bdf0da02f68dcb0", + [] + ], + "navigate-same-document_currententrychange-expected.txt": [ + "33b4bbf7b55fbc0da914e4dacc665cfec075ed9e", + [] + ], + "navigate-same-document_no-currententrychange-expected.txt": [ + "82f9fc229c2ab7d7af2d05b49886515db4ca62ab", + [] + ], + "reload-intercept-reject_currententrychange-expected.txt": [ + "42e114c858ecc243d28e0d2aa588a46d8d79ce91", + [] + ], + "reload-intercept-reject_no-currententrychange-expected.txt": [ + "96d82c24a0395be856664c20b73d4013bee0188b", + [] + ], + "reload-intercept_currententrychange-expected.txt": [ + "39f1916b3c2d34986231c36eb97cd9fbaa34d1cb", + [] + ], + "reload-intercept_no-currententrychange-expected.txt": [ + "468af8f396773b4fa183d825bd1280a7d5e41d6e", + [] + ], + "reload-no-popstate-expected.txt": [ + "39f1916b3c2d34986231c36eb97cd9fbaa34d1cb", + [] + ], "resources": { "helpers.mjs": [ "22752e4cfed7baaf26afc52db6569feb1af07e2a", @@ -465527,6 +465990,10 @@ } }, "precommit-handler": { + "precommitHandler-window-stop-before-commit-expected.txt": [ + "59f4a80c8d4cb924dda0689aacc20fc48aca0c4c", + [] + ], "resources": { "precommitHandler-helpers.js": [ "1338617681feb373a47052a7f605f44d3eca2a16", @@ -471211,10 +471678,6 @@ "8c03d3e3350fe36498753af9021c04431738068d", [] ], - "scroll-timeline-shorthand-expected.txt": [ - "ed640009fa43cf386da64dbabb64e25dbbbe05ef", - [] - ], "support": { "animation-range.css": [ "1ebd0b429b228ec088bd024696180893b1922d2d", @@ -471236,10 +471699,6 @@ "view-timeline-pseudo-on-scroller-expected.txt": [ "9a02af2f2900fcdc02a24460814da45bc90ddea9", [] - ], - "view-timeline-shorthand-expected.txt": [ - "96fbbc1cb40dca154e8b4005f4a598ebfb14dd4c", - [] ] }, "scroll-timelines": { @@ -477066,19 +477525,19 @@ ] }, "from.any-expected.txt": [ - "9045cde676b5d31368fdfb6e6ee9708e6d209849", + "ccbc6617482a5dfb66ea7778ed861d232b53c949", [] ], "from.any.serviceworker-expected.txt": [ - "9045cde676b5d31368fdfb6e6ee9708e6d209849", + "ccbc6617482a5dfb66ea7778ed861d232b53c949", [] ], "from.any.sharedworker-expected.txt": [ - "9045cde676b5d31368fdfb6e6ee9708e6d209849", + "ccbc6617482a5dfb66ea7778ed861d232b53c949", [] ], "from.any.worker-expected.txt": [ - "9045cde676b5d31368fdfb6e6ee9708e6d209849", + "ccbc6617482a5dfb66ea7778ed861d232b53c949", [] ], "general.any-expected.txt": [ @@ -479024,12 +479483,8 @@ "9264c265f71526b9e9700f1c9f37d7ac37309529", [] ], - "textpath-path-attr-empty-ref.tentative.svg": [ - "82230a6bd2f85b5feef830d9206e864cd037c8d0", - [] - ], "textpath-path-attr-ref.svg": [ - "51a780cbd1d02303b54781b8f0d6b298d59c13fe", + "b3687eabf11f58b269fc77e74e17e61fb5feadac", [] ], "textpath-pathlength-css-display-none-ref.tentative.svg": [ @@ -479791,6 +480246,10 @@ "trusted-types-sandbox-allow-scripts.html.headers": [ "6bd66164613016269ebcee6416ed41cdf312a42a", [] + ], + "trusted-types-secondary-document-expected.txt": [ + "4481d2259590973557617c683a0ab91cd32aa0de", + [] ] }, "ua-client-hints": { @@ -484134,6 +484593,10 @@ "51e62e2c98405e89671f23dd36dba550cb0789a3", [] ], + "audiobuffersource-playbackrate-negative-expected.txt": [ + "b1ce0e0324bd4f0492e589466e0364a38193d600", + [] + ], "resources": { "audiobuffersource-multi-channels-expected.wav": [ "ab9d5fe5a9dbd736a079f0cfd7966d5e064ed7ef", @@ -484517,7 +484980,7 @@ [] ], "README.md": [ - "4ce861ebefe76bd81069472df9e2e6b116d05523", + "8f54adcde8e1bde6b9b945a1dc5572cf6f005767", [] ], "WEB_FEATURES.yml": [ @@ -484756,6 +485219,10 @@ "e0d6a6bedcf12dad5ec45a768f638bf1cb1ec1e7", [] ], + "h264_444.mp4": [ + "c79ff88f2e6048e77b76b2f1223d90d918739a69", + [] + ], "h264_interlaced.mp4": [ "e6223318f010f916d18a7c3d4366de4e3846911a", [] @@ -484889,7 +485356,7 @@ [] ], "videoDecoder-codec-specific-setup.js": [ - "cb8d09d443809873bb6edc0d112e27994f5488ae", + "040d9f13a81af24ed8a05385ab310ad4b0ce9d48", [] ], "videoFrame-construction.any.worker-expected.txt": [ @@ -486915,14 +487382,24 @@ ] }, "idlharness.https.window-expected.txt": [ - "0d3582d53187afcfdd58f224c2e5b64278d42836", + "6ca09c162208aa99f05e81f1117332d4eed59dd5", [] ], "imperative": { "WEB_FEATURES.yml": [ "cf1d265b5d638446d9d8efac38fe7fe227bb0941", [] - ] + ], + "resources": { + "helpers.js": [ + "458365d604a5670f44e6f35393eecc9ca6991d2f", + [] + ], + "iframe-register-tool.html": [ + "6bb988a0bc52d12be379a7d398303b31952aed38", + [] + ] + } } }, "webmessaging": { @@ -490911,10 +491388,6 @@ "WEB_FEATURES.yml": [ "6c25506a9dd762e5fc883e5946fd8dec84c7d470", [] - ], - "sharedworker-in-worker-expected.txt": [ - "c78623fd940e3a073a64f580460387fa7d946d7c", - [] ] }, "beta": { @@ -490930,10 +491403,6 @@ "bef771ff9ebad32911f9d292a13ff9a9e602efd0", [] ], - "sharedworker.py": [ - "bd6f70e7d9478c3239c047618f815fb9e6a06ce3", - [] - ], "subsharedworker.js": [ "de6a8cacaf80f60e40d9df3c72d2376a7babc362", [] @@ -490976,14 +491445,6 @@ "0f9ce8eacf4aeab410d2b4c4254e0106d9e94e28", [] ], - "sharedworker.js": [ - "d0718cfdefc0fbcf06811e24dc88135f0f57a999", - [] - ], - "subsharedworker.js": [ - "e23602ff9c5654b726fc88e6aa0169416ee31d15", - [] - ], "subworker.js": [ "44407358e61256e4c5e761c9fa334528ced2f2bc", [] @@ -491130,10 +491591,6 @@ "61838162329cc5eba6fb66d2db384c2427ddcea7", [] ], - "expected-self-properties.worker-expected.txt": [ - "5e3cfcda75138a24879f0acb633980de0cfd5432", - [] - ], "null": [ "6d079b514cf50a42deb039a2503a6f7ca1f2f70d", [] @@ -492561,6 +493018,10 @@ [] ], "resources": { + "abort-during-navigation-iframe.html": [ + "836a90324668c57cbbd106f8115556dbeca41cd6", + [] + ], "accept-language.py": [ "b68cf355038ca9f9f938a5c3b2f5c75ebfd05487", [] @@ -522044,8 +522505,41 @@ ] ] }, + "supports-modern.tentative.https.any.js": [ + "709ffcd43e2962c1585388cda81bb5baae13c622", + [ + "WebCryptoAPI/supports-modern.tentative.https.any.html", + { + "script_metadata": [ + [ + "title", + "WebCrypto API: supports method tests for algorithms in https://wicg.github.io/webcrypto-modern-algos/" + ], + [ + "script", + "util/helpers.js" + ] + ] + } + ], + [ + "WebCryptoAPI/supports-modern.tentative.https.any.worker.html", + { + "script_metadata": [ + [ + "title", + "WebCrypto API: supports method tests for algorithms in https://wicg.github.io/webcrypto-modern-algos/" + ], + [ + "script", + "util/helpers.js" + ] + ] + } + ] + ], "supports.tentative.https.any.js": [ - "dd39273e4b918b4f835efc368407ca4accf440b0", + "921212a0c21dfa43dd30fbee5d284cf3de32cdf0", [ "WebCryptoAPI/supports.tentative.https.any.html", { @@ -522624,7 +523118,7 @@ ] ], "language-model-append.tentative.https.window.js": [ - "dbd9edd164a0e9915f8fded000688e66a5a2a282", + "8a6426ffb0c50b076bb5d37548359e9d6eb87051", [ "ai/language-model/language-model-append.tentative.https.window.html", { @@ -522654,15 +523148,15 @@ } ] ], - "language-model-availability-available-multimodal.tentative.https.window.js": [ - "a9caa0ebceff8cc8f2b938a5c408de7ee0a446a2", + "language-model-availability-available.tentative.https.window.js": [ + "40c149cb91d99ddb3808853bc39a9138ebef9386", [ - "ai/language-model/language-model-availability-available-multimodal.tentative.https.window.html", + "ai/language-model/language-model-availability-available.tentative.https.window.html", { "script_metadata": [ [ "title", - "Language Model Availability Available Multimodal" + "Language Model Availability Available" ], [ "script", @@ -522681,15 +523175,15 @@ } ] ], - "language-model-availability-available.tentative.https.window.js": [ - "40c149cb91d99ddb3808853bc39a9138ebef9386", + "language-model-availability-sampling-mode.tentative.https.window.js": [ + "55d31aa8f4ed921bc6980cac6065ef43e752ce9f", [ - "ai/language-model/language-model-availability-available.tentative.https.window.html", + "ai/language-model/language-model-availability-sampling-mode.tentative.https.window.html", { "script_metadata": [ [ "title", - "Language Model Availability Available" + "Language Model Prompt - Sampling Mode Availability" ], [ "script", @@ -522697,6 +523191,10 @@ ], [ "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", "../resources/util.js" ], [ @@ -522766,15 +523264,15 @@ } ] ], - "language-model-create-multimodal.tentative.https.window.js": [ - "6536ab84d7af4354a09504171f06732ab29c33ff", + "language-model-create-sampling-mode.tentative.https.window.js": [ + "63af92c5b70c75357b11d8eeb0b1a7fa6fce7785", [ - "ai/language-model/language-model-create-multimodal.tentative.https.window.html", + "ai/language-model/language-model-create-sampling-mode.tentative.https.window.html", { "script_metadata": [ [ "title", - "Language Model Create Multimodal" + "Language Model - Sampling Mode Create" ], [ "script", @@ -522927,37 +523425,6 @@ } ] ], - "language-model-measure-context-usage.tentative.https.window.js": [ - "ebeb74eab4464eea9e206e1af408d0d2686aa717", - [ - "ai/language-model/language-model-measure-context-usage.tentative.https.window.html", - { - "script_metadata": [ - [ - "title", - "Language Model Measure Input Usage" - ], - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "../resources/util.js" - ], - [ - "timeout", - "long" - ] - ], - "timeout": "long" - } - ] - ], "language-model-params.tentative.https.window.js": [ "2f8b198d70f2458be882440d246de453e03dd3e9", [ @@ -522989,312 +523456,6 @@ } ] ], - "language-model-prompt-context-destroyed.tentative.https.window.js": [ - "89dae3c1e9962cc9da6a0d187efc14c0145f41eb", - [ - "ai/language-model/language-model-prompt-context-destroyed.tentative.https.window.html", - { - "script_metadata": [ - [ - "title", - "Language Model Prompt Context Destroyed" - ], - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "../resources/util.js" - ], - [ - "timeout", - "long" - ] - ], - "timeout": "long" - } - ] - ], - "language-model-prompt-gc.tentative.https.window.js": [ - "db4823a454ad8cb8c94b14155528b7e462774344", - [ - "ai/language-model/language-model-prompt-gc.tentative.https.window.html", - { - "script_metadata": [ - [ - "title", - "Language Model Prompt GC" - ], - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "../resources/util.js" - ], - [ - "timeout", - "long" - ] - ], - "timeout": "long" - } - ] - ], - "language-model-prompt-monitor-callback-exception.tentative.https.window.js": [ - "e135a4b83a1538c4bf2b4d0d00a75b245ed424a6", - [ - "ai/language-model/language-model-prompt-monitor-callback-exception.tentative.https.window.html", - { - "script_metadata": [ - [ - "title", - "Language Model Prompt Monitor Callback Exception" - ], - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "../resources/util.js" - ], - [ - "timeout", - "long" - ] - ], - "timeout": "long" - } - ] - ], - "language-model-prompt-multimodal-audio.tentative.https.window.js": [ - "8aeae01d896cd912d79d5b55ea4e47e261ef6eba", - [ - "ai/language-model/language-model-prompt-multimodal-audio.tentative.https.window.html", - { - "script_metadata": [ - [ - "title", - "Language Model Prompt Multimodal Audio" - ], - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "../resources/util.js" - ], - [ - "timeout", - "long" - ] - ], - "timeout": "long" - } - ] - ], - "language-model-prompt-multimodal-image.tentative.https.window.js": [ - "7b5e29308ac1db416b80d90104f2040492ea4aa3", - [ - "ai/language-model/language-model-prompt-multimodal-image.tentative.https.window.html", - { - "script_metadata": [ - [ - "title", - "Language Model Prompt Multimodal Image" - ], - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "../resources/util.js" - ], - [ - "timeout", - "long" - ] - ], - "timeout": "long" - } - ] - ], - "language-model-prompt-multimodal-video.tentative.https.window.js": [ - "3cfdefa2dd138618a505646deec05588d71b4ca7", - [ - "ai/language-model/language-model-prompt-multimodal-video.tentative.https.window.html", - { - "script_metadata": [ - [ - "title", - "Language Model Prompt Multimodal Video" - ], - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "../resources/util.js" - ], - [ - "timeout", - "long" - ] - ], - "timeout": "long" - } - ] - ], - "language-model-prompt-multimodal.tentative.https.window.js": [ - "ab4155a05188519662d1f6c34f6d48d135febdb4", - [ - "ai/language-model/language-model-prompt-multimodal.tentative.https.window.html", - { - "script_metadata": [ - [ - "title", - "Language Model Prompt Multimodal" - ], - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "../resources/util.js" - ], - [ - "timeout", - "long" - ] - ], - "timeout": "long" - } - ] - ], - "language-model-prompt-streaming-gc.tentative.https.window.js": [ - "2acc83bc654f3d423559f98c0b309ce97e0e403c", - [ - "ai/language-model/language-model-prompt-streaming-gc.tentative.https.window.html", - { - "script_metadata": [ - [ - "title", - "Language Model Prompt Streaming GC" - ], - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "../resources/util.js" - ], - [ - "timeout", - "long" - ] - ], - "timeout": "long" - } - ] - ], - "language-model-prompt-streaming.tentative.https.window.js": [ - "b523204067c3a375cb68fa872435dd63c5971261", - [ - "ai/language-model/language-model-prompt-streaming.tentative.https.window.html", - { - "script_metadata": [ - [ - "title", - "Language Model Prompt Streaming" - ], - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "../resources/util.js" - ], - [ - "timeout", - "long" - ] - ], - "timeout": "long" - } - ] - ], - "language-model-prompt.tentative.https.window.js": [ - "a24cc106e2fee1d85c6639942022290e17837539", - [ - "ai/language-model/language-model-prompt.tentative.https.window.html", - { - "script_metadata": [ - [ - "title", - "Language Model Prompt" - ], - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "../resources/util.js" - ], - [ - "timeout", - "long" - ] - ], - "timeout": "long" - } - ] - ], "language-model-quota-exceeded.tentative.https.window.js": [ "fdd91c8fc95f23965e4af84b96c500483691a253", [ @@ -523326,68 +523487,6 @@ } ] ], - "language-model-response-json-schema.tentative.https.window.js": [ - "146fcaf8636d565145d8ce4ca4615541eea21c09", - [ - "ai/language-model/language-model-response-json-schema.tentative.https.window.html", - { - "script_metadata": [ - [ - "title", - "Language Model Response JSON Schema" - ], - [ - "script", - "/resources/testdriver.js" - ], - [ - "script", - "/resources/testdriver-vendor.js" - ], - [ - "script", - "../resources/util.js" - ], - [ - "timeout", - "long" - ] - ], - "timeout": "long" - } - ] - ], - "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", [ @@ -523418,7 +523517,1660 @@ "timeout": "long" } ] - ] + ], + "prompt": { + "context": { + "destroyed.tentative.https.window.js": [ + "72d50435089eca0f8d38fa0d7b6a7d63c4513945", + [ + "ai/language-model/prompt/context/destroyed.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Prompt Context Destroyed" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "measure.tentative.https.window.js": [ + "212b4b707f159a0fadd8d67101d39f0963973eb4", + [ + "ai/language-model/prompt/context/measure.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Measure Input Usage" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "overflow.tentative.https.window.js": [ + "8222052db461022af13ed3b1c689fe1e3b2b6326", + [ + "ai/language-model/prompt/context/overflow.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Prompt Context Overflow" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "usage-initial-prompt.tentative.https.window.js": [ + "86bba1d6c2a0891b8493a947d43a1553f5583ee0", + [ + "ai/language-model/prompt/context/usage-initial-prompt.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Prompt Context Usage - Initial Prompt" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "usage-prompt-quota-exceeded.tentative.https.window.js": [ + "bd069f6e40be6eef4c827bf8e878ffb433380e88", + [ + "ai/language-model/prompt/context/usage-prompt-quota-exceeded.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Prompt Context Usage - Prompt Quota Exceeded" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "usage.tentative.https.window.js": [ + "bd103c656e2b42b7740235354ccaf067a08a7429", + [ + "ai/language-model/prompt/context/usage.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Prompt Context Usage" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ] + }, + "empty-inputs": { + "empty-array-input.tentative.https.window.js": [ + "d1b92cadf0ee9224b041e86f1420b9e09a5706d0", + [ + "ai/language-model/prompt/empty-inputs/empty-array-input.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Prompt Empty Inputs - array" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "empty-object-input.tentative.https.window.js": [ + "d2ad23ecf238f75030ff921cc945cbc065878b4d", + [ + "ai/language-model/prompt/empty-inputs/empty-object-input.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Prompt Empty Inputs - object" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "empty-sequence-input.tentative.https.window.js": [ + "c29b21ea3df58093f5e9902a38845dfc7a010901", + [ + "ai/language-model/prompt/empty-inputs/empty-sequence-input.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Prompt Empty Inputs - sequence empty" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "empty-string-input.tentative.https.window.js": [ + "f6f86baa85e4167c49def17c327ea3c2c6d20041", + [ + "ai/language-model/prompt/empty-inputs/empty-string-input.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Prompt Empty Inputs - string" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "null-input.tentative.https.window.js": [ + "0c931507e4eddcda4c7983f51cc3d91b0fc3006e", + [ + "ai/language-model/prompt/empty-inputs/null-input.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Prompt Empty Inputs - null" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "sequence-with-empty-string-input.tentative.https.window.js": [ + "159b9f8e240f7dda9321219837485106f43813cd", + [ + "ai/language-model/prompt/empty-inputs/sequence-with-empty-string-input.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Prompt Empty Inputs - sequence string" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "undefined-input.tentative.https.window.js": [ + "770cb103d6ff45dee48b0ce204a1dee569611ff0", + [ + "ai/language-model/prompt/empty-inputs/undefined-input.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Prompt Empty Inputs - undefined" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ] + }, + "garbage-collection.tentative.https.window.js": [ + "81f4b8350832606bd8c8cd1009f4fbee651bb12e", + [ + "ai/language-model/prompt/garbage-collection.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Prompt GC" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "monitor-callback-exception.tentative.https.window.js": [ + "7b957c0ea952714c4e3eac7ed5bceb883c00f148", + [ + "ai/language-model/prompt/monitor-callback-exception.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Prompt Monitor Callback Exception" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "multimodal": { + "audio-input.tentative.https.window.js": [ + "b3aa13f424a6c37c4552507ff580a33a1ad646ad", + [ + "ai/language-model/prompt/multimodal/audio-input.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Prompt Multimodal Audio" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "availability.tentative.https.window.js": [ + "0ced9024aaf9920f77c30bf8c6dcb2a108566519", + [ + "ai/language-model/prompt/multimodal/availability.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Availability Available Multimodal" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "create.tentative.https.window.js": [ + "7f47ac30d019b9738c71aa43e86c9c54d472ad80", + [ + "ai/language-model/prompt/multimodal/create.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Create Multimodal" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "image": { + "array-buffer-view-offset.tentative.https.window.js": [ + "c2f6ac69a1a8df6bc7cc7d52869a5c8628d3146a", + [ + "ai/language-model/prompt/multimodal/image/array-buffer-view-offset.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Prompt Multimodal Image - ArrayBufferView Offset" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "array-buffer-view.tentative.https.window.js": [ + "e5fcdbd3a32823c7a740f09cdc1a562c8c8ccd8d", + [ + "ai/language-model/prompt/multimodal/image/array-buffer-view.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Prompt Multimodal Image - ArrayBufferView" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "array-buffer.tentative.https.window.js": [ + "a717110a66ef187c3744169798cd1b8fc30508e9", + [ + "ai/language-model/prompt/multimodal/image/array-buffer.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Prompt Multimodal Image - ArrayBuffer" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "blob.tentative.https.window.js": [ + "093cd58aed1a53bed52d5222668ed185a3f05945", + [ + "ai/language-model/prompt/multimodal/image/blob.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Prompt Multimodal Image - Blob" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "html-canvas-element.tentative.https.window.js": [ + "1452da15b4ab54e29fdf3402d08b84cbba75e167", + [ + "ai/language-model/prompt/multimodal/image/html-canvas-element.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Prompt Multimodal Image - HTMLCanvasElement" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "html-image-element-svg.tentative.https.window.js": [ + "774c2c4e3e858ef90bf0d250b95ca48916440344", + [ + "ai/language-model/prompt/multimodal/image/html-image-element-svg.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Prompt Multimodal Image - HTMLImageElement SVG" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "html-image-element.tentative.https.window.js": [ + "df9262354dadce80cc80185b32afc821e49998d9", + [ + "ai/language-model/prompt/multimodal/image/html-image-element.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Prompt Multimodal Image - HTMLImageElement" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "image-bitmap.tentative.https.window.js": [ + "f161bf8315bfa7cb811d1085f14b28aced1e9a2a", + [ + "ai/language-model/prompt/multimodal/image/image-bitmap.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Prompt Multimodal Image - ImageBitmap" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "image-data.tentative.https.window.js": [ + "92bab6ce2e5790d2a6e4905536aed39f3ca6f713", + [ + "ai/language-model/prompt/multimodal/image/image-data.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Prompt Multimodal Image - ImageData" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "initial-prompt.tentative.https.window.js": [ + "f167d2eea4ac2e0b82e7b0dfbb77112839975dbb", + [ + "ai/language-model/prompt/multimodal/image/initial-prompt.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Prompt Multimodal Image - Initial Prompt" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "offscreen-canvas.tentative.https.window.js": [ + "bf93afc2ce0f6a37c8607fce316180e89c26a278", + [ + "ai/language-model/prompt/multimodal/image/offscreen-canvas.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Prompt Multimodal Image - OffscreenCanvas" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "svg-image-element.tentative.https.window.js": [ + "843a47aa52b4912a81e0f57a63c5d22bb590a802", + [ + "ai/language-model/prompt/multimodal/image/svg-image-element.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Prompt Multimodal Image - SVGImageElement" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "without-image-expected-input.tentative.https.window.js": [ + "76034cc07e0a0b1165f66eff258d4a7fcd010860", + [ + "ai/language-model/prompt/multimodal/image/without-image-expected-input.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Prompt Multimodal Image - Without Image Expected Input" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ] + }, + "prompt-multimodal.tentative.https.window.js": [ + "31f8d2f69fc991eaf29c38600d079080ad090d25", + [ + "ai/language-model/prompt/multimodal/prompt-multimodal.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Prompt Multimodal" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "video": { + "html-video-element.tentative.https.window.js": [ + "3ea5c395827a7fb37598163acf7cdc2208ba06df", + [ + "ai/language-model/prompt/multimodal/video/html-video-element.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Prompt Multimodal Video - HTMLVideoElement" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "video-frame.tentative.https.window.js": [ + "96e61d24ac21d63715d46ba06a52d1d356bb5594", + [ + "ai/language-model/prompt/multimodal/video/video-frame.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Prompt Multimodal Video - VideoFrame" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ] + } + }, + "prompt-simple-question.tentative.https.window.js": [ + "b71a7e03064ca5d17b88c05aca7bb0362caa56ed", + [ + "ai/language-model/prompt/prompt-simple-question.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Prompt - Prompt Simple Question" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "prompt.tentative.https.window.js": [ + "795c997aa232514497091be3fa5c170dc979baf0", + [ + "ai/language-model/prompt/prompt.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Prompt" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "rejections.tentative.https.window.js": [ + "b99ef7696c14db0263bf7f32cc0ccb1c0cf77fe1", + [ + "ai/language-model/prompt/rejections.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Prompt Rejections" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "streaming": { + "empty-array-input.tentative.https.window.js": [ + "177a85b5ea0b1f1d76d21000441c399c2f421455", + [ + "ai/language-model/prompt/streaming/empty-array-input.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Prompt Streaming - array" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "empty-object-input.tentative.https.window.js": [ + "99bd812be87d90ad83c71df06b5a989f9a757489", + [ + "ai/language-model/prompt/streaming/empty-object-input.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Prompt Streaming - object" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "empty-sequence-input.tentative.https.window.js": [ + "556ef2c0f6faa8ee0213d27aba00ddd43f751b88", + [ + "ai/language-model/prompt/streaming/empty-sequence-input.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Prompt Streaming - sequence empty" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "empty-string-input.tentative.https.window.js": [ + "ec139cf655bbc503a53323704d3b25f87488a460", + [ + "ai/language-model/prompt/streaming/empty-string-input.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Prompt Streaming - string" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "garbage-collection.tentative.https.window.js": [ + "6ed73e13cd9ed3f6502afe5f327a850b61a84840", + [ + "ai/language-model/prompt/streaming/garbage-collection.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Prompt Streaming GC" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "null-input.tentative.https.window.js": [ + "6f84f6f235710cf026d448413b9f82841c9a2a95", + [ + "ai/language-model/prompt/streaming/null-input.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Prompt Streaming - null" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "prompt-streaming.tentative.https.window.js": [ + "e4d223f75518076fea036498c40319e8cd31e194", + [ + "ai/language-model/prompt/streaming/prompt-streaming.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Prompt Streaming" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "sequence-with-empty-string-input.tentative.https.window.js": [ + "cf956539ae9dda48e626d898c09f2e6078e23403", + [ + "ai/language-model/prompt/streaming/sequence-with-empty-string-input.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Prompt Streaming - sequence string" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "undefined-input.tentative.https.window.js": [ + "fb8436cae17a1e7cb5a68fd056e4070361d98449", + [ + "ai/language-model/prompt/streaming/undefined-input.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Prompt Streaming - undefined" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ] + } + }, + "response-constraint": { + "json-schema": { + "circular-references-rejection.tentative.https.window.js": [ + "b87029b459543ead341fbe511476f9907c5704bf", + [ + "ai/language-model/response-constraint/json-schema/circular-references-rejection.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Response JSON Schema - Circular References Rejection" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "invalid-type-rejection.tentative.https.window.js": [ + "d5650cfd285b3a77a8579192d258fe60c733a200", + [ + "ai/language-model/response-constraint/json-schema/invalid-type-rejection.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Response JSON Schema - Invalid Type Rejection" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "prefix-deviation-rejection.tentative.https.window.js": [ + "5bd136f86972cf1f50dbd5af531323320da7f087", + [ + "ai/language-model/response-constraint/json-schema/prefix-deviation-rejection.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Response JSON Schema - Prefix Deviation Rejection" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "response-schema-omitted-from-input.tentative.https.window.js": [ + "01cb219cdcff55f0c8a9041b39ac3ced34d55761", + [ + "ai/language-model/response-constraint/json-schema/response-schema-omitted-from-input.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Response JSON Schema - Omitted from Input" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "valid-schema-success.tentative.https.window.js": [ + "541a549f4d83d6f0580b01b2ce23e3cb248e4fdf", + [ + "ai/language-model/response-constraint/json-schema/valid-schema-success.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Response JSON Schema - Valid Schema Success" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "valid-schema-with-prefix-success.tentative.https.window.js": [ + "3aa704d1d1b967ec95d6ef5bc7a6296e9ec8f3a8", + [ + "ai/language-model/response-constraint/json-schema/valid-schema-with-prefix-success.tentative.https.window.html", + { + "script_metadata": [ + [ + "title", + "Language Model Response JSON Schema - Valid Schema With Prefix Success" + ], + [ + "script", + "/resources/testdriver.js" + ], + [ + "script", + "/resources/testdriver-vendor.js" + ], + [ + "script", + "../../../resources/util.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ] + }, + "regex.tentative.https.window.js": [ + "b57186b95d831dc138d1bc049e213a57b6a932a2", + [ + "ai/language-model/response-constraint/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_detection": { "detector-iframe.https.html": [ @@ -523574,7 +525326,7 @@ ] ], "proofreader-proofread.tentative.https.window.js": [ - "4febc4446c7b146eafb4e4f10ac06e581283c994", + "d4e5b99c0e96bb11820f9ad6b266dd24c16f3b25", [ "ai/proofreader/proofreader-proofread.tentative.https.window.html", { @@ -543740,6 +545492,13 @@ ] }, "inheritance": { + "auxiliary-blank-document.html": [ + "d7de318c3a66d9d7b7e50681d5a633bff92df3dd", + [ + null, + {} + ] + ], "blob-inherits-from-meta-http-equiv-with-invalid-characters.html": [ "c7ac08b25079162f07f443fdea38ee38eea59987", [ @@ -543771,7 +545530,7 @@ ] ], "document-write-iframe.html": [ - "73614e3aa2da597d17564ce290c1c0741eed4c92", + "07f0e2931fa0e9690c45778850964b4714b5a7f0", [ null, {} @@ -543785,7 +545544,7 @@ ] ], "history-iframe.sub.html": [ - "1f6960531ebab658df4ed02093cae67f9b9ac963", + "49e6a5fae1b5d2d9918c4a3bc467d0f89b9e9480", [ null, { @@ -543794,7 +545553,7 @@ ] ], "history.sub.html": [ - "5ea6abe8fb33344f38a0bdc7cf867ee72d692522", + "a0fda8c151890376d82c67cd77579c7bd4a904eb", [ null, {} @@ -544029,6 +545788,20 @@ {} ] ], + "media-src-blocked-blob-url.html": [ + "6c42acf628daaddd519e59eaea66391ef9225214", + [ + null, + {} + ] + ], + "media-src-blocked-data-url.html": [ + "b419479571155ab1ee1ffb388f34d7003c792a4d", + [ + null, + {} + ] + ], "media-src-blocked.sub.html": [ "16c36dfb2047592e728ce8276e1ee6368d7d0007", [ @@ -545388,34 +547161,6 @@ {} ] ], - "script-url-blocked-report-contains-hash-dedicated-worker.https.html": [ - "924adc04c63b417e9e77d10538f05a0887d838b1", - [ - null, - {} - ] - ], - "script-url-blocked-report-contains-hash-service-worker.https.html": [ - "a6baad4b9d1522d5ea160a1f7926323be0c000f8", - [ - null, - {} - ] - ], - "script-url-blocked-report-contains-hash-shared-worker.https.html": [ - "cf71b7b93fc804662d785f923632cf4095333831", - [ - null, - {} - ] - ], - "script-url-blocked-report-contains-hash.https.html": [ - "67494583c10b751ac857a5be4fe6304213994161", - [ - null, - {} - ] - ], "url-hash-in-header-and-meta.https.html": [ "77cadf521e4011e8d9dfcb82ee9720fdec26be90", [ @@ -552652,7 +554397,7 @@ ] ], "position-anchor-basics.html": [ - "a5179ebe13479445554c1c452c5054191f0e0d10", + "4fd25d8d7caa305cc51a561d201dc2d2101e5144", [ null, {} @@ -557593,7 +559338,7 @@ ] ], "at-container-style-parsing.html": [ - "1bb5e1a7e7bda911ef746b232b4aad571401cf77", + "36a4f7014140f047dff17514ce03bafeb0efc564", [ null, {} @@ -558258,7 +560003,7 @@ ] ], "query-evaluation-style.html": [ - "a144f4e4b707a22226a023fde2037facba8b4274", + "01ebda5ea9d2f7aba2e54380bc1bebc93ba52c71", [ null, {} @@ -559036,7 +560781,14 @@ {} ] ] - } + }, + "match-container.tentative.html": [ + "981d419b7410f6a1ef8652b2b68145222c7dfd9c", + [ + null, + {} + ] + ] }, "css-contain": { "contain-chrome-thcrash-001.html": [ @@ -561194,7 +562946,7 @@ ] ], "flex-baseline-overflow-hidden.html": [ - "661c1ed52d06cf9f7649bf4193fa0c8b077e6f3b", + "36bbd61e390fd91f93e0adeb294d6e7ba47835d6", [ null, {} @@ -576000,6 +577752,15 @@ {} ] ], + "pseudo-element-removal.html": [ + "0646f55fd4da6d472b84a1a3937ffd6f270eb52c", + [ + null, + { + "testdriver": true + } + ] + ], "pseudo-replaced-elements.html": [ "8b5f994841b8e8e4f3aea05465926ee429a5718a", [ @@ -576172,7 +577933,7 @@ ] ], "inheritance.html": [ - "3120e92a7af8bc5f55eb9417a00e78c02e2346d5", + "fd678a1d768b73df2ae0ce2b9303f85faa62506d", [ null, {} @@ -576229,7 +577990,7 @@ ] ], "ruby-overhang-valid.html": [ - "c83d25141bbaceedfc942e976867976eabd46de5", + "7fa8662c098d3cf2ac1363ed9495d585362f828b", [ null, {} @@ -577504,7 +579265,7 @@ ] ], "nested-supercedes-common-to-both-axes.html": [ - "c76ba27b83c08bea790033965f0f5d4e005f785f", + "ecebe43c696d377f46fab56014a552f6020482d1", [ null, { @@ -577549,7 +579310,7 @@ ] ], "prefer-inner-target.html": [ - "feefbe1b5e3f41d66419e71788bef8e0b56481dc", + "aaf26d4410e24a27a6f476a8ef2a7735b25016cc", [ null, { @@ -577557,6 +579318,13 @@ } ] ], + "prefer-targeted-element-both-axes.html": [ + "e488a611b53d5e72fb73c096c173495f74ea6511", + [ + null, + {} + ] + ], "prefer-targeted-element-main-frame.html": [ "65ffee164eedb9829c6e9c259fa2a926c4e31520", [ @@ -578851,6 +580619,20 @@ null, {} ] + ], + "shape-outside-path-interpolation.html": [ + "59ff7497b62363b30de8edca4d2314960f04ccdc", + [ + null, + {} + ] + ], + "shape-outside-shape-interpolation.html": [ + "ef0a42b4e811f7f05db7d0651b8b24c059aa08a1", + [ + null, + {} + ] ] }, "basic-shape-circle-ellipse-serialization.html": [ @@ -591705,7 +593487,7 @@ ] ], "url-request-modifiers-font-face-parsing.html": [ - "00ac3b79910597b0f018a754c0101274b0e09cad", + "97547eab1b94d90a62f471d2c9a14b68cf3f2679", [ null, {} @@ -591719,14 +593501,14 @@ ] ], "url-request-modifiers-invalid.sub.html": [ - "bc0e0c2bc6f7c04a8d8c0fd326ddb2691bacaca3", + "178417fca7387e0d6081128e4988b8efd4088a10", [ null, {} ] ], "url-request-modifiers-serialize.sub.html": [ - "e60a0a268d4389d2ee715f394f05ae55a9a2bba8", + "5ea2b5c6b97efce8604d62a24ed6295b90b08266", [ null, {} @@ -593366,6 +595148,13 @@ {} ] ], + "font-size-keyword-system-font.html": [ + "ae5f9d1f101db57c6b0db2173a1e75b93a85d0eb", + [ + null, + {} + ] + ], "ic-unit.html": [ "680129016dee85365577dd9ca3059f7f1fa9478e", [ @@ -594397,7 +596186,7 @@ ] ], "adoptedstylesheets-observablearray.html": [ - "783a0541633d3f2b5fdfae90c364ffa8350be561", + "75d8ffc5c38c5d7dac8b1d6370fd23419c2a2af7", [ null, {} @@ -595323,7 +597112,7 @@ ] ], "stylesheet-same-origin.sub.html": [ - "6ad55190dab366f2d9e4bdf7755750d7f5945bbe", + "10097132993581d0fc41ba5a718e2e339b0ba19e", [ null, {} @@ -599042,6 +600831,13 @@ {} ] ], + "empty-pseudo-in-has-display-none.html": [ + "8513f39a6ada89f0f0bd2850cb21913b6bed2f50", + [ + null, + {} + ] + ], "empty-pseudo-in-has.html": [ "4e9f6f27378fb9579728cad3f9208b97d48f1b96", [ @@ -599625,7 +601421,7 @@ ] ], "sound-state.html": [ - "e41e4ace2be507eaa686aa054c838cc84cb46ab5", + "fd0e8f53a4318e3d72f1ce565c47d955a1a3c01d", [ null, {} @@ -599991,7 +601787,7 @@ ] ], "webkit-pseudo-element.html": [ - "30103fa72bf479fb80e75c03058f33a150119be8", + "babf2301143256ee0005dcbfbd3aafb5624b3e84", [ null, {} @@ -600223,6 +602019,15 @@ {} ] ], + "ElementInternals-behavior-accessibility.tentative.html": [ + "1d7d0515a97e16cd323518af9e9d68b46428527a", + [ + null, + { + "testdriver": true + } + ] + ], "ElementInternals-form.html": [ "fd9363b4506305a0f915d9035239f57432e7a1d4", [ @@ -600259,7 +602064,7 @@ ] ], "ElementInternals-submit-behavior.tentative.html": [ - "a1f13560f30b47be7e53db571d148739b0b4b9cf", + "ce632503ca0018dfad20d5bdf17c63af91f0102f", [ null, { @@ -600996,14 +602801,14 @@ ] ], "ShadowRoot-init-customElementRegistry.html": [ - "b81fbce26d6a7514a54be0d2d5e40cb2bdb3ae6c", + "a392b50e50f6963ca5f0c6b4882a580f76f943c6", [ null, {} ] ], "ShadowRoot-init-declarative.html": [ - "13359df5e60d42b0d7642005f15225bee8eec4ed", + "01863a2d44eb3aac2540cfe2780bd6d3e40b9b13", [ null, {} @@ -601052,7 +602857,7 @@ ] ], "element-mutation.html": [ - "dd292b4a75ee25d60e99fe88266003cc50a8a787", + "d1020568adc722553b7ffede09cb1410cafc82de", [ null, {} @@ -601101,7 +602906,7 @@ ] ], "scoped-registry-append-does-not-upgrade.html": [ - "f93dbb1335b0a3163e798d8b889a4cedf8598d50", + "581b7eeaec3e5b48ba6b3b8ac964fe778912d894", [ null, {} @@ -601747,7 +603552,7 @@ ] ], "create.tentative.https.html": [ - "cc9690f504f5f647660e5a958737a9796d3017f1", + "6a48524c943b9b61b61c6803d76d74c980d68a7f", [ null, { @@ -601772,7 +603577,7 @@ ] ], "digital-credentials-static-methods.tentative.https.html": [ - "a92288b29485fa334335f8d2f084fc36354de87e", + "bb5e6ce2acbc27bc11589d310c0627b412278833", [ null, {} @@ -601806,7 +603611,7 @@ ] ], "get.https.html": [ - "0c7f640773ddacb018cab01909a8a7f1b265c2ea", + "8593bf2fb0bb0d80b6af8b20e2635c1f7deff2db", [ null, { @@ -608322,6 +610127,13 @@ } ] ], + "delete-editing-host.html": [ + "748c40937d47bfcdfda38325a0f9a63f5c844c62", + [ + null, + {} + ] + ], "delete-in-child-of-head.tentative.html": [ "978cf83d47add5ef754e588074844d0e624dfa27", [ @@ -630280,74 +632092,6 @@ } ] ], - "notify-event-iframe.https.html": [ - "1f8e1b8a322d3a8c2b63d2083c7d13c0b1f09491", - [ - null, - { - "testdriver": true, - "timeout": "long" - } - ] - ], - "notify-event-invalid.https.html": [ - "7695f49e0b606eb938bc6e32d5cdb9070b740b0f", - [ - null, - { - "testdriver": true, - "timeout": "long" - } - ] - ], - "notify-event-nested-fenced-frames.https.html": [ - "d435cbc009d51ed958fd537009663e1ada289575", - [ - null, - { - "testdriver": true - } - ] - ], - "notify-event-prevent-caching.https.html": [ - "9511dce8c8dbad82a0f2fb0681d59fa6876ccf50", - [ - null, - { - "testdriver": true, - "timeout": "long" - } - ] - ], - "notify-event-success.https.html": [ - "76ed9abbfa05cabdd6540363d0af4dfcc72900c5", - [ - null, - { - "testdriver": true - } - ] - ], - "notify-event-top-level-navigation.https.html": [ - "da3435dc607b08b2ebbd6e5af64172d12db19165", - [ - null, - { - "testdriver": true, - "timeout": "long" - } - ] - ], - "notify-event-transient-user-activation.https.html": [ - "5e37b1180ad1da5937328e903c51da59d4e4c9d6", - [ - null, - { - "testdriver": true, - "timeout": "long" - } - ] - ], "opaque-ad-sizes-exact-size.https.html": [ "b23d3ab0d7165d3b6aefccdfa7ba53971262717e", [ @@ -644307,7 +646051,7 @@ ] ], "text.https.html": [ - "901e9eef8373a00942fbfafa86032be7406d5655", + "ba49e2b851f13d39f8810c53b762cb971a2b3ef2", [ null, {} @@ -661321,6 +663065,16 @@ {} ] ], + "keyboard-lock-cross-origin-iframe.tentative.sub.html": [ + "0e638bc7172a63fe5df352a8a4a626194df21011", + [ + null, + { + "testdriver": true, + "timeout": "long" + } + ] + ], "navigate-iframe.sub.html": [ "9aa0e6908d1c2e31cf8fc2590e94e377e5c37fc1", [ @@ -665978,14 +667732,14 @@ ] ], "window-open-popup-during-load.html": [ - "5308c01c39969ebee64a53d88b2e1b60b2da02e5", + "5d44de89461ef187a61121683e76febe41e63dc7", [ null, {} ] ], "window-open-popup-during-pageshow.html": [ - "065d9332258eb8f46cbb5f1b9c5259159a50631d", + "dc9f883b96d67663d813efea5eb16da7806a4563", [ null, {} @@ -676144,6 +677898,34 @@ ] }, "filters": { + "svg_diffuse_filter_visited_color_taints.html": [ + "338f8968c97da220a725856ebef4e4b1315e7266", + [ + null, + {} + ] + ], + "svg_drop_shadow_filter_visited_color_taints.html": [ + "608e63e0ab8aaec6049f1d5146ba45e6ca718437", + [ + null, + {} + ] + ], + "svg_flood_filter_visited_color_taints.html": [ + "7c0a6a39c5b8352abc0660be7d81cfd51a6d7442", + [ + null, + {} + ] + ], + "svg_specular_filter_visited_color_taints.html": [ + "83d11ce55a6e5f7a372392fc489d2768f7f82312", + [ + null, + {} + ] + ], "tentative": { "idl-conversions": { "canvas-filter-sequence-conversion.html": [ @@ -696735,7 +698517,7 @@ ] ], "reporting-subresource-corp.https.html": [ - "e56124a4a085d962874714b3c23b091378d9ff6b", + "da73f83acaa2a592c7e72ecf5401f9e6a85f28c3", [ null, { @@ -699547,7 +701329,7 @@ ] ], "reporting-subresource-corp.tentative.https.html": [ - "013eb34d1065ee7bbe274af2b5409d47a37be0bf", + "5ced0aa7e090c626f644813d934a2e4b0ffa72d8", [ null, { @@ -702843,7 +704625,7 @@ }, "platform": { "mousedown-drag-select-input-display-change.html": [ - "fe411b65c01226d784609482e1fd431b131024db", + "eba3e9d570bee7512e4673f473d2528fd6d49974", [ null, { @@ -709876,7 +711658,7 @@ }, "user-interface": { "muted.html": [ - "eb6d2ac688d392feb91cf07ec5b136e8a0c656b9", + "0bdc425750bc8907d4ec5ba341ea5dc16d7b3e58", [ null, {} @@ -712670,6 +714452,13 @@ {} ] ], + "sizes-auto-resize-observer-removes-auto.html": [ + "522b18ec965abeb6b2cfe36c8b5bd5948764430c", + [ + null, + {} + ] + ], "sizes-auto.html": [ "64493ee389ac305a0bcee1f78f583a90211baf2e", [ @@ -713425,7 +715214,7 @@ ] ], "form_attribute.html": [ - "dde3250dbf7c10a767e91c28c3b42078533e8748", + "4508a667ee2b15134307c88e8fc2e81f8d02719f", [ null, {} @@ -715559,7 +717348,7 @@ ] ], "option-disabled-optgroup.html": [ - "85bcd631f1f4a23a8067043f20060760397be1a3", + "2320f9f09691b9380720d15bff4b0d83eb300489", [ null, {} @@ -715713,6 +717502,13 @@ } ] ], + "select-input-parsing.tentative.html": [ + "cf6e94fff62f5e31628a32694c7fc8de356706d7", + [ + null, + {} + ] + ], "select-inside-top-layer.html": [ "6d70f3aaf8d3dc23b2f5fb784c399991913dc938", [ @@ -715814,7 +717610,7 @@ ] ], "select-parsing.html": [ - "5878b39f749a7ae7862a40d0f21c36ae5d1889ef", + "252ef6bd578471c52fff372d7e8d5d6ca11176e6", [ null, {} @@ -716011,7 +717807,7 @@ }, "customizable-select-listbox": { "customizable-select-listbox-keyboard-behavior.optional.html": [ - "6915682c6ddc86229c6fe9e2192eb78d960bfe03", + "934ca464c2b045659f6acf6a5b74d44a48f1e026", [ null, { @@ -717984,6 +719780,15 @@ } ] ], + "menu-elements-pageup-pagedown.optional.html": [ + "dbe21aba91e5f130bfc3684c99a6ec034c9e6a92", + [ + null, + { + "testdriver": true + } + ] + ], "menu-elements-typeahead.html": [ "44eea7c1271e1a1779d4c9a1416441d15edbc2b9", [ @@ -722835,7 +724640,7 @@ ] ], "script-crossorigin-network.sub.html": [ - "5886ab6f32c85af027872947d3b4682228e75dc1", + "70a0585884f0e32f085a144ee665bb5f38d0347a", [ null, {} @@ -723103,7 +724908,7 @@ ] ], "ignore-content-type.any.js": [ - "2b71b534f29cd361fc7112a465d726f00dc0ed70", + "e2f5cf17acebb93b92f78d57d8e8b5f851955473", [ "html/semantics/scripting-1/the-script-element/text-module/ignore-content-type.any.html", { @@ -723139,7 +724944,7 @@ ] ], "ignore-extension.any.js": [ - "a1d6cd31f1c8749ae6410d313cd4a89fdad84878", + "350b489a06fa3d35db6049dc6c337389b9eea006", [ "html/semantics/scripting-1/the-script-element/text-module/ignore-extension.any.html", { @@ -723175,7 +724980,7 @@ ] ], "integrity.html": [ - "bda5d6958b85b793bc4516510fc60fad5884da35", + "1c1060c0089076978982cdf727c9d11463a86bc8", [ null, {} @@ -723203,7 +725008,7 @@ ] ], "repeated-imports.any.js": [ - "2ebc346dd4c95ec2282aefa9f9dfc47014ce88bb", + "547023157da4721f1d3b0eb9c733773f9d537b55", [ "html/semantics/scripting-1/the-script-element/text-module/repeated-imports.any.html", { @@ -723532,7 +725337,7 @@ ] ], "disabled.html": [ - "142a12dd122b555dcc6eee18334f796dc9269961", + "1716e7ab01f66aedc11cb347b0cc05ad51638d27", [ null, {} @@ -738009,7 +739814,7 @@ ] ], "href-click-004.tentative.html": [ - "764222dd1f94ec8da2aa734653e6b1a3e87cb081", + "accadb8063f60a516fe6edac9b42d78e0209b641", [ null, { @@ -745200,14 +747005,18 @@ }, "focus-reset": { "autofocus.html": [ - "c40e2f68f11ee1d3147bcfaf1e2dd74e93f399a5", + "b013dcd5ad400fe42dfa3e2763b2acddce1ef4dd", [ - null, + "navigation-api/focus-reset/autofocus.html?delayed-checkpoint", + {} + ], + [ + "navigation-api/focus-reset/autofocus.html?same-checkpoint", {} ] ], "basic.html": [ - "f5a30972b0e5452deaf1efebe4ba580379493a8b", + "9c5413fc176fe113223b4e0c0674ea17035a69e0", [ null, { @@ -745251,7 +747060,7 @@ ] ], "multiple-intercept.html": [ - "75e38c98a40f1bdf6ad1d08e1bbd470ea92d64c1", + "103023e6911b253ae0f043ae86d5d17af49bd83d", [ null, { @@ -747349,7 +749158,7 @@ ] ], "anchor-download-intercept-reject.html": [ - "5af651eb890ff69c3974a4008e50580891209da4", + "a19fa91e920906e6f3126f19c980fd04d4a1a894", [ "navigation-api/ordering-and-transition/anchor-download-intercept-reject.html?currententrychange", {} @@ -747360,7 +749169,7 @@ ] ], "anchor-download-intercept.html": [ - "38478e3c9a843983da70a90a573a108c64eaa880", + "72dce7cc37905539edd88e9fa90a9b03c7ecab27", [ "navigation-api/ordering-and-transition/anchor-download-intercept.html?currententrychange", {} @@ -747472,7 +749281,7 @@ ] ], "location-href-intercept-reject.html": [ - "81e8f2e00804fcc333065b3b9376d79969ce1f5a", + "831af58f3104463f3d6ebfa086400c14fdde9287", [ "navigation-api/ordering-and-transition/location-href-intercept-reject.html?currententrychange", {} @@ -747483,7 +749292,7 @@ ] ], "location-href-intercept.html": [ - "75f1d3d1d0286b96e97793e7eb03534ae95f5ff0", + "7787a54f2b6cb849ad57b2100b91b0fd6d463193", [ "navigation-api/ordering-and-transition/location-href-intercept.html?currententrychange", {} @@ -747533,7 +749342,7 @@ ] ], "navigate-in-transition-finished.html": [ - "8b3811dd36fd5586930492e5d1d514d61453fc66", + "9cde1cb9d302f038765cbcb752763d8bcf291dae", [ "navigation-api/ordering-and-transition/navigate-in-transition-finished.html?currententrychange", {} @@ -747588,7 +749397,7 @@ ] ], "navigate-intercept.html": [ - "eec9d3ca119b82406cdd93ad4de6af93f0ef1cf2", + "5315ecfbc1c53d81c225420818c5f1e2b31d2d3b", [ "navigation-api/ordering-and-transition/navigate-intercept.html?currententrychange", {} @@ -747610,7 +749419,7 @@ ] ], "navigate-same-document-intercept-reject.html": [ - "1e851cf75b108ddfcd2bab2a0d885f52bb98561c", + "64f9612f8a99730c162b8a5c99b5389ad4b1d215", [ "navigation-api/ordering-and-transition/navigate-same-document-intercept-reject.html?currententrychange", {} @@ -747621,7 +749430,7 @@ ] ], "navigate-same-document.html": [ - "fc506cef8bf481bee89b8cfd4f78843b95459305", + "d96393f1310eac3b83cccefc8f0e52b956ac36c7", [ "navigation-api/ordering-and-transition/navigate-same-document.html?currententrychange", {} @@ -747639,7 +749448,7 @@ ] ], "reload-intercept-reject.html": [ - "9c8894bff488ae67aa73be4510d0a6f5555a59c6", + "8183383c313d57ee7b4f9ac8e3a9b5f1c52a036b", [ "navigation-api/ordering-and-transition/reload-intercept-reject.html?currententrychange", {} @@ -747650,7 +749459,7 @@ ] ], "reload-intercept.html": [ - "1494136e199c508564a7449586c2f5579d9be69c", + "da1ae207882e9712bf243df673acee97ada1e6aa", [ "navigation-api/ordering-and-transition/reload-intercept.html?currententrychange", {} @@ -747661,7 +749470,7 @@ ] ], "reload-no-popstate.html": [ - "6c4592b67cc1417e1aa69491c41bb69cc8caba6e", + "5f67b256895006219bc47ff0184d1cac2acacf19", [ null, {} @@ -747896,7 +749705,7 @@ ] ], "precommitHandler-window-stop-before-commit.html": [ - "857a21ed3a97dd695d553818b5d067fec6666534", + "c1a11fa91fc1c076fb08f4004bcb681888435bf4", [ null, {} @@ -756274,7 +758083,7 @@ ] ], "preload-type-match.html": [ - "f429670b539c57ac297c9174a1f39e8c3df145f8", + "746c179cf7af7900f50c099986ad9cc25a81b60e", [ null, { @@ -774849,7 +776658,7 @@ ] ], "scroll-timeline-shorthand.html": [ - "722a8a1f4d7b7170e0b719b75b370ce4fe201886", + "0803d8a84f6cf058bdbd3190ddea7a34f4d7f8f1", [ null, {} @@ -775045,7 +776854,7 @@ ] ], "view-timeline-shorthand.html": [ - "9027eb0b09dc7dd348d2d3a0df94720b0de76150", + "b6b2dde3b08ff667027da7c9f51ec88bc65042da", [ null, {} @@ -781051,6 +782860,27 @@ {} ] ], + "shadowrootadoptedstylesheets-idl-absent-and-empty.html": [ + "659b6bd65ff1e4e04775928ad7b1438211e8cca7", + [ + null, + {} + ] + ], + "shadowrootadoptedstylesheets-idl-feature-detection.html": [ + "e9a23ae904dbc805ac75b746512cda635e256092", + [ + null, + {} + ] + ], + "shadowrootadoptedstylesheets-idl-reflection.html": [ + "41a2fecbeaa9b50f2c93849cde914e5d2551633e", + [ + null, + {} + ] + ], "shadowrootadoptedstylesheets-invalid-specifier.html": [ "34c7f876184e69555a7acc62e5af9bf9152b126d", [ @@ -781142,6 +782972,13 @@ {} ] ], + "shadowrootadoptedstylesheets-serialization.html": [ + "e36882d8a33685fa0dce2a8559c738f56e549bc2", + [ + null, + {} + ] + ], "shadowrootadoptedstylesheets-with-declarative-module.html": [ "737937e4b5c064775fff6616d8ca9fc30d3c1b38", [ @@ -782165,7 +784002,7 @@ ] ], "event-path.html": [ - "089d128252a46df1ad4f46088434a506e1ef957d", + "9fe2ace20f8e31fb7d2cd4ee72e17d6ed44ca3c6", [ null, {} @@ -795791,7 +797628,7 @@ ] ], "from.any.js": [ - "2b28a05fee398c523d049c56aff190e771eb19f2", + "77f2bbf0342a10b5f2581bca6502be5111e37a5e", [ "streams/readable-streams/from.any.html", { @@ -806896,7 +808733,7 @@ ] ], "SVGGraphicsElement.getBBox-05.html": [ - "8c0d11ed1c1cfd01484774328c773538e7bc5bf7", + "af25641d68455b145673cf6253a1ccc0aa4d65c4", [ null, {} @@ -809055,6 +810892,13 @@ {} ] ], + "trusted-types-secondary-document.html": [ + "01dd93d0d7a8653d690d4e62e763ffc3acff2b85", + [ + null, + {} + ] + ], "trusted-types-source-file-path.html": [ "105a04247f630ddb49a2813cfa2345226eac91aa", [ @@ -826924,7 +828768,7 @@ ] ], "effect-value-iteration-composite-operation.html": [ - "4679fb4d1b03cd3907fd9365b8d3f08d7d2ceb37", + "6408e0180aa71f81a5b6225594f2bc2a93fd23ce", [ null, {} @@ -830506,6 +832350,13 @@ {} ] ], + "audiobuffersource-duration-loop-playbackrate.html": [ + "0cf8e7d976e91bfb448fd8b32d09f77aa0fd1c9e", + [ + null, + {} + ] + ], "audiobuffersource-duration-loop.html": [ "fc2b55bce8a3e50b728a9606f0bfd3842199bd9c", [ @@ -830548,6 +832399,13 @@ {} ] ], + "audiobuffersource-playbackrate-negative.html": [ + "f6083299c5c8fde6d97d91a17aec62144b023346", + [ + null, + {} + ] + ], "audiobuffersource-playbackrate-zero.html": [ "c8bcbb61dd00ca95b898d98e02efa49ddbe215d9", [ @@ -831920,7 +833778,7 @@ ] ], "mediaElementAudioSourceToScriptProcessorTest.html": [ - "1099ee8d244a9d8a2d0d3e60531d5ae9f516ca57", + "39d238ec2c0b9b90a574b4f8b6f9ffa646f3ec50", [ null, {} @@ -839286,6 +841144,47 @@ } ] ], + "videoDecoder-444-h264.https.any.js": [ + "e6ebb3148e4505a1bf113f1bbf24f6b1406be83c", + [ + "webcodecs/videoDecoder-444-h264.https.any.html?h264_444_avc", + { + "script_metadata": [ + [ + "global", + "window,dedicatedworker" + ], + [ + "script", + "videoDecoder-codec-specific-setup.js" + ], + [ + "variant", + "?h264_444_avc" + ] + ] + } + ], + [ + "webcodecs/videoDecoder-444-h264.https.any.worker.html?h264_444_avc", + { + "script_metadata": [ + [ + "global", + "window,dedicatedworker" + ], + [ + "script", + "videoDecoder-codec-specific-setup.js" + ], + [ + "variant", + "?h264_444_avc" + ] + ] + } + ] + ], "videoDecoder-codec-specific-orientation.https.any.js": [ "9fb1714a7b1126ccec08de98effec7dfa95673c9", [ @@ -842296,6 +844195,22 @@ ] }, "webmcp": { + "declarative": { + "toolchange-on-control-add-remove.https.html": [ + "e365c71f3cc125bbb98f708fb981a898039ac549", + [ + null, + {} + ] + ], + "toolchange-on-name-change.https.html": [ + "3ec9fc16023f56b6663c5765066a09119c122922", + [ + null, + {} + ] + ] + }, "idlharness.https.window.js": [ "1f65593c09379e0451124fe0ff5b3628fe02df4b", [ @@ -842315,8 +844230,15 @@ ] ], "imperative": { + "detached-frame-getTools.https.html": [ + "fa696f2dab5d78b6a64f6451a462045eede33988", + [ + null, + {} + ] + ], "detached-frame-registerTool.https.html": [ - "0b2d4005c1754654a4a79e966b22da349ffa0ca5", + "df82a7c8610ec88f68cee87d2561c331f0adb275", [ null, {} @@ -842329,6 +844251,56 @@ {} ] ], + "exposedTo-cross-origin-child.https.html": [ + "78e5f3c8521c052e3d4e48c3fc6c13ea6a5a3e14", + [ + null, + { + "timeout": "long" + } + ] + ], + "exposedTo-defaults-cross-origin.https.html": [ + "0b8d015a9feff009eb6e28bb5d109cecad4189d9", + [ + null, + { + "timeout": "long" + } + ] + ], + "exposedTo-defaults-same-origin.https.html": [ + "adcef47480e51a5466ceb7774eab211e74d478d7", + [ + null, + {} + ] + ], + "exposedTo-invalid-origins.https.html": [ + "0cc38d37163b8da42cb4861cfac29336844ad754", + [ + null, + {} + ] + ], + "exposedTo-multiple-children.https.html": [ + "efb0b7b4cc5195333b6628a10277d992aa61cca3", + [ + null, + { + "timeout": "long" + } + ] + ], + "exposedTo-window-open.https.html": [ + "9fabde9f59ec4949aa0f1e838a918c71144d277d", + [ + null, + { + "timeout": "long" + } + ] + ], "model_context.https.window.js": [ "42165d55a1218274b8f7f2184e5260bae0a52682", [ @@ -842343,6 +844315,13 @@ {} ] ], + "permissions-policy.https.html": [ + "24f25e0bdee57444ad1909f68d36d72a0cff6261", + [ + null, + {} + ] + ], "register_tool_invalid_json_schema.https.window.js": [ "b67ce9bc3d8a48526a4bc2620b23992db7ffe6af", [ @@ -842350,6 +844329,13 @@ {} ] ], + "register_tool_name_validation.https.window.js": [ + "d1405a4c1ff033649407f30bd70ff54b438e60f1", + [ + "webmcp/imperative/register_tool_name_validation.https.window.html", + {} + ] + ], "register_tool_no_schema.https.window.js": [ "440caa47de75e321a80cb70605276d630ff63842", [ @@ -856428,7 +858414,7 @@ ] ], "slice.https.any.js": [ - "e448da4b580cdb482feb88d020439f15fc248626", + "c3784bd41770198d90eb06263c20d96e574c2d16", [ "webnn/conformance_tests/slice.https.any.html?cpu", { @@ -874404,7 +876390,7 @@ ] ], "slice.https.any.js": [ - "833628a96bcb201a413937564c8b51c64499099d", + "1e15b41782d3d5da0012cee7cf9b65f14ff62d78", [ "webnn/validation_tests/slice.https.any.html?cpu", { @@ -876587,7 +878573,7 @@ ] ], "RTCPeerConnection-remote-track-mute.https.html": [ - "f625623e00d70d587ad3eb3bd73fb8163723a214", + "e1becf0008e363e56dc466499cc72aca79b1ba48", [ null, { @@ -897758,13 +899744,6 @@ {} ] ], - "sharedworker-in-worker.html": [ - "25d2582366eb1b739edc2fb540f41a8b0c125486", - [ - null, - {} - ] - ], "worker-in-worker.html": [ "284425ed3407735c8072753d1299ff2c38da1a47", [ @@ -898012,7 +899991,7 @@ ] ], "expected-self-properties.worker.js": [ - "0ce41b59e7496dfda26053cdfac6bd090b40a3b6", + "72edf495eb67e3cf832cbed01f43d9d61895a78d", [ "workers/constructors/Worker/expected-self-properties.worker.html", {} @@ -898035,7 +900014,7 @@ ] ], "unexpected-self-properties.worker.js": [ - "69d29b2297847124206b392fea67949106a8a3fe", + "acdd0eb303b4fc78f8061edf654e6c2a3a942daa", [ "workers/constructors/Worker/unexpected-self-properties.worker.html", {} @@ -900245,6 +902224,20 @@ } ] ], + "abort-during-navigation.window.js": [ + "79bab924dadb6db83e6f9121db03153c257ce618", + [ + "xhr/abort-during-navigation.window.html", + { + "script_metadata": [ + [ + "title", + "XMLHttpRequest: navigation should not fire abort event" + ] + ] + } + ] + ], "abort-during-open.any.js": [ "42a1bce0ef2cbc4578d15fde846010af2092cbdf", [ @@ -919145,7 +921138,7 @@ ] ], "cookies.py": [ - "d403f279d51f9746c7b6091c601edbc5664dbeaf", + "7dfafdf3449fbe01f4a24e53eb2a46e903ab94c6", [ null, {}
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/supports-modern.tentative.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/supports-modern.tentative.https.any.js index 2cd17ce..709ffcd4 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/supports-modern.tentative.https.any.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/supports-modern.tentative.https.any.js
@@ -17,7 +17,7 @@ 'ML-KEM-512': { operations: [ 'generateKey', 'importKey', 'encapsulateKey', 'encapsulateBits', - 'decapuslateKey', 'decapsulateBits' + 'decapsulateKey', 'decapsulateBits' ], }, 'ML-KEM-768': { @@ -72,7 +72,7 @@ // Use appropriate algorithm parameters for each operation let algorithm; - let length; + let lengthOrAdditionalAlgorithm; switch (operation) { case 'generateKey': algorithm = algorithmInfo.keyGenParams || algorithmName; @@ -94,7 +94,7 @@ algorithm.public = (await algorithm.public).publicKey; } if (algorithmName === 'PBKDF2' || algorithmName === 'HKDF') { - length = 256; + lengthOrAdditionalAlgorithm = 256; } break; case 'digest': @@ -105,12 +105,15 @@ case 'decapsulateKey': case 'decapsulateBits': algorithm = algorithmName; + if (operation === 'encapsulateKey' || operation === 'decapsulateKey') { + lengthOrAdditionalAlgorithm = { name: 'AES-GCM', length: 256 }; + } break; default: algorithm = algorithmName; } - const result = SubtleCrypto.supports(operation, algorithm, length); + const result = SubtleCrypto.supports(operation, algorithm, lengthOrAdditionalAlgorithm); if (isSupported) { assert_true(result, `${algorithmName} should support ${operation}`);
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/inheritance/auxiliary-blank-document.html b/third_party/blink/web_tests/external/wpt/content-security-policy/inheritance/auxiliary-blank-document.html new file mode 100644 index 0000000..d7de318c --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/content-security-policy/inheritance/auxiliary-blank-document.html
@@ -0,0 +1,78 @@ +<!DOCTYPE html> +<head> + <meta http-equiv="Content-Security-Policy" content="img-src 'self'"> +<script src=/common/get-host-info.sub.js></script> + + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <title>CSP inheritance to an auxiliary about:blank</title> +</head> +<body> + <script> + function waitForEvent(target, name) { + return new Promise(resolve => { + function listener(e) { + target.removeEventListener(name, listener); + resolve(e); + } + target.addEventListener(name, listener); + }); + } + + async function testImgBlocked(doc, url) { + const img = doc.createElement("img"); + img.src = url; + + const pViolation = waitForEvent(doc, "securitypolicyviolation"); + const pLoad = waitForEvent(img, "load"); + + // Still return violation event if it occurs on the wrong window + // See subtest for the target. + const pAbort = waitForEvent(window, "securitypolicyviolation") + + doc.body.append(img); + return Promise.race([pViolation, pLoad, pAbort]); + } + + const xorigin = get_host_info().REMOTE_ORIGIN; + + promise_test(async t => { + const win = window.open("about:blank"); + t.add_cleanup(() => win.close()); + win.onload = () => assert_unreached("Should load synchronously"); + assert_equals(win.document.readyState, "complete"); + + const eSelf = await testImgBlocked(win.document, "/content-security-policy/support/pass.png"); + assert_equals(eSelf.type, "load"); + + const eXorig = await testImgBlocked(win.document, xorigin + "/content-security-policy/support/fail.png"); + assert_equals(eXorig.type, "securitypolicyviolation"); + }, "window.open() inherits CSPs on initial about:blank."); + + promise_test(async t => { + const win = window.open("/common/blank.html"); + t.add_cleanup(() => win.close()); + win.stop(); + assert_equals(win.document.documentURI, "about:blank"); + + const eXorig = await testImgBlocked(win.document, xorigin + "/content-security-policy/support/fail.png"); + assert_equals(eXorig.type, "securitypolicyviolation"); + assert_equals(eXorig.target, win.document); + }, "For transient doc, violation event occurs in auxiliary, not opener window."); + + promise_test(async t => { + const win = window.open("/common/blank.html"); + t.add_cleanup(() => win.close()); + win.stop(); + assert_equals(win.document.documentURI, "about:blank"); + + const eSelf = await testImgBlocked(win.document, "/content-security-policy/support/pass.png"); + assert_equals(eSelf.type, "load"); + + const eXorig = await testImgBlocked(win.document, xorigin + "/content-security-policy/support/fail.png"); + assert_equals(eXorig.type, "securitypolicyviolation"); + }, "window.open() inherits CSPs on transient about:blank."); + + </script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/inheritance/document-write-iframe.html b/third_party/blink/web_tests/external/wpt/content-security-policy/inheritance/document-write-iframe.html index 73614e3..07f0e293 100644 --- a/third_party/blink/web_tests/external/wpt/content-security-policy/inheritance/document-write-iframe.html +++ b/third_party/blink/web_tests/external/wpt/content-security-policy/inheritance/document-write-iframe.html
@@ -8,14 +8,22 @@ <body> <script> let message_from = (w) => { - return new Promise(resolve => { - let listener = msg => { + return new Promise((resolve, reject) => { + let onMsg = msg => { if (msg.source != w) return; - window.removeEventListener('message', listener); + window.removeEventListener('message', onMsg); + window.removeEventListener('securitypolicyviolation', abort) resolve(msg.data); }; - window.addEventListener('message', listener); + // Avoid timeout if violation events occur on the wrong window + let abort = evt => { + window.removeEventListener('message', onMsg); + window.removeEventListener('securitypolicyviolation', abort) + reject("unexpected violation in top window"); + } + window.addEventListener('message', onMsg); + window.addEventListener('securitypolicyviolation', abort) }); };
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/inheritance/history-iframe.sub.html b/third_party/blink/web_tests/external/wpt/content-security-policy/inheritance/history-iframe.sub.html index 1f696053..49e6a5f 100644 --- a/third_party/blink/web_tests/external/wpt/content-security-policy/inheritance/history-iframe.sub.html +++ b/third_party/blink/web_tests/external/wpt/content-security-policy/inheritance/history-iframe.sub.html
@@ -52,7 +52,8 @@ await t.step_wait( condition = () => { try { - return iframe.contentWindow.location.href == "about:blank"; + return iframe.contentWindow.location.href == "about:blank" && + iframe.contentDocument.readyState == "complete"; } catch {} return false; },
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/inheritance/history.sub.html b/third_party/blink/web_tests/external/wpt/content-security-policy/inheritance/history.sub.html index 5ea6abe..a0fda8c 100644 --- a/third_party/blink/web_tests/external/wpt/content-security-policy/inheritance/history.sub.html +++ b/third_party/blink/web_tests/external/wpt/content-security-policy/inheritance/history.sub.html
@@ -148,20 +148,21 @@ // Navigate to the local scheme document. We need to wait for the // navigation to succeed. - let wait = () => t.step_wait( + let wait = (msg) => t.step_wait( condition = () => { try { - return popup.location.href == testCase.url; + return popup.location.href == testCase.url && + popup.document.readyState == "complete"; } catch {} return false; }, - description = "Wait for the popup to navigate.", + description = "Wait for the popup to navigate: " + msg, timeout=3000, interval=50); let message = message_from(testCase.token); popup.location = testCase.url; - await wait(); + await wait("to test url"); if (testCase.add_img_function) { testCase.add_img_function(popup); } @@ -169,6 +170,7 @@ // Check that the local scheme document inherits CSP from the initiator. assert_equals(await message, "img blocked", "Image should be blocked by CSP inherited from navigation initiator."); + assert_equals(popup.history.length, 2, "History entry for test url added"); const token_2 = token(); let loaded_2 = message_from(token_2, "ready"); @@ -181,7 +183,10 @@ "Could not navigate popup."); // We need to wait for the history navigation to be performed. - await wait(); + await Promise.race([ + message_from(token_1).then(() => assert_unreached("Navigated back too far")), + wait("history.back() to test url") + ]) // Check that the "about:blank" document reloaded from history has the // original CSPs.
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/inheritance/support/postmessage-opener.html b/third_party/blink/web_tests/external/wpt/content-security-policy/inheritance/support/postmessage-opener.html index 7ee11bc..945adbd 100644 --- a/third_party/blink/web_tests/external/wpt/content-security-policy/inheritance/support/postmessage-opener.html +++ b/third_party/blink/web_tests/external/wpt/content-security-policy/inheritance/support/postmessage-opener.html
@@ -1,4 +1,6 @@ <script> +window.onload = () => { const params = new URLSearchParams(window.location.search); opener.postMessage({msg: "ready", token: params.get("token")}, "*"); +} </script>
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/inheritance/support/postmessage-top.html b/third_party/blink/web_tests/external/wpt/content-security-policy/inheritance/support/postmessage-top.html index 242063a..79ca9741 100644 --- a/third_party/blink/web_tests/external/wpt/content-security-policy/inheritance/support/postmessage-top.html +++ b/third_party/blink/web_tests/external/wpt/content-security-policy/inheritance/support/postmessage-top.html
@@ -1,5 +1,7 @@ <!DOCTYPE html> <script> +window.onload = () => { const params = new URLSearchParams(window.location.search); top.postMessage({msg: "ready", token: params.get("token")}, "*"); +} </script>
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/media-src/media-src-blocked-blob-url.html b/third_party/blink/web_tests/external/wpt/content-security-policy/media-src/media-src-blocked-blob-url.html new file mode 100644 index 0000000..6c42acf --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/content-security-policy/media-src/media-src-blocked-blob-url.html
@@ -0,0 +1,69 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Video element with blob: URL must be blocked when blob: is not in media-src</title> + <meta http-equiv="Content-Security-Policy" content="script-src * 'unsafe-inline'; media-src https://example.com; connect-src 'self';"> + <script src='/resources/testharness.js'></script> + <script src='/resources/testharnessreport.js'></script> +</head> +<body> + <h1>Video element with blob: URL must be blocked when blob: is not in media-src</h1> + <div id='log'></div> + + <script> + async function nextViolation() { + return await new Promise((resolve) => { + window.addEventListener("securitypolicyviolation", resolve, { + once: true, + }); + }); + } + + promise_test(t => { + return fetch("/media/A4.mp4") + .then(response => response.blob()) + .then(blob => { + const blobUrl = URL.createObjectURL(blob); + t.add_cleanup(() => URL.revokeObjectURL(blobUrl)); + + return new Promise((resolve, reject) => { + const violationPromise = nextViolation(); + + const video = document.createElement("video"); + video.src = blobUrl; + video.onloadeddata = reject; + video.onerror = () => { resolve(violationPromise); }; + + document.body.appendChild(video); + }).then((violation) => { + assert_equals(violation.violatedDirective, "media-src", "directive"); + assert_equals(violation.blockedURI, "blob", "blocked URI"); + }); + }); + }, "Video with blob: URL blocked when blob: not in media-src"); + + promise_test(t => { + return fetch("/media/sound_5.oga") + .then(response => response.blob()) + .then(blob => { + const blobUrl = URL.createObjectURL(blob); + t.add_cleanup(() => URL.revokeObjectURL(blobUrl)); + + return new Promise((resolve, reject) => { + const violationPromise = nextViolation(); + + const audio = document.createElement("audio"); + audio.src = blobUrl; + audio.onloadeddata = reject; + audio.onerror = () => { resolve(violationPromise); }; + + document.body.appendChild(audio); + }).then((violation) => { + assert_equals(violation.violatedDirective, "media-src", "directive"); + assert_equals(violation.blockedURI, "blob", "blocked URI"); + }); + }); + }, "Audio with blob: URL blocked when blob: not in media-src"); + </script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/media-src/media-src-blocked-data-url.html b/third_party/blink/web_tests/external/wpt/content-security-policy/media-src/media-src-blocked-data-url.html new file mode 100644 index 0000000..b419479 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/content-security-policy/media-src/media-src-blocked-data-url.html
@@ -0,0 +1,54 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Video element with data: URL must be blocked by media-src 'self'</title> + <meta http-equiv="Content-Security-Policy" content="script-src * 'unsafe-inline'; media-src 'self';"> + <script src='/resources/testharness.js'></script> + <script src='/resources/testharnessreport.js'></script> +</head> +<body> + <h1>Video element with data: URL must be blocked by media-src 'self'</h1> + <div id='log'></div> + + <script> + // Minimal valid MP4 as a data: URL. + const dataVideoUrl = "data:video/mp4;base64,AAAAGGZ0eXBtcDQyAAAAAG1wNDJtcDQx"; + + async function nextViolation() { + return await new Promise((resolve) => { + window.addEventListener("securitypolicyviolation", resolve, { + once: true, + }); + }); + } + + promise_test(t => new Promise((resolve, reject) => { + const violationPromise = nextViolation(); + + const video = document.createElement("video"); + video.src = dataVideoUrl; + video.onloadeddata = reject; + video.onerror = () => { resolve(violationPromise); }; + + document.body.appendChild(video); + }).then((violation) => { + assert_equals(violation.violatedDirective, "media-src", "directive"); + assert_equals(violation.blockedURI, "data", "blocked URI"); + }), "Video with data: URL blocked by media-src 'self'"); + + promise_test(t => new Promise((resolve, reject) => { + const violationPromise = nextViolation(); + + const audio = document.createElement("audio"); + audio.src = dataVideoUrl; + audio.onloadeddata = reject; + audio.onerror = () => { resolve(violationPromise); }; + + document.body.appendChild(audio); + }).then((violation) => { + assert_equals(violation.violatedDirective, "media-src", "directive"); + assert_equals(violation.blockedURI, "data", "blocked URI"); + }), "Audio with data: URL blocked by media-src 'self'"); + </script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/script-src/tentative/script-url-blocked-report-contains-hash-dedicated-worker.https.html b/third_party/blink/web_tests/external/wpt/content-security-policy/script-src/tentative/script-url-blocked-report-contains-hash-dedicated-worker.https.html deleted file mode 100644 index 924adc0..0000000 --- a/third_party/blink/web_tests/external/wpt/content-security-policy/script-src/tentative/script-url-blocked-report-contains-hash-dedicated-worker.https.html +++ /dev/null
@@ -1,42 +0,0 @@ -<!DOCTYPE html> -<html> - -<head> - <title>script-url-blocked-and-sends-hash in dedicated worker</title> - <script src="/common/get-host-info.sub.js"></script> - <script src="/resources/testharness.js"></script> - <script src="/resources/testharnessreport.js"></script> - <script src="support/util.js"></script> -</head> - -<body> - <script> - const scriptUrl = new URL("./support/externalScript.js", document.location).toString(); - - promise_test(async t => { - const expectedHash = await sha256ofURL(scriptUrl); - - return new Promise((resolve, reject) => { - const w = new Worker("./support/worker-report-hash.js"); - w.onmessage = e => { - if (e.data.type === 'violation') { - try { - assert_equals(e.data.blockedURI, scriptUrl); - assert_equals(e.data.urlHash.replace(/=+$/, ''), `url-sha256-${expectedHash}`); - assert_equals(e.data.evalHash, ""); - resolve(); - } catch (err) { - reject(err); - } - } - }; - w.onerror = (e) => { - // An error will be triggered because the worker can't import externalScript.js. - e.preventDefault(); - }; - }); - }, "script-specific violation report contains correct urlHash in dedicated worker"); - </script> -</body> - -</html> \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/script-src/tentative/script-url-blocked-report-contains-hash-service-worker.https.html b/third_party/blink/web_tests/external/wpt/content-security-policy/script-src/tentative/script-url-blocked-report-contains-hash-service-worker.https.html deleted file mode 100644 index a6baad4b..0000000 --- a/third_party/blink/web_tests/external/wpt/content-security-policy/script-src/tentative/script-url-blocked-report-contains-hash-service-worker.https.html +++ /dev/null
@@ -1,50 +0,0 @@ -<!DOCTYPE html> -<html> - -<head> - <title>script-url-blocked-and-sends-hash in service worker</title> - <script src="/common/get-host-info.sub.js"></script> - <script src="/resources/testharness.js"></script> - <script src="/resources/testharnessreport.js"></script> - <script src="/service-workers/service-worker/resources/test-helpers.sub.js"></script> - <script src="support/util.js"></script> -</head> - -<body> - <script> - const scriptUrl = new URL("./support/externalScript.js", document.location).toString(); - - promise_test(async t => { - const expectedHash = await sha256ofURL(scriptUrl); - - const SCOPE = './support/does-not-exist.html'; - const SCRIPT = './support/worker-report-hash.js'; - - // Make sure we have a clean state. - await service_worker_unregister(t, SCOPE); - - return new Promise((resolve, reject) => { - navigator.serviceWorker.addEventListener('message', e => { - if (e.data.type === 'violation') { - try { - assert_equals(e.data.blockedURI, scriptUrl); - assert_equals(e.data.urlHash.replace(/=+$/, ''), `url-sha256-${expectedHash}`); - assert_equals(e.data.evalHash, ""); - - // Clean up - service_worker_unregister(t, SCOPE).then(resolve); - } catch (err) { - reject(err); - } - } - }); - - navigator.serviceWorker.register(SCRIPT, { scope: SCOPE }).catch(err => { - // An error will be triggered because the worker can't import externalScript.js. - }); - }); - }, "script-specific violation report contains correct urlHash in service worker"); - </script> -</body> - -</html> \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/script-src/tentative/script-url-blocked-report-contains-hash-shared-worker.https.html b/third_party/blink/web_tests/external/wpt/content-security-policy/script-src/tentative/script-url-blocked-report-contains-hash-shared-worker.https.html deleted file mode 100644 index cf71b7b..0000000 --- a/third_party/blink/web_tests/external/wpt/content-security-policy/script-src/tentative/script-url-blocked-report-contains-hash-shared-worker.https.html +++ /dev/null
@@ -1,35 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title>script-url-blocked-and-sends-hash in shared worker</title> - <script src="/common/get-host-info.sub.js"></script> - <script src="/resources/testharness.js"></script> - <script src="/resources/testharnessreport.js"></script> - <script src="support/util.js"></script> -</head> -<body> -<script> - const scriptUrl = new URL("./support/externalScript.js", document.location).toString(); - - promise_test(async t => { - const expectedHash = await sha256ofURL(scriptUrl); - - return new Promise((resolve, reject) => { - const w = new SharedWorker("./support/worker-report-hash.js"); - w.port.onmessage = e => { - if (e.data.type === 'violation') { - try { - assert_equals(e.data.blockedURI, scriptUrl); - assert_equals(e.data.urlHash.replace(/=+$/, ''), `url-sha256-${expectedHash}`); - assert_equals(e.data.evalHash, ""); - resolve(); - } catch (err) { - reject(err); - } - } - }; - }); - }, "script-specific violation report contains correct urlHash in shared worker"); -</script> -</body> -</html>
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/script-src/tentative/script-url-blocked-report-contains-hash.https.html b/third_party/blink/web_tests/external/wpt/content-security-policy/script-src/tentative/script-url-blocked-report-contains-hash.https.html deleted file mode 100644 index 67494583..0000000 --- a/third_party/blink/web_tests/external/wpt/content-security-policy/script-src/tentative/script-url-blocked-report-contains-hash.https.html +++ /dev/null
@@ -1,44 +0,0 @@ -<!DOCTYPE html> -<html> - -<head> - <title>script-url-blocked-and-sends-hash</title> - <script src="/common/get-host-info.sub.js"></script> - <script src="/resources/testharness.js"></script> - <script src="/resources/testharnessreport.js"></script> - <script src="support/util.js"></script> -</head> - -<body> - <script> - const { ORIGIN } = get_host_info(); - const scriptUrl = new URL("./support/externalScript.js", document.location).toString(); - const otherUrl = new URL("./support/add_dynamic_script.js", document.location).toString(); - - promise_test(async t => { - const expectedHash = await sha256ofURL(scriptUrl); - - return new Promise(resolve => { - document.addEventListener("securitypolicyviolation", function (e) { - if (e.blockedURI === scriptUrl) { - // sha256ofURL removes the '=' at the end of the hash, so we need to remove it from urlHash. - assert_equals(e.urlHash.replace(/=+$/, ''), `url-sha256-${expectedHash}`); - assert_equals(e.evalHash, ""); - resolve(); - } - }); - - const meta = document.createElement('meta'); - meta.httpEquiv = 'Content-Security-Policy'; - meta.content = "script-src 'unsafe-eval' 'unsafe-inline' 'nonce-abc' 'url-sha256-dummy'"; - document.head.appendChild(meta); - - const script = document.createElement('script'); - script.src = scriptUrl; - document.body.appendChild(script); - }); - }, "script-specific violation report contains correct urlHash"); - </script> -</body> - -</html> \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/script-src/tentative/support/worker-report-hash.js b/third_party/blink/web_tests/external/wpt/content-security-policy/script-src/tentative/support/worker-report-hash.js deleted file mode 100644 index 83cdb6e..0000000 --- a/third_party/blink/web_tests/external/wpt/content-security-policy/script-src/tentative/support/worker-report-hash.js +++ /dev/null
@@ -1,37 +0,0 @@ -self.addEventListener('securitypolicyviolation', e => { - let context = 'DedicatedWorker'; - if (typeof SharedWorkerGlobalScope !== 'undefined' && self instanceof SharedWorkerGlobalScope) { - context = 'SharedWorker'; - } else if (typeof ServiceWorkerGlobalScope !== 'undefined' && self instanceof ServiceWorkerGlobalScope) { - context = 'ServiceWorker'; - } - - const msg = { - type: 'violation', - blockedURI: e.blockedURI, - urlHash: e.urlHash, - evalHash: e.evalHash - }; - - if (context === 'DedicatedWorker') { - self.postMessage(msg); - } else if (context === 'SharedWorker') { - if (self.sharedPorts) { - self.sharedPorts.forEach(port => port.postMessage(msg)); - } - } else if (context === 'ServiceWorker') { - self.clients.matchAll({ includeUncontrolled: true }).then(clients => { - clients.forEach(client => client.postMessage(msg)); - }); - } -}); - -if (typeof SharedWorkerGlobalScope !== 'undefined' && self instanceof SharedWorkerGlobalScope) { - self.sharedPorts = []; - self.addEventListener('connect', e => { - self.sharedPorts.push(e.ports[0]); - importScripts('externalScript.js'); - }); -} else { - importScripts('externalScript.js'); -}
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/script-src/tentative/support/worker-report-hash.js.headers b/third_party/blink/web_tests/external/wpt/content-security-policy/script-src/tentative/support/worker-report-hash.js.headers deleted file mode 100644 index e0cbd93b..0000000 --- a/third_party/blink/web_tests/external/wpt/content-security-policy/script-src/tentative/support/worker-report-hash.js.headers +++ /dev/null
@@ -1 +0,0 @@ -Content-Security-Policy: script-src 'url-sha256-dummy'
diff --git a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-position-multicol-011.html b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-position-multicol-011.html index eab57bfd..ce0ec152 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-position-multicol-011.html +++ b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-position-multicol-011.html
@@ -7,11 +7,13 @@ <style> #mc { columns: 2; + column-fill: auto; gap: 0; display: list-item; list-style-position: outside; margin-left: 40px; width: 60px; + height: 100px; color: red; } #mc::marker { @@ -22,8 +24,8 @@ <p>Test passes if there is a filled green square and <strong>no red</strong>.</p> <div style="position:relative;"> <div id="mc"> - x - <div style="break-before:column; position:relative;"> + <div style="height: 100px"></div> + <div style="position:relative;"> <div style="anchor-name:--foo;">y</div> <div style="position:absolute; position-anchor:--foo; top:anchor(top); right:anchor(right); width:30px; height:100px; background:green;"></div> </div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-scroll-implicit-001.html b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-scroll-implicit-001.html index e0b6ded..a6652c4 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-scroll-implicit-001.html +++ b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-scroll-implicit-001.html
@@ -9,8 +9,7 @@ position: fixed; width: 100px; height: 50px; - left: anchor(left); - top: anchor(bottom); + position-area: center bottom; background: green; border: none; padding: 0;
diff --git a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-scroll-implicit-002.html b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-scroll-implicit-002.html index f70235b..040d09e 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-scroll-implicit-002.html +++ b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-scroll-implicit-002.html
@@ -9,8 +9,7 @@ position: absolute; width: 100px; height: 50px; - left: anchor(left); - top: anchor(bottom); + position-area: center bottom; background: green; border: none; padding: 0;
diff --git a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/position-anchor-basics-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/position-anchor-basics-expected.txt new file mode 100644 index 0000000..dc4d9576 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/position-anchor-basics-expected.txt
@@ -0,0 +1,6 @@ +This is a testharness.js-based test. +Found 1 FAIL, 0 TIMEOUT, 0 NOTRUN. +[FAIL] Property position-anchor has initial value normal in popovers + assert_equals: expected "normal" but got "none" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/position-anchor-basics.html b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/position-anchor-basics.html index a5179eb..4fd25d8 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/position-anchor-basics.html +++ b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/position-anchor-basics.html
@@ -11,6 +11,7 @@ <div id="container"> <div id="target"></div> + <div id="popover" popover></div> </div> <script> @@ -34,6 +35,15 @@ // Inherited: no assert_not_inherited('position-anchor', 'none', '--foo'); +// Previous resolution added `position-anchor: auto` to popovers in +// the UA stylesheet, but that is no longer required. See: +// https://github.com/w3c/csswg-drafts/issues/13067#issuecomment-3525018605 +// https://github.com/w3c/csswg-drafts/issues/13067#issuecomment-4239954367 +test(() => { + popover.style['position-anchor'] = 'initial'; + assert_equals(getComputedStyle(popover)['position-anchor'], 'normal'); +}, 'Property position-anchor has initial value normal in popovers'); + // Animation type: discrete test_no_interpolation({ property: 'position-anchor',
diff --git a/third_party/blink/web_tests/external/wpt/css/css-animations/crashtests/transform-properties-from-none-to-none-crash.html b/third_party/blink/web_tests/external/wpt/css/css-animations/crashtests/transform-properties-from-none-to-none-crash.html new file mode 100644 index 0000000..a2f4f7a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-animations/crashtests/transform-properties-from-none-to-none-crash.html
@@ -0,0 +1,39 @@ +<!DOCTYPE html> + +<html class="test-wait"> + +<title>Crash when animating transform-related properties from none to none</title> +<link rel="author" title="Kiet Ho" href="mailto:kiet.ho@apple.com"> + +<style> + @keyframes anim { + from { + rotate: none; + scale: none; + translate: none; + } + + to { + rotate: none; + scale: none; + translate: none; + } + } + + #element { + animation: 1s anim running; + } +</style> + +<div id="element"></div> + +<script> + // Let the animation play out for at least one frame. + requestAnimationFrame(() => { + requestAnimationFrame(() => { + document.documentElement.classList.remove("test-wait"); + }); + }); +</script> + +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-conditional/container-queries/at-container-style-parsing.html b/third_party/blink/web_tests/external/wpt/css/css-conditional/container-queries/at-container-style-parsing.html index 1bb5e1a7..36a4f70 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-conditional/container-queries/at-container-style-parsing.html +++ b/third_party/blink/web_tests/external/wpt/css/css-conditional/container-queries/at-container-style-parsing.html
@@ -44,6 +44,7 @@ test_cq_condition_known('style(var(--p) < calc(100 + 200))'); test_cq_condition_known('style(attr(data-foo type(<number>)) < var(--p) < var(--q))'); test_cq_condition_known('style(--foo < initial)'); + test_cq_condition_known('style(10px <= env(safe-area-inset-top) < 20px)'); test_cq_condition_unknown('style(--foo: bar;)'); test_cq_condition_unknown('style(style(--foo: bar))');
diff --git a/third_party/blink/web_tests/external/wpt/css/css-conditional/container-queries/query-evaluation-style.html b/third_party/blink/web_tests/external/wpt/css/css-conditional/container-queries/query-evaluation-style.html index a144f4e..01ebda5 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-conditional/container-queries/query-evaluation-style.html +++ b/third_party/blink/web_tests/external/wpt/css/css-conditional/container-queries/query-evaluation-style.html
@@ -45,7 +45,7 @@ --foo: bar; } </style> -<div id=container> +<div id=container xyzzy="5px"> <div id=inner data-foo="3px"></div> </div> <script> @@ -239,10 +239,28 @@ test_query_with_custom_properties('style(--x >= 3ms)', [['--x', '3px']], false); - test_query_with_custom_properties(`style(--length <= 30px)`, + test_query_with_custom_properties('style(--length <= 30px)', [['--length', 'attr(data-foo type(<length>))']], true); + // These should be true: the container has an attribute 'xyzzy="5px"', + // while 'plugh' is undefined so will use the default. + test_query('style(1px < attr(xyzzy type(<length>)) < 10px)', true); + test_query('style(1px < attr(plugh, 5px) < 10px)', true); + test_query('style(1px < attr(plugh type(<length>), 5px) < 10px)', true); + // This is false because the untyped attr() resolves to a string, not a length. + test_query('style(1px < attr(xyzzy) < 10px)', false); + test_query('style(1px < attr(plugh, "5px") < 10px)', false); + + // var() function with a default value. + test_query('style(var(--unknown-prop, 20px) > 10px)', true); + test_query_with_custom_properties('style(var(--prop, 5px) > 10px)', + [['--prop', '15px']], + true); + test_query_with_custom_properties('style(var(--length, 20px) < 10px)', + [['--length', 'attr(data-foo type(<length>))']], + true); + test_query('style(10px <= 10px < 11px)', true); test_query_with_custom_properties( 'style(3 < --x <= 5)', @@ -253,4 +271,7 @@ [['--x', '3'], ['--y', '3'], ['--z', '1']], true); + // test queries with env(), assuming "safe area" insets will never be negative. + test_query('style(0px <= env(safe-area-inset-top))', true); + test_query('style(0px > env(safe-area-inset-bottom))', false); </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-highlight-api/crashtests/highlight-image-multiple-crash.html b/third_party/blink/web_tests/external/wpt/css/css-highlight-api/crashtests/highlight-image-multiple-crash.html new file mode 100644 index 0000000..395804a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-highlight-api/crashtests/highlight-image-multiple-crash.html
@@ -0,0 +1,11 @@ +<!DOCTYPE html> +<style> +::highlight(h1) { background-color: rgba(255,0,0,.5); } +::highlight(h2) { background-color: rgba(0,0,255,.5); } +</style> +<div id="t"><img src="../../../images/blank-highlight.png"></div> +<script> +const range = new StaticRange({startContainer: t, startOffset: 0, endContainer: t, endOffset: 1}); +CSS.highlights.set("h1", new Highlight(range)); +CSS.highlights.set("h2", new Highlight(range)); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-highlight-api/highlight-image.html b/third_party/blink/web_tests/external/wpt/css/css-highlight-api/highlight-image.html index b5d44e06..e45b0db 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-highlight-api/highlight-image.html +++ b/third_party/blink/web_tests/external/wpt/css/css-highlight-api/highlight-image.html
@@ -18,7 +18,7 @@ <script> let imageElement1 = document.getElementById('img1'); - let highlight1 = new Highlight(new StaticRange({startContainer: imageElement1.childNodes[0], startOffset: 0, endContainer: imageElement1.childNodes[0], endOffset: 1})); + let highlight1 = new Highlight(new StaticRange({startContainer: imageElement1, startOffset: 0, endContainer: imageElement1, endOffset: 1})); CSS.highlights.set("example-highlight1", highlight1);
diff --git a/third_party/blink/web_tests/external/wpt/css/css-highlight-api/painting/custom-highlight-painting-insert-node-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-highlight-api/painting/custom-highlight-painting-insert-node-001-ref.html new file mode 100644 index 0000000..d538c550 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-highlight-api/painting/custom-highlight-painting-insert-node-001-ref.html
@@ -0,0 +1,3 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<pre>Hello <span style="color: red;">world</span></pre>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-highlight-api/painting/custom-highlight-painting-insert-node-001.html b/third_party/blink/web_tests/external/wpt/css/css-highlight-api/painting/custom-highlight-painting-insert-node-001.html new file mode 100644 index 0000000..f0a11c2 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-highlight-api/painting/custom-highlight-painting-insert-node-001.html
@@ -0,0 +1,26 @@ +<!DOCTYPE html> +<html class="reftest-wait"> +<meta charset="utf-8"> +<title>CSS Highlight API Test: highlight renders on text node inserted after highlight registration</title> +<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/"> +<link rel="match" href="custom-highlight-painting-insert-node-001-ref.html"> +<meta name="assert" content="Highlights on ranges of detached text nodes are painted after the text node is inserted into the document."> +<script src="/common/reftest-wait.js"></script> +<style> + ::highlight(example) { + color: red; + } +</style> +<body> +<pre></pre> +<script> + const pre = document.querySelector('pre'); + const text = document.createTextNode('Hello world'); + const range = new Range(); + range.setStart(text, 6); + range.setEnd(text, 11); + CSS.highlights.set('example', new Highlight(range)); + pre.append(text); + requestAnimationFrame(() => requestAnimationFrame(() => takeScreenshot())); +</script> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-highlight-api/painting/custom-highlight-painting-insert-node-002.html b/third_party/blink/web_tests/external/wpt/css/css-highlight-api/painting/custom-highlight-painting-insert-node-002.html new file mode 100644 index 0000000..f4a590d1 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-highlight-api/painting/custom-highlight-painting-insert-node-002.html
@@ -0,0 +1,26 @@ +<!DOCTYPE html> +<html class="reftest-wait"> +<meta charset="utf-8"> +<title>CSS Highlight API Test: highlight renders when subtree containing highlighted range is inserted</title> +<link rel="help" href="https://drafts.csswg.org/css-highlight-api-1/"> +<link rel="match" href="custom-highlight-painting-insert-node-001-ref.html"> +<meta name="assert" content="Highlights on ranges inside a detached subtree are painted after the subtree root is inserted into the document."> +<script src="/common/reftest-wait.js"></script> +<style> + ::highlight(example) { + color: red; + } +</style> +<body> +<script> + const pre = document.createElement('pre'); + const text = document.createTextNode('Hello world'); + pre.append(text); + const range = new Range(); + range.setStart(text, 6); + range.setEnd(text, 11); + CSS.highlights.set('example', new Highlight(range)); + document.body.append(pre); + requestAnimationFrame(() => requestAnimationFrame(() => takeScreenshot())); +</script> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-images/image-orientation/image-orientation-background-image.html b/third_party/blink/web_tests/external/wpt/css/css-images/image-orientation/image-orientation-background-image.html index 866e945..46aa1b009 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-images/image-orientation/image-orientation-background-image.html +++ b/third_party/blink/web_tests/external/wpt/css/css-images/image-orientation/image-orientation-background-image.html
@@ -4,7 +4,7 @@ <link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au"> <link rel="help" href="https://drafts.csswg.org/css-images-3/#propdef-image-orientation"> <link rel="match" href="reference/image-orientation-background-image-ref.html"> -<meta name=fuzzy content="0-3;0-50"> +<meta name=fuzzy content="0-3;0-60"> <style> div { width: 100px; height: 50px; background-image: url(support/exif-orientation-2-ur.jpg); } .no-orient { image-orientation: none; }
diff --git a/third_party/blink/web_tests/external/wpt/css/css-images/image-orientation/image-orientation-list-style-image.html b/third_party/blink/web_tests/external/wpt/css/css-images/image-orientation/image-orientation-list-style-image.html index ac735626d..059317e 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-images/image-orientation/image-orientation-list-style-image.html +++ b/third_party/blink/web_tests/external/wpt/css/css-images/image-orientation/image-orientation-list-style-image.html
@@ -4,7 +4,7 @@ <link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au"> <link rel="help" href="https://drafts.csswg.org/css-images-3/#propdef-image-orientation"> <link rel="match" href="reference/image-orientation-list-style-image-ref.html"> -<meta name=fuzzy content="0-3;0-50"> +<meta name=fuzzy content="0-3;0-60"> <style> ul { margin-left: 100px; list-style-image: url(support/exif-orientation-2-ur.jpg); } .no-orient { image-orientation: none; }
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/max-height-stretch-relayout.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/max-height-stretch-relayout.html new file mode 100644 index 0000000..eda960a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/max-height-stretch-relayout.html
@@ -0,0 +1,27 @@ +<!DOCTYPE html> +<title>Resize containing block of auto-height multicol container with max-height:stretch</title> +<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org"> +<link rel="help" href="https://issues.chromium.org/issues/486806596"> +<link rel="match" href="../reference/ref-filled-green-100px-square.xht"> +<style> + #target { + columns: 2; + column-fill: auto; + gap: 0; + max-height: stretch; + } + #content { + height: 200px; + background: green; + } +</style> +<p>Test passes if there is a filled green square and <strong>no red</strong>.</p> +<div id="elm" style="width:100px; height:30px; background:red;"> + <div id="target"> + <div id="content"></div> + </div> +</div> +<script> + document.body.offsetTop; + elm.style.height = "100px"; +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/input/keyboard-snap-interruption.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/input/keyboard-snap-interruption.html new file mode 100644 index 0000000..6e0aa362 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/input/keyboard-snap-interruption.html
@@ -0,0 +1,67 @@ +<!DOCTYPE html> +<link rel="help" href="https://drafts.csswg.org/css-scroll-snap-1/#scroll-snap-type" /> +<title>Keyboard scroll snap interruption</title> +<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1"> +<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/testdriver-actions.js"></script> +<script src="/dom/events/scrolling/scroll_support.js"></script> +<script src="../support/common.js"></script> + +<style> + #scroller { + width: 600px; + height: 300px; + overflow-x: scroll; + scroll-behavior: smooth; + scroll-snap-type: x mandatory; + display: flex; + border: 1px solid black; + } + .snap { + width: 600px; + height: 100%; + flex-shrink: 0; + scroll-snap-align: start; + } + #snap-left { + background-color: red; + } + #snap-right { + background-color: blue; + } +</style> + +<div id="scroller" tabindex="0"> + <div class="snap" id="snap-left"></div> + <div class="snap" id="snap-right"></div> +</div> + +<script> +const scroller = document.getElementById("scroller"); + +promise_test(async t => { + scroller.focus(); + assert_equals(scroller.scrollLeft, 0, "verify test pre-condition"); + + const scrollEndPromise = waitForScrollEndFallbackToDelayWithoutScrollEvent(scroller); + + // Send first key press to start smooth snap animation to 600. + await keyPress(scroller, "ArrowRight"); + + // Wait for animation to start progressing. + await waitFor(() => scroller.scrollLeft > 0, "Timeout waiting for scroll to start"); + assert_less_than(scroller.scrollLeft, 600, "Scroll should not have finished yet"); + + // Send second key press to interrupt the ongoing snap animation. + await keyPress(scroller, "ArrowRight"); + + // Wait for the scroll to fully settle. + await scrollEndPromise; + + // Assert that it successfully reached the mandatory snap target. + assert_equals(scroller.scrollLeft, 600, "Should successfully snap to the target despite interruption"); +}, "Interrupting a snap animation with another key press targeting the same node preserves snapping destination"); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/nested-supercedes-common-to-both-axes.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/nested-supercedes-common-to-both-axes.html index c76ba27..ecebe43 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/nested-supercedes-common-to-both-axes.html +++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/nested-supercedes-common-to-both-axes.html
@@ -51,9 +51,10 @@ </style> <div class="scroller" id="scroller"> <div class="large-space"></div> - <div id="box1" class="snap box">Box 1</div> - <div id="box2" class="inner snap box">Box 2</div> - <div id="box3" class="inner snap box">Box 3</div> + <div id="box1" class="snap box">Box 1 + <div id="box2" class="inner snap box">Box 2</div> + <div id="box3" class="inner snap box">Box 3</div> + </div> </div> <script> window.onload = () => {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-inner-target.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-inner-target.html index feefbe1..aaf26d4 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-inner-target.html +++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-inner-target.html
@@ -8,7 +8,6 @@ <script src="/resources/testdriver.js"></script> <script src="/resources/testdriver-actions.js"></script> <script src="/resources/testdriver-vendor.js"></script> - <script src="resources/common.js" ></script> </head> <body> <style> @@ -34,7 +33,6 @@ position: absolute; width: 100px; height: 100px; - border: solid 1px black; } .top { top: 0px; @@ -54,29 +52,29 @@ .inner1 { height: 150px; width: 150px; - top: 150px; - left: 100px; + top: 0px; + left: 50px; background-color: blue; } .inner2 { height: 100px; width: 100px; - top: 150px; - left: 100px; + top: 0px; + left: 0px; background-color: pink; } .inner3 { height: 75px; width: 75px; - top: 150px; - left: 100px; + top: 0px; + left: 0px; background-color: green; } .inner4 { height: 50px; width: 50px; - top: 150px; - left: 100px; + top: 0px; + left: 0px; background-color: grey; } .outer { @@ -91,11 +89,15 @@ <div class="large-space"></div> <div class="top left target">Top Left</div> <div class="top right target">Top Right</div> - <div class="outer target" id="outer">Outer</div> - <div class="inner inner1 target" id="inner1">I1</div> - <div class="inner inner2 target" id="inner2">I2</div> - <div class="inner inner3 target" id="inner3">I3</div> - <div class="inner inner4 target" id="inner4">I4</div> + <div class="outer target" id="outer">Outer + <div class="inner inner1 target" id="inner1">I1 + <div class="inner inner2 target" id="inner2">I2 + <div class="inner inner3 target" id="inner3">I3 + <div class="inner inner4 target" id="inner4">I4</div> + </div> + </div> + </div> + </div> </div> <script> window.onload = (async () => { @@ -107,46 +109,61 @@ const scroller = document.getElementById("scroller"); promise_test(async (t) => { + t.add_cleanup(() => { + scroller.scrollTop = 0; + }); await waitForCompositorCommit(); - await runScrollSnapSelectionVerificationTest(t, scroller, - /*aligned_elements_x=*/[], - /*aligned_elements_y=*/[inner1, inner2, inner3, inner4, outer], - /*axis=*/"y", - /*expected_target_x*/null, - /*expected_target_y*/inner4); + scroller.scrollTop = outer.offsetTop; + assert_equals(scroller.scrollTop, outer.offsetTop, + "scroll position should be at the snap target"); + t.add_cleanup(() => { + // Reset inner4's style. + inner4.style.left = ""; + }); // Push inner4 outside the snapport. It should no longer be considered // the snap target; inner3 is next in line. inner4.style.left = "500px"; - await runScrollSnapSelectionVerificationTest(t, scroller, - /*aligned_elements_x=*/[], - /*aligned_elements_y=*/[inner1, inner2, inner3, inner4, outer], - /*axis=*/"y", - /*expected_target_x*/null, - /*expected_target_y*/inner3); + assert_equals(scroller.scrollTop, outer.offsetTop, + "scroll position should be at the snap target"); + assert_equals(scroller.scrollLeft, 0, + "horizontal scroll position should remain unchanged"); - // Reset inner4's style. - inner4.style.left = "100px"; + t.add_cleanup(() => { + inner3.style.top = ""; + }); + // Move inner3 so that snap-after-relayout follows it. + inner3.style.top = "100px"; + assert_equals(scroller.scrollTop, outer.offsetTop + 100, + "scroll position should follow inner3 snap target after relayout"); }, "snap container selects innermost area as snap target"); promise_test(async (t) => { t.add_cleanup(() => { - outer.style.top = "150px"; + outer.style.top = ""; }); await waitForCompositorCommit(); - // Move outer target below inner targets. + // Move outer target; all inner targets move with it, so every + // inner target's Y offset equals outer's. outer.style.top = "400px"; - // Snap to now-below outer target. + // Scroll to the position where all snap targets are co-located; + // inner4 is selected as the snap target since it is the innermost. scroller.scrollTop = outer.offsetTop; + assert_equals(scroller.scrollTop, outer.offsetTop, + "scroll position should be at the snap target"); - runLayoutSnapSeletionVerificationTest(t, scroller, - [inner1, inner2, inner3, inner4], outer, "y"); - }, "snap container follows selected snap target after layout change " + - "(the pre-existing snap target should not be overriden because of " + - "the innermost area)"); + t.add_cleanup(() => { + inner4.style.top = ""; + }); + // Move the innermost target so that snap-after-relayout follows it. + inner4.style.top = "100px"; + assert_equals(scroller.scrollTop, outer.offsetTop + 100, + "scroll position should follow the innermost snap target after relayout"); + }, "snap container follows the innermost snap target after layout change " + + "(not the co-located outer target)"); }); </script> </body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-targeted-element-both-axes-iframe.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-targeted-element-both-axes-iframe.html new file mode 100644 index 0000000..fdea771 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-targeted-element-both-axes-iframe.html
@@ -0,0 +1,31 @@ +<!DOCTYPE html> +<html> + <body> + <style> + #scroller { + overflow: scroll; + width: 360px; + height: 360px; + scroll-snap-type: both mandatory; + position: relative; + scrollbar-width: none; + } + .box { + width: 100px; + height: 100px; + background-color: green; + position: absolute; + scroll-snap-align: center; + } + .box:target { + background-color: blue; + } + </style> + <div id="scroller"> + <div style="width: 700px; height: 700px;"></div> + <div id="a" class="box" style="left: 330px; top: 210px;"></div> + <div id="b" class="box" style="left: 210px; top: 330px;"></div> + <div id="target" class="box" style="left: 330px; top: 330px;"></div> + </div> + </body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-targeted-element-both-axes.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-targeted-element-both-axes.html new file mode 100644 index 0000000..e488a61 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-targeted-element-both-axes.html
@@ -0,0 +1,71 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <title>CSS Scroll Snap: targeted element preferred over aligned snap areas on both axes</title> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="/dom/events/scrolling/scroll_support.js"></script> +</head> +<body> + <iframe id="iframe" src="prefer-targeted-element-both-axes-iframe.html#target" + style="width: 400px; height: 400px;"></iframe> + <script> + // 3 snap targets in a 360x360 scroller (scroll-snap-type: both mandatory, + // scroll-snap-align: center, scrollbar-width: none). snap_x = left - 130, + // snap_y = top - 130. + // + // #a: left=330, top=210 snap=(200, 80) -- X-aligned with target + // #b: left=210, top=330 snap=( 80, 200) -- Y-aligned with target + // #target: left=330, top=330 snap=(200, 200) -- URL-targeted, last in DOM + // + // At scroll (200, 200), #a and #target are aligned on the X axis and #b and + // #target are aligned on the Y axis. #a and #b appear before #target in DOM + // order, so a browser that stops searching once it finds a valid (x, y) pair + // from the previously snapped targets would pick #a for X and #b for Y, + // never reaching #target. The test verifies correct behavior by moving #a + // slightly on X and #b slightly on Y, then asserting the scroller stays at + // #target's snap position (200, 200) rather than following #a or #b. + + promise_test(async () => { + const iframe = document.getElementById("iframe"); + await new Promise(resolve => { + iframe.addEventListener("load", resolve, { once: true }); + }); + + await waitForCompositorCommit(); + + const doc = iframe.contentDocument; + const scroller = doc.getElementById("scroller"); + const a = doc.getElementById("a"); + const b = doc.getElementById("b"); + + // On chrome loading #target does not snap to the expected position. + if (scroller.scrollLeft != 200 || scroller.scrollTop != 200) { + scroller.scrollTo(200, 200); + } + // Verify the scroller snapped to #target's position (200, 200) on load + // due to the URL fragment. + assert_equals(scroller.scrollLeft, 200, + "scroller initially snapped to #target's X position via URL fragment"); + assert_equals(scroller.scrollTop, 200, + "scroller initially snapped to #target's Y position via URL fragment"); + + // Move #a slightly on X (snap_x: 200 → 210) and #b slightly on Y + // (snap_y: 200 → 210), triggering a resnap. The scroller should stay at + // #target's position (200, 200), not follow #a to x=210 or #b to y=210. + a.style.left = "340px"; + b.style.top = "340px"; + + await new Promise(resolve => requestAnimationFrame(resolve)); + await new Promise(resolve => requestAnimationFrame(resolve)); + + assert_equals(scroller.scrollLeft, 200, + "scroller prefers #target over #a on X axis"); + assert_equals(scroller.scrollTop, 200, + "scroller prefers #target over #b on Y axis"); + }, "scroller selects targeted area among multiple aligned areas on both axes"); + </script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-autospace/text-autospace-preformatted-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-autospace/text-autospace-preformatted-001-ref.html index d3679fc..3d8234f 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-text/text-autospace/text-autospace-preformatted-001-ref.html +++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-autospace/text-autospace-preformatted-001-ref.html
@@ -3,7 +3,7 @@ <style> .container { font: 40px sans-serif; - text-autospace: none; + text-autospace: no-autospace; } .mono { font-family: monospace;
diff --git a/third_party/blink/web_tests/external/wpt/css/css-values/html-attr-case-insensitivity-ref.html b/third_party/blink/web_tests/external/wpt/css/css-values/html-attr-case-insensitivity-ref.html new file mode 100644 index 0000000..b20171db --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-values/html-attr-case-insensitivity-ref.html
@@ -0,0 +1,23 @@ +<!DOCTYPE html> +<html lang="en"> +<meta charset="utf-8"> + +<title>Reference: HTML attribute names are ASCII-case-insensitive</title> + +<style> +div { + color: green; +} +</style> + +<div>This should be green.</div> +<div>This should be green.</div> +<div>This should be green.</div> + +<div>This should be green.</div> +<div>This should be green.</div> +<div>This should be green.</div> + +<div>This should be green.</div> +<div>This should be green.</div> +<div>This should be green.</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-values/html-attr-case-insensitivity.html b/third_party/blink/web_tests/external/wpt/css/css-values/html-attr-case-insensitivity.html new file mode 100644 index 0000000..39ba432a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-values/html-attr-case-insensitivity.html
@@ -0,0 +1,36 @@ +<!DOCTYPE html> +<html lang="en"> +<meta charset="utf-8"> + +<title>HTML attribute names are ASCII-case-insensitive</title> + +<link rel="help" href="https://drafts.csswg.org/css-values-5/#typedef-attr-name"> +<link rel="help" href="https://html.spec.whatwg.org/multipage/syntax.html#syntax"> +<link rel="match" href="html-attr-case-insensitivity-ref.html"/> + +<style> +div.a { + color: attr(color-attr type(<color>), red); +} +div.b { + color: attr(CoLoR-attr type(<color>), red); +} +div.c { + color: attr(CØLØR-ÅTTR type(<color>), green); +} +div.d { + color: attr(CØLØR-ÅTTR type(<color>), red); +} +</style> + +<div class="a" coLor-attr="green">This should be green.</div> +<div class="a" CoLoR-attr="green">This should be green.</div> +<div class="a" COLOR-ATTR="green">This should be green.</div> + +<div class="b" coLor-attr="green">This should be green.</div> +<div class="b" CoLoR-attr="green">This should be green.</div> +<div class="b" COLOR-ATTR="green">This should be green.</div> + +<div class="c" cølør-åttr="red">This should be green.</div> +<div class="c" CøLøR-åttr="red">This should be green.</div> +<div class="d" CØLØR-ÅTTR="green">This should be green.</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-viewport/zoom/font-size-keyword-system-font.html b/third_party/blink/web_tests/external/wpt/css/css-viewport/zoom/font-size-keyword-system-font.html new file mode 100644 index 0000000..ae5f9d1 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-viewport/zoom/font-size-keyword-system-font.html
@@ -0,0 +1,31 @@ +<!DOCTYPE html> +<title>CSS zoom applies to font-size when specified via system font keyword</title> +<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io"> +<link rel="author" title="Mozilla" href="https://mozilla.org"> +<link rel="help" href="https://drafts.csswg.org/css-viewport/"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<style> +#ref, #target { + font: menu; + width: 1em; + height: 1em; +} +#target { + zoom: 2; +} +</style> +<div id="ref">Reference</div> +<div id="target">Target</div> +<script> +test(function() { + const unzoomedComputedSize = parseFloat(getComputedStyle(ref).fontSize); + assert_greater_than(unzoomedComputedSize, 0, "system font should have a positive font-size"); + const zoomedComputedSize = parseFloat(getComputedStyle(target).fontSize); + assert_equals(zoomedComputedSize, unzoomedComputedSize, "computed style should be the same"); + + const unzoomedWidth = ref.getBoundingClientRect().width; + const zoomedWidth = target.getBoundingClientRect().width; + assert_approx_equals(zoomedWidth, 2 * unzoomedWidth, 0.01); +}, "zoom scales font-size set via system font keyword"); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vlr-003.xht b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vlr-003.xht index 40ac9fca..fdaca89 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vlr-003.xht +++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vlr-003.xht
@@ -8,7 +8,7 @@ <!-- Test inspired by - https://searchfox.org/mozilla-central/source/layout/reftests/writing-mode/1130907-intrinsic-sizing-2.html + https://searchfox.org/firefox-main/source/layout/reftests/writing-mode/1130907-intrinsic-sizing-2.html --> <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vlr-005.xht b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vlr-005.xht index a40a1dd..39caae3 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vlr-005.xht +++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vlr-005.xht
@@ -8,7 +8,7 @@ <!-- Test inspired by - https://searchfox.org/mozilla-central/source/layout/reftests/writing-mode/1130907-intrinsic-sizing-2.html + https://searchfox.org/firefox-main/source/layout/reftests/writing-mode/1130907-intrinsic-sizing-2.html --> <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vlr-007.xht b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vlr-007.xht index eb65d2c1..5bb763d 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vlr-007.xht +++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vlr-007.xht
@@ -8,7 +8,7 @@ <!-- Test inspired by - https://searchfox.org/mozilla-central/source/layout/reftests/writing-mode/1130907-intrinsic-sizing-2.html + https://searchfox.org/firefox-main/source/layout/reftests/writing-mode/1130907-intrinsic-sizing-2.html --> <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vlr-009.xht b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vlr-009.xht index 444f53e2..2fa2881c 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vlr-009.xht +++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vlr-009.xht
@@ -8,7 +8,7 @@ <!-- Test inspired by - https://searchfox.org/mozilla-central/source/layout/reftests/writing-mode/1130907-intrinsic-sizing-2.html + https://searchfox.org/firefox-main/source/layout/reftests/writing-mode/1130907-intrinsic-sizing-2.html --> <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vlr-011.xht b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vlr-011.xht index 3d4ecdf9..73626a0e 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vlr-011.xht +++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vlr-011.xht
@@ -8,7 +8,7 @@ <!-- Test inspired by - https://searchfox.org/mozilla-central/source/layout/reftests/writing-mode/1130907-intrinsic-sizing-2.html + https://searchfox.org/firefox-main/source/layout/reftests/writing-mode/1130907-intrinsic-sizing-2.html --> <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vlr-013.xht b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vlr-013.xht index c617555..2e340b4 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vlr-013.xht +++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vlr-013.xht
@@ -8,7 +8,7 @@ <!-- Test inspired by - https://searchfox.org/mozilla-central/source/layout/reftests/writing-mode/1130907-intrinsic-sizing-2.html + https://searchfox.org/firefox-main/source/layout/reftests/writing-mode/1130907-intrinsic-sizing-2.html --> <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vlr-021.xht b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vlr-021.xht index b3fe884..c23c8b9 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vlr-021.xht +++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vlr-021.xht
@@ -8,7 +8,7 @@ <!-- Test inspired by - https://searchfox.org/mozilla-central/source/layout/reftests/writing-mode/1130907-intrinsic-sizing-2.html + https://searchfox.org/firefox-main/source/layout/reftests/writing-mode/1130907-intrinsic-sizing-2.html --> <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vlr-023.xht b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vlr-023.xht index 235125b5..8e8e452 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vlr-023.xht +++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vlr-023.xht
@@ -8,7 +8,7 @@ <!-- Test inspired by - https://searchfox.org/mozilla-central/source/layout/reftests/writing-mode/1130907-intrinsic-sizing-2.html + https://searchfox.org/firefox-main/source/layout/reftests/writing-mode/1130907-intrinsic-sizing-2.html --> <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vrl-002.xht b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vrl-002.xht index 726385e..6fdad5a 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vrl-002.xht +++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vrl-002.xht
@@ -8,7 +8,7 @@ <!-- Test inspired by - https://searchfox.org/mozilla-central/source/layout/reftests/writing-mode/1130907-intrinsic-sizing-2.html + https://searchfox.org/firefox-main/source/layout/reftests/writing-mode/1130907-intrinsic-sizing-2.html --> <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vrl-004.xht b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vrl-004.xht index 2755c55..ada7956 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vrl-004.xht +++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vrl-004.xht
@@ -8,7 +8,7 @@ <!-- Test inspired by - https://searchfox.org/mozilla-central/source/layout/reftests/writing-mode/1130907-intrinsic-sizing-2.html + https://searchfox.org/firefox-main/source/layout/reftests/writing-mode/1130907-intrinsic-sizing-2.html --> <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vrl-006.xht b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vrl-006.xht index 24f2c464..717c47c 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vrl-006.xht +++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vrl-006.xht
@@ -8,7 +8,7 @@ <!-- Test inspired by - https://searchfox.org/mozilla-central/source/layout/reftests/writing-mode/1130907-intrinsic-sizing-2.html + https://searchfox.org/firefox-main/source/layout/reftests/writing-mode/1130907-intrinsic-sizing-2.html --> <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vrl-008.xht b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vrl-008.xht index afcf6f7e..0bdc437 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vrl-008.xht +++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vrl-008.xht
@@ -8,7 +8,7 @@ <!-- Test inspired by - https://searchfox.org/mozilla-central/source/layout/reftests/writing-mode/1130907-intrinsic-sizing-2.html + https://searchfox.org/firefox-main/source/layout/reftests/writing-mode/1130907-intrinsic-sizing-2.html --> <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vrl-010.xht b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vrl-010.xht index 5c361ef..3e71230d 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vrl-010.xht +++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vrl-010.xht
@@ -8,7 +8,7 @@ <!-- Test inspired by - https://searchfox.org/mozilla-central/source/layout/reftests/writing-mode/1130907-intrinsic-sizing-2.html + https://searchfox.org/firefox-main/source/layout/reftests/writing-mode/1130907-intrinsic-sizing-2.html --> <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vrl-012.xht b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vrl-012.xht index 6e1b687..5ef21db 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vrl-012.xht +++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/line-box-height-vrl-012.xht
@@ -8,7 +8,7 @@ <!-- Test inspired by - https://searchfox.org/mozilla-central/source/layout/reftests/writing-mode/1130907-intrinsic-sizing-2.html + https://searchfox.org/firefox-main/source/layout/reftests/writing-mode/1130907-intrinsic-sizing-2.html --> <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom/adoptedstylesheets-observablearray.html b/third_party/blink/web_tests/external/wpt/css/cssom/adoptedstylesheets-observablearray.html index 783a054..75d8ffc 100644 --- a/third_party/blink/web_tests/external/wpt/css/cssom/adoptedstylesheets-observablearray.html +++ b/third_party/blink/web_tests/external/wpt/css/cssom/adoptedstylesheets-observablearray.html
@@ -89,4 +89,15 @@ const shadow = host.attachShadow({mode: 'open'}); assert_true(Array.isArray(shadow.adoptedStyleSheets)); }, "adoptedStyleSheets should return true for isArray()"); + +test(function() { + let backing = null; + Object.defineProperty(Array.prototype, "1", { + configurable: true, + set(v) { backing = this; } + }); + document.adoptedStyleSheets = [new CSSStyleSheet(), new CSSStyleSheet()]; + delete Array.prototype["1"]; + assert_equals(backing, null); +}, "adoptedStyleSheets should not expose its backing object via prototype"); </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom/stylesheet-same-origin.sub.html b/third_party/blink/web_tests/external/wpt/css/cssom/stylesheet-same-origin.sub.html index 6ad5519..10097132 100644 --- a/third_party/blink/web_tests/external/wpt/css/cssom/stylesheet-same-origin.sub.html +++ b/third_party/blink/web_tests/external/wpt/css/cssom/stylesheet-same-origin.sub.html
@@ -8,6 +8,7 @@ <script src="/resources/testharnessreport.js"></script> <link id="crossorigin" href="http://www1.{{host}}:{{ports[http][1]}}/css/cssom/stylesheet-same-origin.css" rel="stylesheet"> + <link id="crossorigin-clone" href="http://www1.{{host}}:{{ports[http][1]}}/css/cssom/stylesheet-same-origin.css" rel="stylesheet"> <link id="sameorigin" href="stylesheet-same-origin.css" rel="stylesheet"> <link id="sameorigindata" href="data:text/css,.green-text{color:rgb(0, 255, 0)}" rel="stylesheet"> <link id="redirect-sameorigin-to-crossorigin" @@ -20,6 +21,7 @@ <script> var crossorigin = document.getElementById("crossorigin").sheet; + var crossoriginClone = document.getElementById("crossorigin-clone").sheet; var redirectSameOriginToCrossOrigin = document.getElementById("redirect-sameorigin-to-crossorigin").sheet; var redirectCrossOriginToSameOrigin = document.getElementById("redirect-crossorigin-to-sameorigin").sheet; var loadError = document.getElementById("loaderror").sheet; @@ -77,6 +79,11 @@ doOriginCleanCheck(sameorigindata, "data:css"); }, "Origin-clean check in data:css CSSOM Stylesheets"); + test(function() { + doOriginDirtyCheck(crossoriginClone, "cross-origin clone"); + crossoriginClone.media.appendMedium("screen"); + doOriginDirtyCheck(crossoriginClone, "cross-origin clone after mutation"); + }, "Origin-clean check in copied cross-origin CSSOM Stylesheets"); </script> </head> <body>
diff --git a/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filter-3d-transform-perspective-ref.html b/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filter-3d-transform-perspective-ref.html new file mode 100644 index 0000000..323f5aa4 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filter-3d-transform-perspective-ref.html
@@ -0,0 +1,23 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>backdrop-filter with 3D transform and perspective on parent (reference)</title> + +<style> + .backdrop { + width: 150px; + height: 150px; + background: yellow; + perspective: 600px; + padding: 20px; + } + .card { + width: 100px; + height: 100px; + background: blue; + transform: rotateY(45deg); + } +</style> + +<div class="backdrop"> + <div class="card"></div> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filter-3d-transform-perspective.html b/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filter-3d-transform-perspective.html new file mode 100644 index 0000000..1df16d57 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filter-3d-transform-perspective.html
@@ -0,0 +1,32 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<meta name=fuzzy content="maxDifference=0-150; totalPixels=0-400"> +<title>backdrop-filter with 3D transform and perspective on parent</title> +<link rel="help" href="https://drafts.fxtf.org/filter-effects-2/#BackdropFilterProperty"> +<link rel="match" href="backdrop-filter-3d-transform-perspective-ref.html"> + +<!-- + Expected: A yellow box containing a perspective-transformed shape filled + with blue (the inverted yellow backdrop). The backdrop-filter: invert(1) + should apply correctly when the element's direct parent provides perspective. +--> + +<style> + .backdrop { + width: 150px; + height: 150px; + background: yellow; + perspective: 600px; + padding: 20px; + } + .card { + width: 100px; + height: 100px; + backdrop-filter: invert(1); + transform: rotateY(45deg); + } +</style> + +<div class="backdrop"> + <div class="card"></div> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filter-nested-3d-transform-perspective-ref.html b/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filter-nested-3d-transform-perspective-ref.html new file mode 100644 index 0000000..d62a2235 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filter-nested-3d-transform-perspective-ref.html
@@ -0,0 +1,27 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>backdrop-filter with 3D transform and perspective in nested context (reference)</title> + +<style> + .backdrop { + width: 150px; + height: 150px; + background: yellow; + } + .scene { + perspective: 300px; + padding: 20px; + } + .card { + width: 100px; + height: 100px; + background: blue; + transform: rotateY(45deg); + } +</style> + +<div class="backdrop"> + <div class="scene"> + <div class="card"></div> + </div> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filter-nested-3d-transform-perspective.html b/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filter-nested-3d-transform-perspective.html new file mode 100644 index 0000000..6bd22e8 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filter-nested-3d-transform-perspective.html
@@ -0,0 +1,37 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<meta name=fuzzy content="maxDifference=0-150; totalPixels=0-400"> +<title>backdrop-filter with 3D transform and perspective in nested context</title> +<link rel="help" href="https://drafts.fxtf.org/filter-effects-2/#BackdropFilterProperty"> +<link rel="match" href="backdrop-filter-nested-3d-transform-perspective-ref.html"> + +<!-- + Expected: A yellow box containing a perspective-transformed shape filled + with blue (the inverted yellow backdrop). The backdrop-filter: invert(1) + should apply correctly when the element is inside a nested 3D transform + context where a parent provides perspective. +--> + +<style> + .backdrop { + width: 150px; + height: 150px; + background: yellow; + } + .scene { + perspective: 300px; + padding: 20px; + } + .card { + width: 100px; + height: 100px; + backdrop-filter: invert(1); + transform: rotateY(45deg); + } +</style> + +<div class="backdrop"> + <div class="scene"> + <div class="card"></div> + </div> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/printing/number-input-link-crash-print.html b/third_party/blink/web_tests/external/wpt/css/printing/number-input-link-crash-print.html new file mode 100644 index 0000000..65616703 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/printing/number-input-link-crash-print.html
@@ -0,0 +1,5 @@ +<!doctype html> +<!-- Really a crashtest but since we don't really have print crashtests, we assert that we print something --> +<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=2036150"> +<link rel="mismatch" href="/css/reference/blank.html"> +<a href="https://example.org" id="a1"><input type=number></a>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/invalidation/empty-pseudo-in-has-display-none.html b/third_party/blink/web_tests/external/wpt/css/selectors/invalidation/empty-pseudo-in-has-display-none.html new file mode 100644 index 0000000..8513f39 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/selectors/invalidation/empty-pseudo-in-has-display-none.html
@@ -0,0 +1,113 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Selectors Invalidation: :empty in :has() with display:none</title> +<link rel="author" title="Simon Fraser" href="smfr@apple.com"> +<link rel="help" href="https://drafts.csswg.org/selectors/#relational"> +<link rel="help" href="https://drafts.csswg.org/selectors/#empty-pseudo"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<style> + #subject { + color: green; + } + #subject:has(:empty) { + display: none; + } +</style> +<div id="subject"> + <p>This should be visible after the child div gets content.</p> + <div id="child"></div> +</div> +<script> +const subject = document.getElementById("subject"); +const child = document.getElementById("child"); + +function testVisibility(test_name, expectVisible) { + test(function() { + const rect = subject.getBoundingClientRect(); + if (expectVisible) { + assert_not_equals(getComputedStyle(subject).display, "none", "display should not be none"); + assert_greater_than(rect.width, 0, "width should be greater than 0"); + assert_greater_than(rect.height, 0, "height should be greater than 0"); + } else { + assert_equals(getComputedStyle(subject).display, "none", "display should be none"); + } + }, test_name); +} + +testVisibility("Initially hidden because #child is :empty", false); + +child.textContent = "text"; +testVisibility("Visible after inserting text into #child", true); + +{ + let inner = document.createElement("div"); + child.appendChild(inner); +} +testVisibility("Hidden after inserting empty element into #child", false); + +child.textContent = "text"; +testVisibility("Visible after inserting text into empty #child", true); + +child.replaceChildren(); +testVisibility("Hidden again after removing all children from #child", false); + +child.textContent = "text"; +testVisibility("Visible again after inserting text into empty #child", true); + +child.textContent = ""; +testVisibility("Hidden again after clearing text from #child", false); + +{ + let inner = document.createElement("div"); + inner.textContent = "content"; + child.appendChild(inner); +} +testVisibility("Visible after inserting non-empty element into #child", true); +</script> + +<!-- Test :has(:not(:empty)) with display:none --> +<style> + #subject2 { + display: none; + } + #subject2:has(:not(:empty)) { + display: block; + } +</style> +<div id="subject2"> + <div id="child2"></div> +</div> +<script> +{ + const subject2 = document.getElementById("subject2"); + const child2 = document.getElementById("child2"); + + function testVisibility2(test_name, expectVisible) { + test(function() { + if (expectVisible) { + assert_not_equals(getComputedStyle(subject2).display, "none", "display should not be none"); + } else { + assert_equals(getComputedStyle(subject2).display, "none", "display should be none"); + } + }, test_name); + } + + testVisibility2(":not(:empty) - Initially hidden because #child2 is :empty", false); + + child2.textContent = "text"; + testVisibility2(":not(:empty) - Visible after inserting text into #child2", true); + + child2.textContent = ""; + testVisibility2(":not(:empty) - Hidden after clearing text from #child2", false); + + child2.textContent = "text"; + testVisibility2(":not(:empty) - Visible again after inserting text into #child2", true); + + child2.replaceChildren(); + testVisibility2(":not(:empty) - Hidden after removing all children from #child2", false); + + child2.appendChild(document.createElement("div")); + testVisibility2(":not(:empty) - Visible after inserting element into #child2", true); +} +</script>
diff --git a/third_party/blink/web_tests/external/wpt/workers/constructors/Worker/expected-self-properties.worker-expected.txt b/third_party/blink/web_tests/external/wpt/css/selectors/media/sound-state-expected.txt similarity index 63% rename from third_party/blink/web_tests/external/wpt/workers/constructors/Worker/expected-self-properties.worker-expected.txt rename to third_party/blink/web_tests/external/wpt/css/selectors/media/sound-state-expected.txt index 5e3cfcd..f80c43e 100644 --- a/third_party/blink/web_tests/external/wpt/workers/constructors/Worker/expected-self-properties.worker-expected.txt +++ b/third_party/blink/web_tests/external/wpt/css/selectors/media/sound-state-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -[FAIL] existence of SharedWorker +[FAIL] Test :muted matches .muted for content attribute default assert_true: expected true got false Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/media/sound-state.html b/third_party/blink/web_tests/external/wpt/css/selectors/media/sound-state.html index e41e4ac..fd0e8f5 100644 --- a/third_party/blink/web_tests/external/wpt/css/selectors/media/sound-state.html +++ b/third_party/blink/web_tests/external/wpt/css/selectors/media/sound-state.html
@@ -43,5 +43,30 @@ assert_equals(document.querySelector("video:muted"), video); assert_equals(document.querySelector("video:not(:muted)"), null); }, "Test :muted pseudo-class"); + + test((t) => { + assert_implements(CSS.supports("selector(:muted)"), ":muted is not supported"); + + const video = document.createElement("video"); + document.body.appendChild(video); + t.add_cleanup(() => video.remove()); + + assert_false(video.muted); + assert_false(video.matches(":muted")); + + video.setAttribute("muted", ""); + assert_true(video.muted); + assert_true(video.matches(":muted")); + + video.removeAttribute("muted"); + assert_false(video.muted); + assert_false(video.matches(":muted")); + + video.setAttribute("muted", ""); + assert_true(video.muted); + video.muted = false; + assert_false(video.muted); + assert_false(video.matches(":muted")); + }, "Test :muted matches .muted for content attribute default"); </script> </body>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/webkit-pseudo-element.html b/third_party/blink/web_tests/external/wpt/css/selectors/webkit-pseudo-element.html index 30103fa..babf2301 100644 --- a/third_party/blink/web_tests/external/wpt/css/selectors/webkit-pseudo-element.html +++ b/third_party/blink/web_tests/external/wpt/css/selectors/webkit-pseudo-element.html
@@ -39,6 +39,15 @@ }, "qS and qSA shouldn't throw exception"); test(() => { + document.querySelectorAll("span::-webkit-something-invalid:active"); + document.querySelectorAll("span::-webkit-something-invalid:hover"); + }, "User-action pseudo-classes are valid"); + + test(() => { + assert_throws_dom("SyntaxError", () => document.querySelector("span::-webkit-something-invalid::before")); + }, "Nested pseudos are invalid"); + + test(() => { let sheet = document.getElementById("style").sheet; assert_equals(sheet.cssRules.length, 2); assert_throws_dom("SyntaxError", () => document.querySelector("span::-webkitfoo"));
diff --git a/third_party/blink/web_tests/external/wpt/custom-elements/registries/ShadowRoot-init-customElementRegistry.html b/third_party/blink/web_tests/external/wpt/custom-elements/registries/ShadowRoot-init-customElementRegistry.html index b81fbce..a392b50 100644 --- a/third_party/blink/web_tests/external/wpt/custom-elements/registries/ShadowRoot-init-customElementRegistry.html +++ b/third_party/blink/web_tests/external/wpt/custom-elements/registries/ShadowRoot-init-customElementRegistry.html
@@ -25,6 +25,25 @@ test(() => { const registry = new CustomElementRegistry; + const host = document.createElement('div', {customElementRegistry: registry}); + assert_equals(host.customElementRegistry, registry); + const shadowRoot = host.attachShadow({mode: 'closed'}); + assert_equals(shadowRoot.customElementRegistry, window.customElements); +}, 'A newly attached ShadowRoot should use the global registry by default even if the host uses a custom registry'); + +test(() => { + const registry = new CustomElementRegistry; + const outerHost = document.body.appendChild(document.createElement('div')); + const outerShadow = outerHost.attachShadow({mode: 'closed', customElementRegistry: registry}); + outerShadow.innerHTML = '<div></div>'; + assert_equals(outerShadow.querySelector('div').customElementRegistry, registry); + const host = outerShadow.querySelector('div'); + const shadowRoot = host.attachShadow({mode: 'closed'}); + assert_equals(shadowRoot.customElementRegistry, window.customElements); +}, 'A newly attached ShadowRoot should use the global registry by default even if the host is within another shadow tree that uses a custom registry'); + +test(() => { + const registry = new CustomElementRegistry; const shadowRoot = document.createElement('div').attachShadow({mode: 'closed', customElementRegistry: registry}); assert_equals(shadowRoot.customElementRegistry, registry); }, 'A newly attached disconnected ShadowRoot should use the scoped registry if explicitly specified in attachShadow');
diff --git a/third_party/blink/web_tests/external/wpt/custom-elements/registries/ShadowRoot-init-declarative-expected.txt b/third_party/blink/web_tests/external/wpt/custom-elements/registries/ShadowRoot-init-declarative-expected.txt deleted file mode 100644 index 8973535..0000000 --- a/third_party/blink/web_tests/external/wpt/custom-elements/registries/ShadowRoot-init-declarative-expected.txt +++ /dev/null
@@ -1,7 +0,0 @@ -This is a testharness.js-based test. -[FAIL] Custom element inside 'shadowrootcustomelementregistry' declarative shadow root - assert_equals: expected null but got object "[object CustomElementRegistry]" -[FAIL] Built-in element inside 'shadowrootcustomelementregistry' declarative shadow root - assert_equals: expected null but got object "[object CustomElementRegistry]" -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/custom-elements/registries/ShadowRoot-init-declarative.html b/third_party/blink/web_tests/external/wpt/custom-elements/registries/ShadowRoot-init-declarative.html index 13359df..01863a2 100644 --- a/third_party/blink/web_tests/external/wpt/custom-elements/registries/ShadowRoot-init-declarative.html +++ b/third_party/blink/web_tests/external/wpt/custom-elements/registries/ShadowRoot-init-declarative.html
@@ -15,8 +15,9 @@ customElement.attachShadow({ mode: "open" }); - assert_equals(customElement.shadowRoot.customElementRegistry, null); -}, "Custom element inside 'shadowrootcustomelementregistry' declarative shadow root"); + assert_equals(customElement.customElementRegistry, null); + assert_equals(customElement.shadowRoot.customElementRegistry, window.customElements); +}, "Custom element inside 'shadowrootcustomelementregistry' declarative shadow root should use document's registry as attachShadow default registry"); test(() => { const divElement = host.shadowRoot.lastElementChild; @@ -24,6 +25,7 @@ divElement.attachShadow({ mode: "open" }); - assert_equals(divElement.shadowRoot.customElementRegistry, null); -}, "Built-in element inside 'shadowrootcustomelementregistry' declarative shadow root"); + assert_equals(divElement.customElementRegistry, null); + assert_equals(divElement.shadowRoot.customElementRegistry, window.customElements); +}, "Built-in element inside 'shadowrootcustomelementregistry' declarative shadow root should use document's registry as attachShadow default registry"); </script>
diff --git a/third_party/blink/web_tests/external/wpt/custom-elements/registries/scoped-custom-element-registry-customelementregistry-attribute.html b/third_party/blink/web_tests/external/wpt/custom-elements/registries/scoped-custom-element-registry-customelementregistry-attribute.html index c29ad6b..ed553db 100644 --- a/third_party/blink/web_tests/external/wpt/custom-elements/registries/scoped-custom-element-registry-customelementregistry-attribute.html +++ b/third_party/blink/web_tests/external/wpt/custom-elements/registries/scoped-custom-element-registry-customelementregistry-attribute.html
@@ -7,6 +7,25 @@ <script src="/resources/testharnessreport.js"></script> </head> <body> +<!-- Elements with customelementregistry attribute parsed during initial document load --> +<div id="builtin-with-attr" customelementregistry></div> +<custom-elem id="candidate-with-attr" customelementregistry></custom-elem> +<div id="parent-with-attr" customelementregistry> + <div id="child-of-attr"></div> + <custom-elem id="candidate-child-of-attr"></custom-elem> + <div id="nested-parent"> + <custom-elem id="deep-nested-candidate"></custom-elem> + </div> +</div> + +<!-- Elements without customelementregistry attribute for comparison --> +<div id="builtin-without-attr"></div> +<custom-elem id="candidate-without-attr"></custom-elem> + +<!-- Elements for upgrade testing --> +<upgrade-elem id="upgrade-with-attr" customelementregistry></upgrade-elem> +<upgrade-elem id="upgrade-without-attr"></upgrade-elem> + <script> function makeIframe(test) { @@ -98,6 +117,116 @@ assert_equals(element.customElementRegistry, win.customElements); }, `Setting customelementregistry content attribute during constructor should not make it use null registry`); +function iframeFromSrcdoc(test, srcdoc) { + return new Promise((resolve) => { + const iframe = document.createElement('iframe'); + iframe.srcdoc = srcdoc; + iframe.onload = () => resolve([iframe.contentDocument, iframe.contentWindow]); + document.body.appendChild(iframe); + test.add_cleanup(() => iframe.remove()); + }); +} + +// Tests for customelementregistry attribute on body tag during initial document parse. + +promise_test(async (test) => { + const [doc, win] = await iframeFromSrcdoc(test, + '<!DOCTYPE html><body customelementregistry><div></div></body>'); + assert_equals(doc.body.getAttribute('customelementregistry'), '', + 'body should have the customelementregistry attribute'); + assert_equals(doc.body.customElementRegistry, null, + 'body should have null registry'); + assert_equals(doc.querySelector('div').customElementRegistry, null, + 'div child of body with customelementregistry should have null registry'); +}, 'Body with customelementregistry attribute during initial parse should have null registry and propagate to children'); + +promise_test(async (test) => { + const [doc, win] = await iframeFromSrcdoc(test, + '<!DOCTYPE html><body customelementregistry><a-b></a-b></body>'); + const ab = doc.querySelector('a-b'); + assert_equals(ab.customElementRegistry, null, + 'custom element candidate child of body with customelementregistry should have null registry'); +}, 'Custom element candidate child of body with customelementregistry should have null registry during initial parse'); + +promise_test(async (test) => { + const [doc, win] = await iframeFromSrcdoc(test, + '<!DOCTYPE html><body customelementregistry><div><a-b></a-b></div></body>'); + assert_equals(doc.querySelector('div').customElementRegistry, null, + 'div child should have null registry'); + assert_equals(doc.querySelector('a-b').customElementRegistry, null, + 'nested custom element candidate should have null registry'); +}, 'Descendants of body with customelementregistry should all have null registry during initial parse'); + +promise_test(async (test) => { + const [doc, win] = await iframeFromSrcdoc(test, + '<!DOCTYPE html><html><head></head><body customelementregistry><div></div></body></html>'); + assert_equals(doc.body.customElementRegistry, null, + 'body should have null registry'); + assert_equals(doc.querySelector('div').customElementRegistry, null, + 'div child should have null registry'); +}, 'Body with customelementregistry in a complete document structure should have null registry'); + +// Tests for customelementregistry attribute on elements during initial document parse. + +test(() => { + const element = document.getElementById('builtin-with-attr'); + assert_equals(element.customElementRegistry, null, + 'Built-in element with customelementregistry attribute should have null registry'); +}, 'Initial parse: built-in element with customelementregistry has null registry'); + +test(() => { + const element = document.getElementById('candidate-with-attr'); + assert_equals(element.customElementRegistry, null, + 'Custom element candidate with customelementregistry attribute should have null registry'); +}, 'Initial parse: custom element candidate with customelementregistry has null registry'); + +test(() => { + const element = document.getElementById('builtin-without-attr'); + assert_equals(element.customElementRegistry, window.customElements, + 'Built-in element without customelementregistry should use the global registry'); +}, 'Initial parse: built-in element without customelementregistry uses global registry'); + +test(() => { + const element = document.getElementById('candidate-without-attr'); + assert_equals(element.customElementRegistry, window.customElements, + 'Custom element candidate without customelementregistry should use the global registry'); +}, 'Initial parse: custom element candidate without customelementregistry uses global registry'); + +// Tests for descendants inheriting null registry. + +test(() => { + const child = document.getElementById('child-of-attr'); + assert_equals(child.customElementRegistry, null, + 'Child of element with customelementregistry should have null registry'); +}, 'Initial parse: child of element with customelementregistry inherits null registry'); + +test(() => { + const child = document.getElementById('candidate-child-of-attr'); + assert_equals(child.customElementRegistry, null, + 'Custom element candidate child of element with customelementregistry should have null registry'); +}, 'Initial parse: custom element candidate child inherits null registry from parent'); + +test(() => { + const child = document.getElementById('deep-nested-candidate'); + assert_equals(child.customElementRegistry, null, + 'Deeply nested custom element candidate should have null registry'); +}, 'Initial parse: deeply nested descendant inherits null registry'); + +// Test that custom element with a definition is NOT upgraded when customelementregistry is present. + +test(() => { + const withAttr = document.getElementById('upgrade-with-attr'); + assert_equals(withAttr.constructor, HTMLElement, + 'Custom element candidate with null registry should not be upgraded'); + customElements.define('upgrade-elem', class extends HTMLElement {}); + assert_equals(withAttr.constructor, HTMLElement, + 'Custom element candidate with null registry should still not be upgraded after defining in global registry'); + + const withoutAttr = document.getElementById('upgrade-without-attr'); + assert_true(withoutAttr instanceof customElements.get('upgrade-elem'), + 'Custom element candidate without customelementregistry should be upgraded'); +}, 'Initial parse: global registry define only upgrades elements without customelementregistry'); + </script> </body> </html>
diff --git a/third_party/blink/web_tests/external/wpt/digital-credentials/create.tentative.https.html b/third_party/blink/web_tests/external/wpt/digital-credentials/create.tentative.https.html index cc9690f..6a48524c 100644 --- a/third_party/blink/web_tests/external/wpt/digital-credentials/create.tentative.https.html +++ b/third_party/blink/web_tests/external/wpt/digital-credentials/create.tentative.https.html
@@ -1,6 +1,6 @@ <!DOCTYPE html> <title>Digital Credential API tests for create.</title> -<link rel="help" href="https://wicg.github.io/digital-credentials/" /> +<link rel="help" href="https://w3c-fedid.github.io/digital-credentials/" /> <script src="/common/get-host-info.sub.js"></script> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/digital-credentials/digital-credentials-static-methods.tentative.https.html b/third_party/blink/web_tests/external/wpt/digital-credentials/digital-credentials-static-methods.tentative.https.html index a92288b..bb5e6ce2 100644 --- a/third_party/blink/web_tests/external/wpt/digital-credentials/digital-credentials-static-methods.tentative.https.html +++ b/third_party/blink/web_tests/external/wpt/digital-credentials/digital-credentials-static-methods.tentative.https.html
@@ -1,6 +1,6 @@ <!DOCTYPE html> <title>Digital Credential static methods.</title> -<link rel="help" href="https://wicg.github.io/digital-credentials/" /> +<link rel="help" href="https://w3c-fedid.github.io/digital-credentials/" /> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/digital-credentials/get.https.html b/third_party/blink/web_tests/external/wpt/digital-credentials/get.https.html index 0c7f640..8593bf2 100644 --- a/third_party/blink/web_tests/external/wpt/digital-credentials/get.https.html +++ b/third_party/blink/web_tests/external/wpt/digital-credentials/get.https.html
@@ -1,6 +1,6 @@ <!DOCTYPE html> <title>Digital Credential tests.</title> -<link rel="help" href="https://wicg.github.io/digital-credentials/" /> +<link rel="help" href="https://w3c-fedid.github.io/digital-credentials/" /> <script src="/common/get-host-info.sub.js"></script> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/docs/test-suite-design.md b/third_party/blink/web_tests/external/wpt/docs/test-suite-design.md index 88c5f4a..6dd9294d 100644 --- a/third_party/blink/web_tests/external/wpt/docs/test-suite-design.md +++ b/third_party/blink/web_tests/external/wpt/docs/test-suite-design.md
@@ -65,6 +65,10 @@ * [wdspec][] tests are written in Python and test [the WebDriver browser automation protocol](https://w3c.github.io/webdriver/) +* [aamtest][] tests are written in Python and test accessibility API mappings, + such as [Core Accessibility API Mappings](https://w3c.github.io/core-aam/) + or [HTML Accessibility API Mappings](https://w3c.github.io/html-aam/). + * [Manual tests][manual] rely on a human to run them and determine their result. @@ -75,3 +79,4 @@ [metadata]: writing-tests/out-of-band-metadata [running-from-local-system]: running-tests/from-local-system [wdspec]: writing-tests/wdspec +[aamtest]: writing-tests/aamtest
diff --git a/third_party/blink/web_tests/external/wpt/docs/writing-tests/aamtest.md b/third_party/blink/web_tests/external/wpt/docs/writing-tests/aamtest.md new file mode 100644 index 0000000..273dff7 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/docs/writing-tests/aamtest.md
@@ -0,0 +1,148 @@ +# aamtest tests + +The aamtest tests are used to verify the mapping of web content to +browser-exposed platform-specific accessibility APIs. These mappings are +specified by working groups of the W3C in the following specifications: + +* [Core-AAM](https://w3c.github.io/core-aam) +* [HTML-AAM](https://w3c.github.io/html-aam) +* [DPUB-AAM](https://w3c.github.io/dpub-aam) +* [MathML-AAM](https://w3c.github.io/mathml-aam) +* [Graphics-AAM](https://w3c.github.io/graphics-aam) +* [SVG-AAM](https://w3c.github.io/svg-aam/) + +These tests are written in [the Python programming +language](https://www.python.org/) and structured with [the pytest testing +framework](https://docs.pytest.org/en/latest/). + +The aamtest type is built on the [wdspec](wdspec) test type, and has access to +all the Python fixtures defined for wdspec tests. It uses the web-platform-tests +maintained WebDriver client library to load HTML and to send other WebDriver +commands to the browser. + +The `wptrunner` will know a Python file is an aamtest if it is contained within +an `aamtests` directory. + +## Platform-Specific Accessibility APIs + +Accessibility APIs are platform (or operating system) specific, each platform +has their own API (sometimes more than one). Assistive technologies, such as +screen readers, interact with the browser on behalf of a user via these +APIs. The AAM specifications explain how to expose web content through these +APIs. You can read more about [the APIs in +Core-AAM](https://w3c.github.io/core-aam/#intro_aapi). + +The table below lists: + +* **API Name**: APIs supported by the aamtest framework +* **Fixture Name**: The name of the pytest fixture that returns access to the API (if you are + on the correct platform). +* **Platform**: The platform of that API. +* **Python Bindings**: The Python library that provides bindings to query the API. + +```eval_rst +.. list-table:: + :header-rows: 1 + + * - API Name + - Fixture Name + - Platform + - Python Bindings + * - Accessibility Toolkit (`ATK <https://developer.gnome.org/atk/stable/>`_) and Assistive Technology Service Provider Interface (`AT-SPI <https://gnome.pages.gitlab.gnome.org/at-spi2-core/libatspi/>`_) + - ``atspi`` + - Linux + - `Provided through PyGObject <https://lazka.github.io/pgi-docs/#Atspi-2.0>`_ + * - The NSAccessibility Protocol for macOS (`AX API <https://developer.apple.com/documentation/appkit/nsaccessibility>`_) + - ``axapi`` + - macOS + - `pyobjc-framework-Accessibility <https://pypi.org/project/pyobjc-framework-Accessibility/>`_ + * - MSAA with IAccessible2 1.3 (`IA2 <https://wiki.linuxfoundation.org/accessibility/iaccessible2/start>`_) + - ``ia2`` + - Windows + - Loading module `ia2_api_all.idl <https://github.com/LinuxA11y/IAccessible2>`_ with `comtypes <https://pypi.org/project/comtypes/>`_ +``` + +The APIs are exposed through a pytest fixture with the name in the table +above. The pytest fixture returns a wrapped version of the API. Requesting this +fixture on a platform where it is not supported will result in a `MISSING` +subtest. It is expected that each test file run on a given platform will have +one or more subtests that run to completion, as well as several subtests who's +results will not be recorded. This is because each test file should show how the +**same markup** is exposed in each supporting accessibility APIs/platforms. + +### Package dependencies for Linux API AT-SPI Python Bindings + +In order to test the Linux API AT-SPI, you need to have the following packages +installed: + +``` +sudo apt install libatspi2.0-dev libcairo2-dev libgirepository1.0-dev +``` + +## Adding new tests + +If you would like to add a new aamtest to a specification that does not yet have +coverage, add the tests to an `aamtests` subfolder. This subfolder indicates the +Python files within it will be run as an aamtest. This includes restarting the +browser with accessibility enabled, if you are doing a full run of the test +suite. + +In the `aamtests` subfolder, the `conftest.py` will need to add the +`webdriver/test/support` path and `core-aam/aamtests/support` path to the +sys.path and add the paths as `pytest_plugins` in order to have access to the +appropriate fixtures. See `core-aam/aamtests/conftest.py`. + +### Test design + +Similar to [testharness.js](testharness) tests, each file is a test, and a +function that begins with the name "test_" is a subtest of that test. + +A typical test file contains some html markup and several subtests. Each subtest +will test how that markup is exposed in a single accessibility API. For example, +if you are testing how `<div role=foobar>foobar widget</div>` is exposed in +accessibility APIs, and foobars are supported in the Linux API AT-SPI and macOS +API AX API, you should add a subtest called `test_atspi` and `test_axapi`, +respectively. Both subtests will load the same HTML, then query their respective +accessibility APIs. The subtest name should include, at least, the name of the +API being tested for ease of understanding the test results. + +For example, the file `foobar.py`: +```python +TEST_HTML = "<div role=foobar id=test></div>" + +# Test of the Linux accessibility API: AT-SPI +def test_atspi(atspi, session, inline): + # The `session` and `inline` fixtures are provided from the `wdspec` test infrastructure. + session.url = inline(TEST_HTML) + + # The `atspi` fixture wraps the AT-SPI Python bindings and provides some helper functions, + # such as `find_node`, which finds a node by DOM ID. + node = atspi.find_node("test", session.url) + assert atspi.Accessible.get_role(node) == atspi.Role.FOOBAR + +# Test of the macOS accessibility API: AX API +def test_axapi(axapi, session, inline): + # The `session` and `inline` fixtures are provided from the `wdspec` test infrastructure. + session.url = inline(TEST_HTML) + + # The `axapi` fixture wraps the AX API Python bindings and provides some helper functions, + # such as `find_node`, which finds a node by DOM ID. + node = axapi.find_node("test", session.url) + role = axapi.AXUIElementCopyAttributeValue(node, "AXRole", None)[1] + assert role == "AXFoobar" +``` + +## Adding support for an unsupported API + +To add an unsupported API: + +1. Add the Python package that provides the Python bindings for that API to + `tools/wptrunner/requirements_platform_accessibility.txt`. +2. Create a wrapper object for the new API in `newapi_wrapper.py` in + `core-aam/aamtests/support/`. It must inherit from `ApiWrapper` and follow + the same conventions as the other API wrappers, as appropriate. +3. Add the fixture for that API in + `core-aam/aamtests/support/fixtures_a11y_api.py`. +4. Update the table in the "Platform-Specific Accessibility APIs" section of this + document. +5. Add a new subtest to all the files that contain markup you would like to test.
diff --git a/third_party/blink/web_tests/external/wpt/dom/collections/childnodes-messagechannel-crash.html b/third_party/blink/web_tests/external/wpt/dom/collections/childnodes-messagechannel-crash.html new file mode 100644 index 0000000..f118eff6 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/dom/collections/childnodes-messagechannel-crash.html
@@ -0,0 +1,9 @@ +<!doctype html> +<link rel=help href="https://bugzil.la/2036139"> +<script> +document.addEventListener('DOMContentLoaded', () => { + const a = document.createElement("pre") + const b = new MessageChannel() + b.port1.postMessage(a.childNodes) +}) +</script>
diff --git a/third_party/blink/web_tests/external/wpt/dom/nodes/crashtests/attribute-index-when-no-attributes.html b/third_party/blink/web_tests/external/wpt/dom/nodes/crashtests/attribute-index-when-no-attributes.html new file mode 100644 index 0000000..628fdd81 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/dom/nodes/crashtests/attribute-index-when-no-attributes.html
@@ -0,0 +1,4 @@ +<!DOCTYPE html> +<script> +document.createElement("fieldset").attributes.item(0); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/editing/crashtests/delete-after-removing-first-child.html b/third_party/blink/web_tests/external/wpt/editing/crashtests/delete-after-removing-first-child.html new file mode 100644 index 0000000..3abc982 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/editing/crashtests/delete-after-removing-first-child.html
@@ -0,0 +1,14 @@ +<!DOCTYPE html> +<html id="a"> +<script id="b"> +window.onload = () => { + document.getSelection().collapse(span1); + const range = document.createRange(); + range.setEndBefore(span2); + // This deletes the document element, but leaves behind span 2. The document + // now contains the div with 1 child, which is span 2. + range.deleteContents(); + document.execCommand("delete", false, null); +} +</script> +<div contenteditable><span id="span1"></span><span id="span2"></span></div>
diff --git a/third_party/blink/web_tests/external/wpt/editing/other/delete-editing-host.html b/third_party/blink/web_tests/external/wpt/editing/other/delete-editing-host.html new file mode 100644 index 0000000..748c409 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/editing/other/delete-editing-host.html
@@ -0,0 +1,29 @@ +<!doctype html> +<meta charset=utf-8> +<title>Deletion of full editing host</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<div contenteditable id="empty"></div> +<div contenteditable id="with-child"><span>Here is a child</span></div> +<script> +const emptyDiv = document.getElementById("empty"); +const withChildDiv = document.getElementById("with-child"); + +test(function() { + document.getSelection().collapse(emptyDiv); + + assert_true(document.execCommand("delete", false, null)); + + assert_true(emptyDiv.isConnected); + assert_equals(emptyDiv.innerHTML, ""); +}, "Should not do anything when deleting full editing host"); + +test(function() { + document.getSelection().collapse(withChildDiv); + + assert_true(document.execCommand("delete", false, null)); + + assert_true(withChildDiv.isConnected); + assert_equals(withChildDiv.innerHTML, "<span>Here is a child</span>"); +}, "Should retain all children when deleting full editing host"); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/metadata/text.https.html b/third_party/blink/web_tests/external/wpt/fetch/metadata/text.https.html index 901e9ee..ba49e2b8 100644 --- a/third_party/blink/web_tests/external/wpt/fetch/metadata/text.https.html +++ b/third_party/blink/web_tests/external/wpt/fetch/metadata/text.https.html
@@ -8,7 +8,7 @@ promise_test(async t => { const key = "text-destination" + token(); - await import("/fetch/metadata/resources/record-header.py?file=" + key); + await import("/fetch/metadata/resources/record-header.py?file=" + key, { with: { type: "text" } }); const expected = {"site": "same-origin", "user": "", "mode": "cors", "dest": "text"}; await validate_expectations(key, expected); }, "The fetch metadata for text module");
diff --git a/third_party/blink/web_tests/external/wpt/fullscreen/api/keyboard-lock-cross-origin-iframe.tentative.sub.html b/third_party/blink/web_tests/external/wpt/fullscreen/api/keyboard-lock-cross-origin-iframe.tentative.sub.html new file mode 100644 index 0000000..0e638bc --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/fullscreen/api/keyboard-lock-cross-origin-iframe.tentative.sub.html
@@ -0,0 +1,123 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <meta name="timeout" content="long"> + <title>Fullscreen keyboardLock option with cross-origin iframe</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="/resources/testdriver.js"></script> + <script src="/resources/testdriver-actions.js"></script> + <script src="/resources/testdriver-vendor.js"></script> + <style> + #outer { + background-color: green; + width: 300px; + height: 300px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + } + </style> +</head> +<body> + <div id="outer"> + <iframe + id="cross-origin-iframe" + src="http://{{hosts[alt][]}}:{{ports[http][0]}}/fullscreen/api/resources/keyboard-lock-inner.sub.html" + allowfullscreen + ></iframe> + </div> + <button id="fullscreen-btn">Enter fullscreen (keyboardLock: none)</button> + <div id="log"></div> + <script> + function waitForFullscreenChange() { + let { promise, resolve } = Promise.withResolvers(); + document.addEventListener("fullscreenchange", resolve, { once: true }); + return promise; + } + + async function request(type) { + const iframe = document.getElementById("cross-origin-iframe"); + let { promise, resolve, reject } = Promise.withResolvers(); + switch(type) { + case "requestFullscreen": { + function onMessage(e) { + if (e.data.action !== "fullscreenResult") { + return; + } + window.removeEventListener("message", onMessage); + e.data.error ? reject(new Error(e.data.error)) : resolve(); + } + window.addEventListener("message", onMessage); + break; + } + case "singlePressEsc": + case "holdPressEsc": { + function onMessage(e) { + if (e.data.action !== "keyDownResult") { + return; + } + window.removeEventListener("message", onMessage); + e.data.error ? reject(new Error(e.data.error)) : resolve(); + } + window.addEventListener("message", onMessage); + break; + } + } + iframe.contentWindow.postMessage({ action: type }, "*"); + await promise; + } + + promise_test(async t => { + t.add_cleanup(() => document.exitFullscreen().catch(() => {})); + + const iframe = document.getElementById("cross-origin-iframe"); + + let enterPromise = waitForFullscreenChange(); + await new Promise(r => t.step_timeout(r, 500)); + await request("requestFullscreen"); + await enterPromise; + assert_equals(document.fullscreenElement, iframe, + "iframe should be the fullscreen element"); + + await request("singlePressEsc"); + assert_equals(document.fullscreenElement, iframe, + "single Escape should not exit fullscreen when keyboardLock is browser"); + + await Promise.all([waitForFullscreenChange(), request("holdPressEsc")]) + assert_equals(document.fullscreenElement, null, + "holding Escape should exit fullscreen when keyboardLock is browser"); + }, "Cross-origin iframe fullscreen with keyboardLock:browser — hold Escape exits"); + + promise_test(async t => { + t.add_cleanup(() => document.exitFullscreen().catch(() => {})); + + const iframe = document.getElementById("cross-origin-iframe"); + + let enterTopPromise = waitForFullscreenChange(); + await test_driver.bless("requestFullscreen with keyboardLock:none", () => + document.getElementById("outer").requestFullscreen({ keyboardLock: "none" }) + ); + await enterTopPromise; + assert_equals(document.fullscreenElement, document.getElementById("outer"), + "outer should be the fullscreen element"); + + await Promise.all([waitForFullscreenChange(), request("requestFullscreen")]); + + assert_equals(document.fullscreenElement, iframe, + "iframe should be the fullscreen element after nested fullscreen request"); + + await request("singlePressEsc"); + + assert_equals(document.fullscreenElement, iframe, + "single Escape should not exit nested keyboardLock:browser fullscreen"); + + await Promise.all([waitForFullscreenChange(), request("holdPressEsc")]); + assert_not_equals(document.fullscreenElement, iframe, + "iframe should no longer be the fullscreen element after holding Escape"); + }, "Nested fullscreen: top-level keyboardLock:none then cross-origin iframe keyboardLock:browser — hold Escape exits iframe fullscreen"); + </script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/fullscreen/api/resources/keyboard-lock-inner.sub.html b/third_party/blink/web_tests/external/wpt/fullscreen/api/resources/keyboard-lock-inner.sub.html new file mode 100644 index 0000000..840124e --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/fullscreen/api/resources/keyboard-lock-inner.sub.html
@@ -0,0 +1,68 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <script src="/resources/testdriver.js"></script> + <script src="/resources/testdriver-actions.js"></script> + <script src="/resources/testdriver-vendor.js"></script> + <script src="../../trusted-click.js"></script> + <style> + #inner { + background-color: red; + width: 200px; + height: 200px; + } + </style> +</head> +<body> + <div id="inner"></div> + <button id="fullscreen-btn">Enter fullscreen (keyboardLock: browser)</button> + <script> + // Keyboard lock + preventDefault() to prevent keys from UA specific behavior. + addEventListener("keydown", ev => ev.preventDefault()); + + async function respondWith(action, cb) { + let error = null; + try { + await cb(); + } catch(err) { + error = err.message; + } finally { + window.top.postMessage({ action, error }, "*"); + } + } + + window.addEventListener("message", async e => { + if (e.data.action === "requestFullscreen") { + await respondWith("fullscreenResult", async () => { + await trusted_click(); + await document.getElementById("inner").requestFullscreen({ keyboardLock: "browser" }); + }) + } else if (e.data.action === "singlePressEsc") { + await respondWith("keyDownResult", async () => { + await new test_driver.Actions() + .keyDown("\uE00C") + .addTick(1) + .keyUp("\uE00C").send(); + // Wait a little before responding. + await new test_driver.Actions().addTick(250).send(); + }) + } else if(e.data.action === "holdPressEsc") { + await respondWith("keyDownResult", async () => { + await new test_driver.Actions() + .keyDown("\uE00C") + .addTick(1000) + .keyDown("\uE00C") + .addTick(1000) + .keyDown("\uE00C") + .addTick(1000) + .keyDown("\uE00C") + .addTick(1000) + .keyDown("\uE00C") + .keyUp("\uE00C").send(); + }); + } + }); + </script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/window-open-popup-during-load-expected.txt b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/window-open-popup-during-load-expected.txt deleted file mode 100644 index fc56a52..0000000 --- a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/window-open-popup-during-load-expected.txt +++ /dev/null
@@ -1,5 +0,0 @@ -This is a testharness.js-based test. -[FAIL] No replace before load, triggered by window.open() on a non-_self window - resolve is not defined -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/window-open-popup-during-load.html b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/window-open-popup-during-load.html index 5308c01c..5d44de8 100644 --- a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/window-open-popup-during-load.html +++ b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/window-open-popup-during-load.html
@@ -41,7 +41,7 @@ assert_equals(w.onloadFired, undefined, "onload must not yet have fired"); assert_equals(w.history.length, 1, "history.length for the opened window must start at 1"); - await new Promise(r => { + await new Promise(resolve => { window.addEventListener("message", t.step_func(e => { if (e.data === "ready") { resolve();
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/window-open-popup-during-pageshow-expected.txt b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/window-open-popup-during-pageshow-expected.txt deleted file mode 100644 index fc56a52..0000000 --- a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/window-open-popup-during-pageshow-expected.txt +++ /dev/null
@@ -1,5 +0,0 @@ -This is a testharness.js-based test. -[FAIL] No replace before load, triggered by window.open() on a non-_self window - resolve is not defined -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/window-open-popup-during-pageshow.html b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/window-open-popup-during-pageshow.html index 065d933..dc9f883 100644 --- a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/window-open-popup-during-pageshow.html +++ b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/window-open-popup-during-pageshow.html
@@ -41,7 +41,7 @@ assert_equals(w.onloadFired, undefined, "onload must not yet have fired"); assert_equals(w.history.length, 1, "history.length for the opened window must start at 1"); - await new Promise(r => { + await new Promise(resolve => { window.addEventListener("message", t.step_func(e => { if (e.data === "ready") { resolve();
diff --git a/third_party/blink/web_tests/external/wpt/html/editing/dnd/crashtests/DataTransfer-getData-RefCell-already-borrowed.html b/third_party/blink/web_tests/external/wpt/html/editing/dnd/crashtests/DataTransfer-getData-RefCell-already-borrowed.html new file mode 100644 index 0000000..1bfdce4 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/editing/dnd/crashtests/DataTransfer-getData-RefCell-already-borrowed.html
@@ -0,0 +1,3 @@ +<!DOCTYPE html> +<link rel="help" href="https://github.com/servo/servo/issues/44599"> +<script>(new DataTransfer()).getData("");</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/editing/dnd/platform/mousedown-drag-select-input-display-change.html b/third_party/blink/web_tests/external/wpt/html/editing/dnd/platform/mousedown-drag-select-input-display-change.html index fe411b65..eba3e9d5 100644 --- a/third_party/blink/web_tests/external/wpt/html/editing/dnd/platform/mousedown-drag-select-input-display-change.html +++ b/third_party/blink/web_tests/external/wpt/html/editing/dnd/platform/mousedown-drag-select-input-display-change.html
@@ -18,9 +18,11 @@ appearance: none; border: none; padding: 0; + width: 250px; + font-size: 16px; } </style> -<input value="XXXXXXXXXXXXXXXXXXXXX" onfocus="this.style.display = 'inline'" onblur="this.style.display = ''"> +<input value="XXXXXXXXXXXXXXXXXXXXX" onmousedown="this.style.display = 'inline'" onmouseup="this.style.display = ''"> <script> promise_test(async function (t) { const input = document.querySelector("input"); @@ -30,16 +32,58 @@ const centerY = Math.round(rect.height / 2); await new test_driver.Actions() + .pointerMove(32, centerY) + .pointerDown() + .pointerMove(endX - 10, centerY) + .pointerMove(endX - 2, centerY) + .pointerUp() + .send(); + + assert_equals(document.activeElement, input, "<input> should be focused"); + assert_not_equals(input.selectionStart, 0, "selection shouldn't be started from the start"); + assert_not_equals(input.selectionStart, input.selectionEnd, + "some text should be selected after dragging"); + }, "text selection drag should still work when mousedown a display change"); + + promise_test(async function (t) { + const input = document.querySelector("input"); + + const rect = input.getBoundingClientRect(); + const endX = Math.floor(rect.width); + const centerY = Math.round(rect.height / 2); + + await new test_driver.Actions() .pointerMove(2, centerY) .pointerDown() - .pointerMove(endX - 10, centerY) - .pointerMove(endX - 2, centerY) .pointerUp() .send(); - assert_equals(input.style.display, "inline", "display should be inline"); assert_equals(document.activeElement, input, "<input> should be focused"); - assert_not_equals(input.selectionStart, input.selectionEnd, - "some text should be selected after dragging"); - }, "text selection drag should still work when mousedown a display change"); + assert_equals(input.selectionStart, input.selectionEnd, + "the selection should be collapsed by the click"); + }, "text click after selecting some characters should collapse selection to start"); + + promise_test(async function (t) { + const input = document.querySelector("input"); + + const rect = input.getBoundingClientRect(); + const endX = Math.floor(rect.width); + const centerY = Math.round(rect.height / 2); + + await new test_driver.Actions() + .pointerMove(32, centerY) + .pointerDown() + .pointerMove(endX - 10, centerY) + .pointerMove(endX - 2, centerY) + .pointerUp() + .pointerMove(18, centerY) + .pointerDown() + .pointerUp() + .send(); + + assert_equals(document.activeElement, input, "<input> should be focused"); + assert_not_equals(input.selectionStart, 0, "selection shouldn't be started from the start"); + assert_equals(input.selectionStart, input.selectionEnd, + "the selection should be collapsed by the click"); + }, "text click after selecting some characters should collapse selection to middle of the value"); </script>
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/attributes-for-embedded-content-and-images/input-text-indent-ref.html b/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/attributes-for-embedded-content-and-images/input-text-indent-ref.html index b4dc8a8..8b4f2d9 100644 --- a/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/attributes-for-embedded-content-and-images/input-text-indent-ref.html +++ b/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/attributes-for-embedded-content-and-images/input-text-indent-ref.html
@@ -1,8 +1,10 @@ <!doctype html> <meta charset="utf-8"> <title>CSS Test Reference</title> +<link rel="stylesheet" href="/fonts/ahem.css"> <style> input { + font: 15px / 1 Ahem; box-sizing: border-box; width: 150px; border: 1px solid;
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/attributes-for-embedded-content-and-images/input-text-indent.html b/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/attributes-for-embedded-content-and-images/input-text-indent.html index ab301a2..65011f9 100644 --- a/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/attributes-for-embedded-content-and-images/input-text-indent.html +++ b/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/attributes-for-embedded-content-and-images/input-text-indent.html
@@ -5,8 +5,10 @@ <link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez"> <link rel="author" href="https://mozilla.com" title="Mozilla"> <link rel="match" href="input-text-indent-ref.html"> +<link rel="stylesheet" href="/fonts/ahem.css"> <style> input { + font: 15px / 1 Ahem; box-sizing: border-box; width: 150px; border: 1px solid;
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/media-elements/user-interface/muted-expected.txt b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/media-elements/user-interface/muted-expected.txt new file mode 100644 index 0000000..b3e85f3 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/media-elements/user-interface/muted-expected.txt
@@ -0,0 +1,15 @@ +This is a testharness.js-based test. +[FAIL] getting audio.muted with muted="" (script-created) + assert_true: expected true got false +[FAIL] setting audio.muted with muted="" (script-created) + assert_equals: expected true but got false +[FAIL] adding/removing muted attribute dynamically affects audio.muted + assert_true: expected true got false +[FAIL] getting video.muted with muted="" (script-created) + assert_true: expected true got false +[FAIL] setting video.muted with muted="" (script-created) + assert_equals: expected true but got false +[FAIL] adding/removing muted attribute dynamically affects video.muted + assert_true: expected true got false +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/media-elements/user-interface/muted.html b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/media-elements/user-interface/muted.html index eb6d2ac6..0bdc42575 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/media-elements/user-interface/muted.html +++ b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/media-elements/user-interface/muted.html
@@ -21,8 +21,8 @@ } </script> -<!-- These tests are inside <audio>/<video> so that the steps for updating the - muted IDL attribute cannot be delayed until the end tag is parsed. --> +<!-- These tests are inside <audio>/<video> so that the parser-created + elements are available for testing before the closing tag. --> <audio id=a1> <script> @@ -80,8 +80,8 @@ </script> </video> -<!-- Negative test to ensure that the load algorithm does not update the - muted IDL attribute to match the content attribute. --> +<!-- Negative test to ensure that the load algorithm does not reset the + muted state. --> <video id=v3 muted></video> <script> @@ -112,25 +112,22 @@ test(function() { var m = document.createElement(tagName); m.setAttribute('muted', ''); - assert_false(m.muted); + assert_true(m.muted); }, 'getting ' + tagName + '.muted with muted="" (script-created)'); test(function() { var m = document.createElement(tagName); m.setAttribute('muted', ''); - test_setting(m, false, true); + test_setting(m, true, true); }, 'setting ' + tagName + '.muted with muted="" (script-created)'); - // Spec bug: https://www.w3.org/Bugs/Public/show_bug.cgi?id=25153 - /* test(function() { var m = document.createElement(tagName); m.setAttribute('muted', ''); m = m.cloneNode(false); assert_true(m.hasAttribute('muted')); - assert_false(m.muted); + assert_true(m.muted); }, 'getting ' + tagName + '.muted with muted="" (cloneNode-created)'); - */ test(function() { var div = document.createElement('div'); @@ -165,5 +162,29 @@ var c = m.cloneNode(true); assert_true(c.muted); }, 'cloning ' + tagName + ' propagates muted (innerHTML-created)'); + + test(function() { + var m = document.createElement(tagName); + assert_false(m.muted); + m.setAttribute('muted', ''); + assert_true(m.muted); + m.removeAttribute('muted'); + assert_false(m.muted); + }, 'adding/removing muted attribute dynamically affects ' + tagName + '.muted'); + + test(function() { + var m = document.createElement(tagName); + m.muted = false; + m.setAttribute('muted', ''); + assert_false(m.muted); + }, 'adding muted attribute has no effect on ' + tagName + '.muted after setter'); + + test(function() { + var m = document.createElement(tagName); + m.setAttribute('muted', ''); + m.muted = true; + m.removeAttribute('muted'); + assert_true(m.muted); + }, 'removing muted attribute has no effect on ' + tagName + '.muted after setter'); }); </script>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/sizes/sizes-auto-resize-observer-removes-auto.html b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/sizes/sizes-auto-resize-observer-removes-auto.html new file mode 100644 index 0000000..522b18ec --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/sizes/sizes-auto-resize-observer-removes-auto.html
@@ -0,0 +1,46 @@ +<!doctype html> +<meta charset="utf-8"> +<title>ResizeObserver causes image to no longer allow lazy loading</title> +<link rel="help" href="https://html.spec.whatwg.org/multipage/images.html#parse-a-sizes-attribute"> +<link rel="help" href="https://html.spec.whatwg.org/multipage/embedded-content.html#allows-auto-sizes"> +<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=2033652"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<img id="img" sizes="1px" style="width:16px;" loading="lazy"> +<script> +"use strict"; +/* +A browser might use resize observer to respond to size changes for sizes=auto images. +If a resize observer from a page is notified before the browser one, and makes the +image not allow auto-sizes anymore, the browser resize observer would +still be notified for the now not sizes=auto image. +*/ +promise_test(async t => { + let waitForLoad = new Promise(r => img.addEventListener('load', r, {once: true})); + img.srcset = "/images/green-1x1.png 1w, /images/green-16x16.png 16w, /images/green-256x256.png 256w"; + await waitForLoad; + let resizeObserved = false; + let observer = new ResizeObserver(() => { + if (img.style.width === "1px") { + img.sizes = "256px"; + resizeObserved = true; + observer.disconnect(); + } + }); + observer.observe(img); + let currentSrc = () => new URL(img.currentSrc).pathname; + assert_equals(currentSrc(), "/images/green-1x1.png", + "image's source should be set based on sizes=1px"); + waitForLoad = new Promise(r => img.addEventListener('load', r, {once: true})); + img.sizes = "auto"; + await waitForLoad; + assert_equals(currentSrc(), "/images/green-16x16.png", + "image's source should be set based on sizes=auto and content box width of 16px"); + waitForLoad = new Promise(r => img.addEventListener('load', r, {once: true})); + img.style.width = "1px"; + await waitForLoad; + assert_true(resizeObserved, "ResizeObserver should have been notified of resize"); + assert_equals(currentSrc(), "/images/green-256x256.png", + "image's source should be set based on sizes=256px from ResizeObserver"); +}); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/sizes/support/sizes-iframed.sub.html b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/sizes/support/sizes-iframed.sub.html index 8ad6567..4aa353dc 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/sizes/support/sizes-iframed.sub.html +++ b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/sizes/support/sizes-iframed.sub.html
@@ -54,9 +54,13 @@ <img srcset='/images/green-1x1.png?e36 50w, /images/green-16x16.png?e36 51w' sizes='calc(1px)'> <img srcset='/images/green-1x1.png?e36a 50w, /images/green-16x16.png?e36a 51w' sizes='min(1px, 100px)'> <img srcset='/images/green-1x1.png?e36b 50w, /images/green-16x16.png?e36b 51w' sizes='min(-100px, 1px)'> +<img srcset='/images/green-1x1.png?e36c 50w, /images/green-16x16.png?e36c 51w' sizes='clamp(1px, -50px, 100px)'> +<img srcset='/images/green-1x1.png?e36d 50w, /images/green-16x16.png?e36d 51w' sizes='clamp(-100px, 1px, 100px)'> <img srcset='/images/green-1x1.png?e37 50w, /images/green-16x16.png?e37 51w' sizes='(min-width:0) calc(1px)'> <img srcset='/images/green-1x1.png?e37a 50w, /images/green-16x16.png?e37a 51w' sizes='(min-width:0) min(1px, 100px)'> <img srcset='/images/green-1x1.png?e37b 50w, /images/green-16x16.png?e37b 51w' sizes='(min-width:0) max(-100px, 1px)'> +<img srcset='/images/green-1x1.png?e37c 50w, /images/green-16x16.png?e37c 51w' sizes='(min-width:0) clamp(1px, -50px, 100px)'> +<img srcset='/images/green-1x1.png?e37d 50w, /images/green-16x16.png?e37d 51w' sizes='(min-width:0) clamp(-100px, 1px, 100px)'> <img srcset='/images/green-1x1.png?e38 50w, /images/green-16x16.png?e38 51w' sizes='(min-width:calc(0)) 1px'> <img srcset='/images/green-1x1.png?e39 50w, /images/green-16x16.png?e39 51w' sizes='(min-width:0) 1px, 100vw'> <img srcset='/images/green-1x1.png?e40 50w, /images/green-16x16.png?e40 51w' sizes='(min-width:0) 1px, (min-width:0) 100vw, 100vw'> @@ -132,9 +136,13 @@ <img srcset='/images/green-1x1.png?f48 50w, /images/green-16x16.png?f48 51w' sizes='calc(1px'> <img srcset='/images/green-1x1.png?f48a 50w, /images/green-16x16.png?f48a 51w' sizes='min(1px, 200vw'> <img srcset='/images/green-1x1.png?f48b 50w, /images/green-16x16.png?f48b 51w' sizes='max(-200vw, 1px'> +<img srcset='/images/green-1x1.png?f48c 50w, /images/green-16x16.png?f48c 51w' sizes='clamp(1px, -50px, 200vw'> +<img srcset='/images/green-1x1.png?f48d 50w, /images/green-16x16.png?f48d 51w' sizes='clamp(-200vw, 1px, 100px'> <img srcset='/images/green-1x1.png?f49 50w, /images/green-16x16.png?f49 51w' sizes='(min-width:0) calc(1px'> <img srcset='/images/green-1x1.png?f49a 50w, /images/green-16x16.png?f49a 51w' sizes='(min-width:0) min(1px, 200vw'> <img srcset='/images/green-1x1.png?f49b 50w, /images/green-16x16.png?f49b 51w' sizes='(min-width:0) max(-200vw, 1px'> +<img srcset='/images/green-1x1.png?f49c 50w, /images/green-16x16.png?f49c 51w' sizes='(min-width:0) clamp(1px, -50px, 200vw'> +<img srcset='/images/green-1x1.png?f49d 50w, /images/green-16x16.png?f49d 51w' sizes='(min-width:0) clamp(-200vw, 1px, 100px'> <p> <img srcset='/images/green-1x1.png?f1 50w, /images/green-16x16.png?f1 51w' sizes='100vw'>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/forms/form-control-infrastructure/form_attribute.html b/third_party/blink/web_tests/external/wpt/html/semantics/forms/form-control-infrastructure/form_attribute.html index dde3250d..4508a667 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/forms/form-control-infrastructure/form_attribute.html +++ b/third_party/blink/web_tests/external/wpt/html/semantics/forms/form-control-infrastructure/form_attribute.html
@@ -229,5 +229,19 @@ }); </script> + + <form id="form3"> + </form> + <input id="form3" form="form3">Same ID as form</input> + + <script> + test(function() { + var form3 = document.getElementById("form3"); + var button = form3.nextElementSibling; + + assert_equals(button.form, form3, + "button should be associated with form3 even though it has the same ID"); + }, "Test for button with same ID as form"); + </script> </body> </html>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/resources/cross-origin.py b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/resources/cross-origin.py index abac190..bd2a9b80 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/resources/cross-origin.py +++ b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/resources/cross-origin.py
@@ -14,7 +14,7 @@ if milk is None: return headers, u"var included = false;" - elif milk.value == b"yes": + elif milk.value == b"1": return headers, u"var included = true;" return headers, u"var included = false;"
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/script-crossorigin-network.sub.html b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/script-crossorigin-network.sub.html index 5886ab6f..70a05858 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/script-crossorigin-network.sub.html +++ b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/script-crossorigin-network.sub.html
@@ -51,7 +51,7 @@ script8.src = cross; script8.crossOrigin = "uſe-credentialſ"; - document.cookie = "milk=yes"; + document.cookie = "milk=1"; document.body.appendChild(script1); script1.onload = function() {
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/text-module/ignore-content-type.any-expected.txt b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/text-module/ignore-content-type.any-expected.txt index c97a7246..dbb18d9 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/text-module/ignore-content-type.any-expected.txt +++ b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/text-module/ignore-content-type.any-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 111 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 106 FAIL, 0 TIMEOUT, 0 NOTRUN. [FAIL] Import of a text module with MIME type should succeed promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." [FAIL] Import of a text module with MIME type text should succeed @@ -46,8 +46,6 @@ promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." [FAIL] Import of a text module with MIME type text/json/json should succeed promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." -[FAIL] Import of a text module with MIME type applic\0ation/vnd.api+json should succeed - promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." [FAIL] Import of a text module with MIME type applic ation/vnd.api+json should succeed promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." [FAIL] Import of a text module with MIME type applic\nation/vnd.api+json should succeed @@ -62,8 +60,6 @@ promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." [FAIL] Import of a text module with MIME type application/vnd.api+json should succeed promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." -[FAIL] Import of a text module with MIME type application/vnd\0.api+json should succeed - promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." [FAIL] Import of a text module with MIME type application/vnd .api+json should succeed promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." [FAIL] Import of a text module with MIME type application/vnd\n.api+json should succeed @@ -180,8 +176,6 @@ promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." [FAIL] Import of a text module with MIME type app™/vnd€.api+json should succeed promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." -[FAIL] Import of a text module with MIME type applic\0ation/vnd\0api+json should succeed - promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." [FAIL] Import of a text module with MIME type applic;ation/vnd;api+json should succeed promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." [FAIL] Import of a text module with MIME type applic{ation/vnd{api+json should succeed @@ -204,8 +198,6 @@ promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." [FAIL] Import of a text module with MIME type /vnd.api+json should succeed promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." -[FAIL] Import of a text module with MIME type app\0lication/vnd.api+json should succeed - promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." [FAIL] Import of a text module with MIME type application/"vnd.api+json should succeed promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." [FAIL] Import of a text module with MIME type application/vnd.api"+json should succeed @@ -220,7 +212,5 @@ promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." [FAIL] Import of a text module with MIME type app(lic)ation/vnd(api)+json should succeed promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." -[FAIL] Import of a text module with MIME type application\0/\0vnd.api+json should succeed - promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/text-module/ignore-content-type.any.js b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/text-module/ignore-content-type.any.js index 2b71b53..e2f5cf1 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/text-module/ignore-content-type.any.js +++ b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/text-module/ignore-content-type.any.js
@@ -27,7 +27,6 @@ "text/json/json", // Control Characters and Whitespace - Invalid Type - "applic\x00ation/vnd.api+json", // NULL in type "applic\x09ation/vnd.api+json", // TAB in type "applic\x0Aation/vnd.api+json", // Line Feed in type "applic\x0Dation/vnd.api+json", // Carriage Return in type @@ -37,7 +36,6 @@ "application\x1F/vnd.api+json", // Unit Separator at end of type // Control Characters and Whitespace - Invalid Subtype - "application/vnd\x00.api+json", // NULL in subtype "application/vnd\x09.api+json", // TAB in subtype "application/vnd\x0A.api+json", // Line Feed in subtype "application/vnd\x0D.api+json", // Carriage Return in subtype @@ -106,7 +104,6 @@ "applic=ation/vnd=api+json", // Equals in both "申请/䏿–‡.api+json", // Chinese in both "app™/vnd€.api+json", // Unicode symbols in both - "applic\x00ation/vnd\x00api+json", // NULL in both "applic;ation/vnd;api+json", // Semicolons in both "applic{ation/vnd{api+json", // Left curly brace in both "applic}ation/vnd}api+json", // Right curly brace in both @@ -120,7 +117,6 @@ "application\"/vnd.api+json", // Quote at end of type "application /vnd.api+json", // Trailing space in type "/vnd.api+json", // Empty type - "app\x00lication/vnd.api+json", // NULL in middle of type // Edge Cases - Subtype "application/\"vnd.api+json", // Quote at start of subtype @@ -132,11 +128,11 @@ // Edge Cases - Multiple Invalid Positions "\"application\"/\"vnd.api\"+json", // Quotes in multiple positions "app(lic)ation/vnd(api)+json", // Parentheses in multiple positions - "application\x00/\x00vnd.api+json", // NULL in both parts ]; for (const content_type of content_types) { promise_test(async test => { - await import(`./file.txt?pipe=header(Content-Type,${encodeURIComponent(content_type)})`, { with: { type: "text" } }); + const enc_content_type = encodeURIComponent(content_type.replaceAll(',', '\\,').replaceAll(')', '\\)')); + await import(`./file.txt?pipe=header(Content-Type,${enc_content_type})`, { with: { type: "text" } }); }, `Import of a text module with MIME type ${content_type} should succeed`); }
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/text-module/ignore-content-type.any.sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/text-module/ignore-content-type.any.sharedworker-expected.txt index c97a7246..dbb18d9 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/text-module/ignore-content-type.any.sharedworker-expected.txt +++ b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/text-module/ignore-content-type.any.sharedworker-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 111 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 106 FAIL, 0 TIMEOUT, 0 NOTRUN. [FAIL] Import of a text module with MIME type should succeed promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." [FAIL] Import of a text module with MIME type text should succeed @@ -46,8 +46,6 @@ promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." [FAIL] Import of a text module with MIME type text/json/json should succeed promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." -[FAIL] Import of a text module with MIME type applic\0ation/vnd.api+json should succeed - promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." [FAIL] Import of a text module with MIME type applic ation/vnd.api+json should succeed promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." [FAIL] Import of a text module with MIME type applic\nation/vnd.api+json should succeed @@ -62,8 +60,6 @@ promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." [FAIL] Import of a text module with MIME type application/vnd.api+json should succeed promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." -[FAIL] Import of a text module with MIME type application/vnd\0.api+json should succeed - promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." [FAIL] Import of a text module with MIME type application/vnd .api+json should succeed promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." [FAIL] Import of a text module with MIME type application/vnd\n.api+json should succeed @@ -180,8 +176,6 @@ promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." [FAIL] Import of a text module with MIME type app™/vnd€.api+json should succeed promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." -[FAIL] Import of a text module with MIME type applic\0ation/vnd\0api+json should succeed - promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." [FAIL] Import of a text module with MIME type applic;ation/vnd;api+json should succeed promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." [FAIL] Import of a text module with MIME type applic{ation/vnd{api+json should succeed @@ -204,8 +198,6 @@ promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." [FAIL] Import of a text module with MIME type /vnd.api+json should succeed promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." -[FAIL] Import of a text module with MIME type app\0lication/vnd.api+json should succeed - promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." [FAIL] Import of a text module with MIME type application/"vnd.api+json should succeed promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." [FAIL] Import of a text module with MIME type application/vnd.api"+json should succeed @@ -220,7 +212,5 @@ promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." [FAIL] Import of a text module with MIME type app(lic)ation/vnd(api)+json should succeed promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." -[FAIL] Import of a text module with MIME type application\0/\0vnd.api+json should succeed - promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/text-module/ignore-content-type.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/text-module/ignore-content-type.any.worker-expected.txt index c97a7246..dbb18d9 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/text-module/ignore-content-type.any.worker-expected.txt +++ b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/text-module/ignore-content-type.any.worker-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 111 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 106 FAIL, 0 TIMEOUT, 0 NOTRUN. [FAIL] Import of a text module with MIME type should succeed promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." [FAIL] Import of a text module with MIME type text should succeed @@ -46,8 +46,6 @@ promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." [FAIL] Import of a text module with MIME type text/json/json should succeed promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." -[FAIL] Import of a text module with MIME type applic\0ation/vnd.api+json should succeed - promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." [FAIL] Import of a text module with MIME type applic ation/vnd.api+json should succeed promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." [FAIL] Import of a text module with MIME type applic\nation/vnd.api+json should succeed @@ -62,8 +60,6 @@ promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." [FAIL] Import of a text module with MIME type application/vnd.api+json should succeed promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." -[FAIL] Import of a text module with MIME type application/vnd\0.api+json should succeed - promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." [FAIL] Import of a text module with MIME type application/vnd .api+json should succeed promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." [FAIL] Import of a text module with MIME type application/vnd\n.api+json should succeed @@ -180,8 +176,6 @@ promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." [FAIL] Import of a text module with MIME type app™/vnd€.api+json should succeed promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." -[FAIL] Import of a text module with MIME type applic\0ation/vnd\0api+json should succeed - promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." [FAIL] Import of a text module with MIME type applic;ation/vnd;api+json should succeed promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." [FAIL] Import of a text module with MIME type applic{ation/vnd{api+json should succeed @@ -204,8 +198,6 @@ promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." [FAIL] Import of a text module with MIME type /vnd.api+json should succeed promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." -[FAIL] Import of a text module with MIME type app\0lication/vnd.api+json should succeed - promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." [FAIL] Import of a text module with MIME type application/"vnd.api+json should succeed promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." [FAIL] Import of a text module with MIME type application/vnd.api"+json should succeed @@ -220,7 +212,5 @@ promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." [FAIL] Import of a text module with MIME type app(lic)ation/vnd(api)+json should succeed promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." -[FAIL] Import of a text module with MIME type application\0/\0vnd.api+json should succeed - promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/text-module/ignore-extension.any.js b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/text-module/ignore-extension.any.js index a1d6cd31f..350b489 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/text-module/ignore-extension.any.js +++ b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/text-module/ignore-extension.any.js
@@ -3,6 +3,6 @@ for (const name of ["file", "file.js", "file.json", "file.txt"]) { promise_test(async t => { const result = await import(`./${name}`, { with: { type: "text" } }); - assert_equals(result, "text file\n"); + assert_equals(result.default, "text file\n"); }, `Extension: ${name}`); }
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/text-module/integrity-expected.txt b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/text-module/integrity-expected.txt index 48b101b..a795128f6 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/text-module/integrity-expected.txt +++ b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/text-module/integrity-expected.txt
@@ -1,5 +1,4 @@ This is a testharness.js-based test. -[FAIL] The integrity attribute must be verified on the top-level of a module loading a text module and allow it to execute when it matches - assert_array_equals: The module and its dependency must have executed lengths differ, expected array ["integrity-matches,text:text file\\n"] length 1, got [] length 0 +Harness Error. harness_status.status = 1 , harness_status.message = Uncaught TypeError: "text" is not a valid module type. Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/text-module/integrity.html b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/text-module/integrity.html index bda5d69..1c1060c 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/text-module/integrity.html +++ b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/text-module/integrity.html
@@ -12,7 +12,7 @@ window.mismatchesLog = []; window.mismatchesEvents = []; </script> -<script type="module" src="integrity-matches.js" integrity="sha384-kc1K2KFKQhnYE1AdnpmUUpFVnxz1GCgGbQ19e3zmXrZw23rgpwa9il4/pHp7NYWA" onload="window.matchesEvents.push('load');" onerror="window.matchesEvents.push('error')"></script> +<script type="module" src="integrity-matches.js" integrity="sha384-pjL0xfAOZ4ZBiE7HXzxD1TkqVgNikOnFFZY3SC2Z4jWAyaP76YUa5VrRInWayN7m" onload="window.matchesEvents.push('load');" onerror="window.matchesEvents.push('error')"></script> <script type="module" src="integrity-mismatches.js" integrity="sha384-doesnotmatch" onload="window.mismatchesEvents.push('load');" onerror="window.mismatchesEvents.push('error')"></script> <script type="module">
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/text-module/repeated-imports.any-expected.txt b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/text-module/repeated-imports.any-expected.txt index 7703bf8..331d923 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/text-module/repeated-imports.any-expected.txt +++ b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/text-module/repeated-imports.any-expected.txt
@@ -9,7 +9,5 @@ promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." [FAIL] Two modules of different type with the same specifier can load if the server changes its responses (first JS, then text) promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." -[FAIL] If an import previously succeeded for a given specifier with no type attribute, future uses of the same values should yield the same result - assert_equals: expected "hello" but got "world" Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/text-module/repeated-imports.any.js b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/text-module/repeated-imports.any.js index 2ebc346..5470231 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/text-module/repeated-imports.any.js +++ b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/text-module/repeated-imports.any.js
@@ -79,12 +79,12 @@ const uuid_token = token(); // serve-js-then-text.py gives us JS the first time const result_js = await import(`./serve-js-then-text.py?key=${uuid_token}`); - assert_equals(result_js.default, "hello"); + assert_equals(result_js.default, "world"); // If this were to do another fetch, the import would fail because // serve-js-then-text.py would give us text this time. But, the module map // entry for this specifier/module type pair already exists, so we // successfully reuse the entry instead of fetching again. const result_js_2 = await import(`./serve-js-then-text.py?key=${uuid_token}`); - assert_equals(result_js_2.default, "hello"); + assert_equals(result_js_2.default, "world"); }, "If an import previously succeeded for a given specifier with no type attribute, future uses of the same values should yield the same result");
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/text-module/repeated-imports.any.sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/text-module/repeated-imports.any.sharedworker-expected.txt index 7703bf8..331d923 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/text-module/repeated-imports.any.sharedworker-expected.txt +++ b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/text-module/repeated-imports.any.sharedworker-expected.txt
@@ -9,7 +9,5 @@ promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." [FAIL] Two modules of different type with the same specifier can load if the server changes its responses (first JS, then text) promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." -[FAIL] If an import previously succeeded for a given specifier with no type attribute, future uses of the same values should yield the same result - assert_equals: expected "hello" but got "world" Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/text-module/repeated-imports.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/text-module/repeated-imports.any.worker-expected.txt index 7703bf8..331d923 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/text-module/repeated-imports.any.worker-expected.txt +++ b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/text-module/repeated-imports.any.worker-expected.txt
@@ -9,7 +9,5 @@ promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." [FAIL] Two modules of different type with the same specifier can load if the server changes its responses (first JS, then text) promise_test: Unhandled rejection with value: object "TypeError: "text" is not a valid module type." -[FAIL] If an import previously succeeded for a given specifier with no type attribute, future uses of the same values should yield the same result - assert_equals: expected "hello" but got "world" Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/html/syntax/charset/README.md b/third_party/blink/web_tests/external/wpt/html/syntax/charset/README.md index eaa70850..33a78e6 100644 --- a/third_party/blink/web_tests/external/wpt/html/syntax/charset/README.md +++ b/third_party/blink/web_tests/external/wpt/html/syntax/charset/README.md
@@ -3,4 +3,4 @@ other hand https://github.com/whatwg/html/issues/6962 have in common. The cases where the two approaches differ are in -https://searchfox.org/mozilla-central/source/testing/web-platform/mozilla/tests/html/syntax/charset +https://searchfox.org/firefox-main/source/testing/web-platform/mozilla/tests/html/syntax/charset
diff --git a/third_party/blink/web_tests/external/wpt/jpegxl/hdr-alpha-reftest-ref.html b/third_party/blink/web_tests/external/wpt/jpegxl/hdr-alpha-reftest-ref.html new file mode 100644 index 0000000..26e0d3da --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/jpegxl/hdr-alpha-reftest-ref.html
@@ -0,0 +1,4 @@ +<!DOCTYPE html> +<link rel="stylesheet" href="resources/jpegxl-reftest.css"> + +<img src="resources/hdr_alpha.png">
diff --git a/third_party/blink/web_tests/external/wpt/jpegxl/hdr-alpha-reftest.html b/third_party/blink/web_tests/external/wpt/jpegxl/hdr-alpha-reftest.html new file mode 100644 index 0000000..90c50ec --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/jpegxl/hdr-alpha-reftest.html
@@ -0,0 +1,7 @@ +<!DOCTYPE html> +<link rel="help" href="https://github.com/web-platform-tests/interop-jpegxl"> +<link rel="match" href="hdr-alpha-reftest-ref.html"> +<meta name="assert" content="64x64 HDR JPEG XL with alpha channel decode should match PNG reference output."> +<link rel="stylesheet" href="resources/jpegxl-reftest.css"> + +<img src="resources/hdr_alpha.jxl">
diff --git a/third_party/blink/web_tests/external/wpt/jpegxl/resources/hdr_alpha.jxl b/third_party/blink/web_tests/external/wpt/jpegxl/resources/hdr_alpha.jxl new file mode 100644 index 0000000..6822686 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/jpegxl/resources/hdr_alpha.jxl Binary files differ
diff --git a/third_party/blink/web_tests/external/wpt/jpegxl/resources/hdr_alpha.png b/third_party/blink/web_tests/external/wpt/jpegxl/resources/hdr_alpha.png new file mode 100644 index 0000000..320c0f48 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/jpegxl/resources/hdr_alpha.png Binary files differ
diff --git a/third_party/blink/web_tests/external/wpt/jpegxl/resources/sdr_alpha.jxl b/third_party/blink/web_tests/external/wpt/jpegxl/resources/sdr_alpha.jxl new file mode 100644 index 0000000..9982d729 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/jpegxl/resources/sdr_alpha.jxl Binary files differ
diff --git a/third_party/blink/web_tests/external/wpt/jpegxl/resources/sdr_alpha.png b/third_party/blink/web_tests/external/wpt/jpegxl/resources/sdr_alpha.png new file mode 100644 index 0000000..37c22d6 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/jpegxl/resources/sdr_alpha.png Binary files differ
diff --git a/third_party/blink/web_tests/external/wpt/jpegxl/sdr-alpha-reftest-ref.html b/third_party/blink/web_tests/external/wpt/jpegxl/sdr-alpha-reftest-ref.html new file mode 100644 index 0000000..2b22c7a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/jpegxl/sdr-alpha-reftest-ref.html
@@ -0,0 +1,4 @@ +<!DOCTYPE html> +<link rel="stylesheet" href="resources/jpegxl-reftest.css"> + +<img src="resources/sdr_alpha.png">
diff --git a/third_party/blink/web_tests/external/wpt/jpegxl/sdr-alpha-reftest.html b/third_party/blink/web_tests/external/wpt/jpegxl/sdr-alpha-reftest.html new file mode 100644 index 0000000..5e7dc266 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/jpegxl/sdr-alpha-reftest.html
@@ -0,0 +1,7 @@ +<!DOCTYPE html> +<link rel="help" href="https://github.com/web-platform-tests/interop-jpegxl"> +<link rel="match" href="sdr-alpha-reftest-ref.html"> +<meta name="assert" content="64x64 sRGB JPEG XL with alpha channel decode should match PNG reference output."> +<link rel="stylesheet" href="resources/jpegxl-reftest.css"> + +<img src="resources/sdr_alpha.jxl">
diff --git a/third_party/blink/web_tests/external/wpt/lint.ignore b/third_party/blink/web_tests/external/wpt/lint.ignore index 408729b..7b21a36c 100644 --- a/third_party/blink/web_tests/external/wpt/lint.ignore +++ b/third_party/blink/web_tests/external/wpt/lint.ignore
@@ -52,6 +52,7 @@ TRAILING WHITESPACE, INDENT TABS, CR AT EOL: *.avif TRAILING WHITESPACE, INDENT TABS, CR AT EOL: *.annexb TRAILING WHITESPACE, INDENT TABS, CR AT EOL: *.crx +TRAILING WHITESPACE, INDENT TABS, CR AT EOL: *.tlb ## .gitignore W3C-TEST.ORG: .gitignore
diff --git a/third_party/blink/web_tests/external/wpt/mathml/relations/html5-tree/href-click-004.tentative.html b/third_party/blink/web_tests/external/wpt/mathml/relations/html5-tree/href-click-004.tentative.html index 764222d..accadb8 100644 --- a/third_party/blink/web_tests/external/wpt/mathml/relations/html5-tree/href-click-004.tentative.html +++ b/third_party/blink/web_tests/external/wpt/mathml/relations/html5-tree/href-click-004.tentative.html
@@ -13,7 +13,7 @@ <style> annotation, annotation-xml { display: initial; } mphantom { visibility: visible; } - .element { background: lightblue; padding: 50px; } + .element, mtr.element > mtd { background: lightblue; padding: 50px; } </style> </head> <body>
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/focus-reset/autofocus.html b/third_party/blink/web_tests/external/wpt/navigation-api/focus-reset/autofocus.html index c40e2f6..b013dcd 100644 --- a/third_party/blink/web_tests/external/wpt/navigation-api/focus-reset/autofocus.html +++ b/third_party/blink/web_tests/external/wpt/navigation-api/focus-reset/autofocus.html
@@ -1,10 +1,25 @@ <!doctype html> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> +<meta name="variant" content="?delayed-checkpoint"> +<meta name="variant" content="?same-checkpoint"> <button autofocus id="initialAutofocusTarget">Initial autofocus target</button> <script type="module"> + +const delayed = location.search === "?delayed-checkpoint"; + +function createExpected(t, decoy, autofocusTarget) { + const handler = delayed ? { handler: () => new Promise(r => t.step_timeout(r, 0)) } : {}; + const expectedDecoy = delayed ? decoy : autofocusTarget; + const decoyMessage = delayed ? "Focus moves to the autofocused button after the transition" : "Focus stays on the non-autofocused button after the transition"; + const expectedBody = delayed ? document.body : expectedDecoy; + const bodyMessage = delayed ? "Focus gets reset after the transition" : "Focus moves to the autofocused button after the transition"; + + return { handler, expectedDecoy, decoyMessage, expectedBody, bodyMessage }; +} + promise_setup(async () => { // Get the overall autofocus processed flag to flip to true, so that // we only test the navigation API-specific stuff. @@ -22,14 +37,15 @@ decoy.focus(); assert_equals(document.activeElement, decoy, "focus() worked"); + const { handler, expectedDecoy, decoyMessage } = createExpected(t, decoy, autofocusTarget); navigation.addEventListener("navigate", e => { - e.intercept(); + e.intercept(handler); }, { once: true }); const { committed, finished } = navigation.navigate("#1"); await committed; - assert_equals(document.activeElement, decoy, "Focus stays on the non-autofocused button during the transition"); + assert_equals(document.activeElement, expectedDecoy, decoyMessage); await finished; assert_equals(document.activeElement, autofocusTarget, "Focus moves to the autofocused button after the transition"); @@ -43,14 +59,15 @@ decoy.focus(); assert_equals(document.activeElement, decoy, "focus() worked"); + const { handler, expectedDecoy, decoyMessage } = createExpected(t, decoy, autofocusTarget); navigation.addEventListener("navigate", e => { - e.intercept(); + e.intercept(handler); }, { once: true }); const { committed, finished } = navigation.navigate("#1"); await committed; - assert_equals(document.activeElement, decoy, "Focus stays on the initially-focused button during the transition"); + assert_equals(document.activeElement, expectedDecoy, decoyMessage); await finished; assert_equals(document.activeElement, autofocusTarget, "Focus moves to the first autofocused button after the transition"); @@ -64,19 +81,20 @@ decoy.focus(); assert_equals(document.activeElement, decoy, "focus() worked"); + const { handler, expectedDecoy, decoyMessage, expectedBody, bodyMessage } = createExpected(t, decoy, autofocusTarget); navigation.addEventListener("navigate", e => { - e.intercept(); + e.intercept(handler); }, { once: true }); const { committed, finished } = navigation.navigate("#1"); await committed; - assert_equals(document.activeElement, decoy, "Focus stays on the non-autofocused button during the transition"); + assert_equals(document.activeElement, expectedDecoy, decoyMessage); autofocusTarget.disabled = true; await finished; - assert_equals(document.activeElement, document.body, "Focus gets reset after the transition"); + assert_equals(document.activeElement, expectedBody, bodyMessage); }, "An element with autofocus, present before navigation but disabled before finished, does not get focused"); promise_test(async t => { @@ -87,19 +105,20 @@ decoy.focus(); assert_equals(document.activeElement, decoy, "focus() worked"); + const { handler, expectedDecoy, decoyMessage, expectedBody, bodyMessage } = createExpected(t, decoy, autofocusTarget); navigation.addEventListener("navigate", e => { - e.intercept(); + e.intercept(handler); }, { once: true }); const { committed, finished } = navigation.navigate("#1"); await committed; - assert_equals(document.activeElement, decoy, "Focus stays on the non-autofocused button during the transition"); + assert_equals(document.activeElement, expectedDecoy, decoyMessage); autofocusTarget.autofocus = false; await finished; - assert_equals(document.activeElement, document.body, "Focus gets reset after the transition"); + assert_equals(document.activeElement, expectedBody, bodyMessage); }, "An element with autofocus, present before navigation but with its autofocus attribute removed before finished, does not get focused"); promise_test(async t => { @@ -110,8 +129,9 @@ decoy.focus(); assert_equals(document.activeElement, decoy, "focus() worked"); + const { handler } = createExpected(t, decoy, autofocusTarget); navigation.addEventListener("navigate", e => { - e.intercept(); + e.intercept(handler); }, { once: true }); const { committed, finished } = navigation.navigate("#1"); @@ -122,29 +142,45 @@ decoy.disabled = true; await finished; - assert_equals(document.activeElement, autofocusTarget, "Focus moves to the second autofocused button after the transition"); + + if (delayed) { + assert_equals(document.activeElement, autofocusTarget, "Focus moves to the second autofocused button after the transition"); + } else { + assert_equals(document.activeElement, decoy, "Focus stays on the initially-focused button during the transition"); + } }, "Two elements with autofocus, present before navigation, but the first gets disabled; the second gets focused"); promise_test(async t => { + if (delayed) { + assert_true(delayed, "This is only relevant for non-finished ") + return; + } const decoy = createAndAppend(t); assert_equals(document.activeElement, document.body, "Start on body"); decoy.focus(); assert_equals(document.activeElement, decoy, "focus() worked"); + const { handler } = createExpected(t, decoy, document.body); navigation.addEventListener("navigate", e => { - e.intercept(); + e.intercept(() => { + t.step_timeout(handler, 0) + }); }, { once: true }); const { committed, finished } = navigation.navigate("#1"); await committed; - assert_equals(document.activeElement, decoy, "Focus stays on the non-autofocused button during the transition"); + assert_equals(document.activeElement, document.body, "Focus gets reset after the transition"); const autofocusTarget = createAndAppend(t, { autofocus: true }); await finished; - assert_equals(document.activeElement, autofocusTarget, "Focus moves to the autofocused button after the transition"); + assert_equals(document.activeElement, document.body, "Focus gets reset after the transition"); + + await new Promise(r => requestAnimationFrame(() => requestAnimationFrame(r))); + assert_equals(document.activeElement, document.body, "Focus stays reset two animation frames after the transition"); + }, "An element with autofocus, introduced between committed and finished, gets focused"); promise_test(async t => { @@ -154,14 +190,15 @@ decoy.focus(); assert_equals(document.activeElement, decoy, "focus() worked"); + const { handler } = createExpected(t, decoy, document.body); navigation.addEventListener("navigate", e => { - e.intercept(); + e.intercept(handler); }, { once: true }); const { committed, finished } = navigation.navigate("#1"); await committed; - assert_equals(document.activeElement, decoy, "Focus stays on the non-autofocused button during the transition"); + assert_equals(document.activeElement, delayed ? decoy : document.body, delayed ? "Focus stays on the non-autofocused button during the transition" : "Focus gets reset after the transition"); await finished; assert_equals(document.activeElement, document.body, "Focus gets reset after the transition");
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/focus-reset/autofocus_same-checkpoint-expected.txt b/third_party/blink/web_tests/external/wpt/navigation-api/focus-reset/autofocus_same-checkpoint-expected.txt new file mode 100644 index 0000000..4e68ee1 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/navigation-api/focus-reset/autofocus_same-checkpoint-expected.txt
@@ -0,0 +1,17 @@ +This is a testharness.js-based test. +[FAIL] An element with autofocus, present before navigation, gets focused + assert_equals: Focus stays on the non-autofocused button after the transition expected Element node <button autofocus=""></button> but got Element node <button></button> +[FAIL] Two elements with autofocus, present before navigation; the first gets focused + assert_equals: Focus stays on the non-autofocused button after the transition expected Element node <button autofocus=""></button> but got Element node <button autofocus=""></button> +[FAIL] An element with autofocus, present before navigation but disabled before finished, does not get focused + assert_equals: Focus stays on the non-autofocused button after the transition expected Element node <button autofocus=""></button> but got Element node <button></button> +[FAIL] An element with autofocus, present before navigation but with its autofocus attribute removed before finished, does not get focused + assert_equals: Focus stays on the non-autofocused button after the transition expected Element node <button autofocus=""></button> but got Element node <button></button> +[FAIL] Two elements with autofocus, present before navigation, but the first gets disabled; the second gets focused + assert_equals: Focus stays on the initially-focused button during the transition expected Element node <button autofocus="" disabled=""></button> but got Element node <button autofocus=""></button> +[FAIL] An element with autofocus, introduced between committed and finished, gets focused + assert_equals: Focus gets reset after the transition expected Element node <body>\n\n<script type="module">\n\nconst delayed = location.... but got Element node <button></button> +[FAIL] An element with autofocus, introduced after finished, does not get focused + assert_equals: Focus gets reset after the transition expected Element node <body>\n\n<script type="module">\n\nconst delayed = location.... but got Element node <button></button> +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/focus-reset/basic.html b/third_party/blink/web_tests/external/wpt/navigation-api/focus-reset/basic.html index f5a3097..9c5413f 100644 --- a/third_party/blink/web_tests/external/wpt/navigation-api/focus-reset/basic.html +++ b/third_party/blink/web_tests/external/wpt/navigation-api/focus-reset/basic.html
@@ -27,13 +27,13 @@ testFocusWasReset(t => { navigation.addEventListener("navigate", e => { - e.intercept(); + e.intercept({ handler: () => new Promise(r => t.step_timeout(r, 0)) }); }, { once: true }); }, "Resets the focus when no focusReset option is provided"); testFocusWasReset(t => { navigation.addEventListener("navigate", e => { - e.intercept(); + e.intercept({ handler: () => new Promise(r => t.step_timeout(r, 0)) }); }, { once: true }); }, "Resets the focus when focusReset is explicitly set to undefined"); @@ -45,13 +45,13 @@ testFocusWasReset(t => { navigation.addEventListener("navigate", e => { - e.intercept({ handler: () => Promise.reject() }); + e.intercept({ handler: () => new Promise((_, r) => t.step_timeout(r, 0)) }); }, { once: true }); }, "Resets the focus when no focusReset option is provided (rejected promise)"); testFocusWasReset(t => { navigation.addEventListener("navigate", e => { - e.intercept({ focusReset: "after-transition" }); + e.intercept({ handler: () => new Promise(r => t.step_timeout(r, 0)), focusReset: "after-transition" }); }, { once: true }); }, "Resets the focus when focusReset is explicitly set to 'after-transition'");
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/focus-reset/multiple-intercept.html b/third_party/blink/web_tests/external/wpt/navigation-api/focus-reset/multiple-intercept.html index 75e38c9..103023e 100644 --- a/third_party/blink/web_tests/external/wpt/navigation-api/focus-reset/multiple-intercept.html +++ b/third_party/blink/web_tests/external/wpt/navigation-api/focus-reset/multiple-intercept.html
@@ -9,7 +9,7 @@ testFocusWasReset(t => { navigation.addEventListener("navigate", e => { - e.intercept(); + e.intercept({ handler: () => new Promise(r => t.step_timeout(r, 0)) }); }, { once: true }); navigation.addEventListener("navigate", e => { @@ -43,13 +43,13 @@ }, { once: true }); navigation.addEventListener("navigate", e => { - e.intercept(); + e.intercept({ handler: () => new Promise(r => t.step_timeout(r, 0)) }); }, { once: true }); }, "after-transition + (not provided)"); testFocusWasReset(t => { navigation.addEventListener("navigate", e => { - e.intercept({ focusReset: "manual" }); + e.intercept({ handler: () => new Promise(r => t.step_timeout(r, 0)), focusReset: "manual" }); }, { once: true }); navigation.addEventListener("navigate", e => {
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/anchor-download-intercept-reject.html b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/anchor-download-intercept-reject.html index 5af651e..a19fa91e9 100644 --- a/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/anchor-download-intercept-reject.html +++ b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/anchor-download-intercept-reject.html
@@ -44,9 +44,9 @@ ["navigate", "", null], ["currententrychange", "#1", { from, navigationType: "push" }], ["handler run", "#1", { from, navigationType: "push" }], - ["promise microtask", "#1", { from, navigationType: "push" }], ["AbortSignal abort", "#1", { from, navigationType: "push" }], ["navigateerror", "#1", { from, navigationType: "push" }], + ["promise microtask", "#1", null], ["transition.finished rejected", "#1", null], ]);
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/anchor-download-intercept-reject_currententrychange-expected.txt b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/anchor-download-intercept-reject_currententrychange-expected.txt new file mode 100644 index 0000000..79b976e --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/anchor-download-intercept-reject_currententrychange-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] event and promise ordering for <a download> intercepted by passing a rejected promise to intercept() + assert_array_equals: expected property 3 to be "AbortSignal abort" but got "promise microtask" (expected array ["navigate", "currententrychange", "handler run", "AbortSignal abort", "navigateerror", "promise microtask", "transition.finished rejected"] got ["navigate", "currententrychange", "handler run", "promise microtask", "AbortSignal abort", "navigateerror", "transition.finished rejected"]) +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/anchor-download-intercept-reject_no-currententrychange-expected.txt b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/anchor-download-intercept-reject_no-currententrychange-expected.txt new file mode 100644 index 0000000..b646f35 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/anchor-download-intercept-reject_no-currententrychange-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] event and promise ordering for <a download> intercepted by passing a rejected promise to intercept() + assert_array_equals: expected property 2 to be "AbortSignal abort" but got "promise microtask" (expected array ["navigate", "handler run", "AbortSignal abort", "navigateerror", "promise microtask", "transition.finished rejected"] got ["navigate", "handler run", "promise microtask", "AbortSignal abort", "navigateerror", "transition.finished rejected"]) +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/anchor-download-intercept.html b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/anchor-download-intercept.html index 38478e3c..72dce7c 100644 --- a/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/anchor-download-intercept.html +++ b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/anchor-download-intercept.html
@@ -40,8 +40,8 @@ ["navigate", "", null], ["currententrychange", "#1", { from, navigationType: "push" }], ["handler run", "#1", { from, navigationType: "push" }], - ["promise microtask", "#1", { from, navigationType: "push" }], ["navigatesuccess", "#1", { from, navigationType: "push" }], + ["promise microtask", "#1", null], ["transition.finished fulfilled", "#1", null], ]); }, "event and promise ordering for <a download> intercepted by intercept()");
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/anchor-download-intercept_currententrychange-expected.txt b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/anchor-download-intercept_currententrychange-expected.txt new file mode 100644 index 0000000..ca30c0c --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/anchor-download-intercept_currententrychange-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] event and promise ordering for <a download> intercepted by intercept() + assert_array_equals: expected property 3 to be "navigatesuccess" but got "promise microtask" (expected array ["navigate", "currententrychange", "handler run", "navigatesuccess", "promise microtask", "transition.finished fulfilled"] got ["navigate", "currententrychange", "handler run", "promise microtask", "navigatesuccess", "transition.finished fulfilled"]) +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/anchor-download-intercept_no-currententrychange-expected.txt b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/anchor-download-intercept_no-currententrychange-expected.txt new file mode 100644 index 0000000..3ee4d276 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/anchor-download-intercept_no-currententrychange-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] event and promise ordering for <a download> intercepted by intercept() + assert_array_equals: expected property 2 to be "navigatesuccess" but got "promise microtask" (expected array ["navigate", "handler run", "navigatesuccess", "promise microtask", "transition.finished fulfilled"] got ["navigate", "handler run", "promise microtask", "navigatesuccess", "transition.finished fulfilled"]) +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/location-href-intercept-reject.html b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/location-href-intercept-reject.html index 81e8f2e..831af58 100644 --- a/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/location-href-intercept-reject.html +++ b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/location-href-intercept-reject.html
@@ -40,9 +40,9 @@ ["navigate", "", null], ["currententrychange", "#1", { from, navigationType: "push" }], ["handler run", "#1", { from, navigationType: "push" }], - ["promise microtask", "#1", { from, navigationType: "push" }], ["AbortSignal abort", "#1", { from, navigationType: "push" }], ["navigateerror", "#1", { from, navigationType: "push" }], + ["promise microtask", "#1", null], ["transition.finished rejected", "#1", null], ]);
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/location-href-intercept-reject_currententrychange-expected.txt b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/location-href-intercept-reject_currententrychange-expected.txt new file mode 100644 index 0000000..6f5cd88 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/location-href-intercept-reject_currententrychange-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] event and promise ordering for location.href setter intercepted by passing a rejected promise to intercept() + assert_array_equals: expected property 3 to be "AbortSignal abort" but got "promise microtask" (expected array ["navigate", "currententrychange", "handler run", "AbortSignal abort", "navigateerror", "promise microtask", "transition.finished rejected"] got ["navigate", "currententrychange", "handler run", "promise microtask", "AbortSignal abort", "navigateerror", "transition.finished rejected"]) +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/location-href-intercept-reject_no-currententrychange-expected.txt b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/location-href-intercept-reject_no-currententrychange-expected.txt new file mode 100644 index 0000000..bbc7ede --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/location-href-intercept-reject_no-currententrychange-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] event and promise ordering for location.href setter intercepted by passing a rejected promise to intercept() + assert_array_equals: expected property 2 to be "AbortSignal abort" but got "promise microtask" (expected array ["navigate", "handler run", "AbortSignal abort", "navigateerror", "promise microtask", "transition.finished rejected"] got ["navigate", "handler run", "promise microtask", "AbortSignal abort", "navigateerror", "transition.finished rejected"]) +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/location-href-intercept.html b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/location-href-intercept.html index 75f1d3d..7787a54f 100644 --- a/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/location-href-intercept.html +++ b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/location-href-intercept.html
@@ -36,8 +36,8 @@ ["navigate", "", null], ["currententrychange", "#1", { from, navigationType: "push" }], ["handler run", "#1", { from, navigationType: "push" }], - ["promise microtask", "#1", { from, navigationType: "push" }], ["navigatesuccess", "#1", { from, navigationType: "push" }], + ["promise microtask", "#1", null], ["transition.finished fulfilled", "#1", null], ]); }, "event and promise ordering for location.href setter intercepted by intercept()");
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/location-href-intercept_currententrychange-expected.txt b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/location-href-intercept_currententrychange-expected.txt new file mode 100644 index 0000000..76c0770d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/location-href-intercept_currententrychange-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] event and promise ordering for location.href setter intercepted by intercept() + assert_array_equals: expected property 3 to be "navigatesuccess" but got "promise microtask" (expected array ["navigate", "currententrychange", "handler run", "navigatesuccess", "promise microtask", "transition.finished fulfilled"] got ["navigate", "currententrychange", "handler run", "promise microtask", "navigatesuccess", "transition.finished fulfilled"]) +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/location-href-intercept_no-currententrychange-expected.txt b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/location-href-intercept_no-currententrychange-expected.txt new file mode 100644 index 0000000..6b89912 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/location-href-intercept_no-currententrychange-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] event and promise ordering for location.href setter intercepted by intercept() + assert_array_equals: expected property 2 to be "navigatesuccess" but got "promise microtask" (expected array ["navigate", "handler run", "navigatesuccess", "promise microtask", "transition.finished fulfilled"] got ["navigate", "handler run", "promise microtask", "navigatesuccess", "transition.finished fulfilled"]) +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/navigate-in-transition-finished.html b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/navigate-in-transition-finished.html index 8b3811d..9cde1cb9 100644 --- a/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/navigate-in-transition-finished.html +++ b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/navigate-in-transition-finished.html
@@ -51,19 +51,19 @@ ["navigate", "", null], ["currententrychange", "#1", { from: fromStart, navigationType: "push" }], ["handler run", "#1", { from: fromStart, navigationType: "push" }], - ["committed fulfilled 1", "#1", { from: fromStart, navigationType: "push" }], - ["transition.committed fulfilled 1", "#1", { from: fromStart, navigationType: "push" }], - ["promise microtask", "#1", { from: fromStart, navigationType: "push" }], ["navigatesuccess", "#1", { from: fromStart, navigationType: "push" }], + ["committed fulfilled 1", "#1", null], + ["transition.committed fulfilled 1", "#1", null], + ["promise microtask", "#1", null], ["finished fulfilled 1", "#1", null], ["transition.finished fulfilled", "#1", null], ["navigate", "#1", null], ["currententrychange", "#2", { from: fromHash1, navigationType: "push" }], ["handler run", "#2", { from: fromHash1, navigationType: "push" }], - ["committed fulfilled 2", "#2", { from: fromHash1, navigationType: "push" }], - ["transition.committed fulfilled 2", "#2", { from: fromHash1, navigationType: "push" }], ["navigatesuccess", "#2", { from: fromHash1, navigationType: "push" }], + ["committed fulfilled 2", "#2", null], + ["transition.committed fulfilled 2", "#2", null], ["finished fulfilled 2", "#2", null], ["transition.finished fulfilled", "#2", null] ]);
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/navigate-in-transition-finished_currententrychange-expected.txt b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/navigate-in-transition-finished_currententrychange-expected.txt new file mode 100644 index 0000000..010add6 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/navigate-in-transition-finished_currententrychange-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] event and promise ordering when navigate() is called inside the transition.finished promise handler + assert_array_equals: expected property 3 to be "navigatesuccess" but got "committed fulfilled 1" (expected array ["navigate", "currententrychange", "handler run", "navigatesuccess", "committed fulfilled 1", "transition.committed fulfilled 1", "promise microtask", "finished fulfilled 1", "transition.finished fulfilled", "navigate", "currententrychange", "handler run", "navigatesuccess", "committed fulfilled 2", "transition.committed fulfilled 2", "finished fulfilled 2", "transition.finished fulfilled"] got ["navigate", "currententrychange", "handler run", "committed fulfilled 1", "transition.committed fulfilled 1", "promise microtask", "navigatesuccess", "finished fulfilled 1", "transition.finished fulfilled", "navigate", "currententrychange", "handler run", "committed fulfilled 2", "transition.committed fulfilled 2", "navigatesuccess", "finished fulfilled 2", "transition.finished fulfilled"]) +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/navigate-in-transition-finished_no-currententrychange-expected.txt b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/navigate-in-transition-finished_no-currententrychange-expected.txt new file mode 100644 index 0000000..5e18b22 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/navigate-in-transition-finished_no-currententrychange-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] event and promise ordering when navigate() is called inside the transition.finished promise handler + assert_array_equals: expected property 2 to be "navigatesuccess" but got "committed fulfilled 1" (expected array ["navigate", "handler run", "navigatesuccess", "committed fulfilled 1", "transition.committed fulfilled 1", "promise microtask", "finished fulfilled 1", "transition.finished fulfilled", "navigate", "handler run", "navigatesuccess", "committed fulfilled 2", "transition.committed fulfilled 2", "finished fulfilled 2", "transition.finished fulfilled"] got ["navigate", "handler run", "committed fulfilled 1", "transition.committed fulfilled 1", "promise microtask", "navigatesuccess", "finished fulfilled 1", "transition.finished fulfilled", "navigate", "handler run", "committed fulfilled 2", "transition.committed fulfilled 2", "navigatesuccess", "finished fulfilled 2", "transition.finished fulfilled"]) +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/navigate-intercept.html b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/navigate-intercept.html index eec9d3c..5315ecf 100644 --- a/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/navigate-intercept.html +++ b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/navigate-intercept.html
@@ -37,10 +37,10 @@ ["navigate", "", null], ["currententrychange", "#1", { from, navigationType: "push" }], ["handler run", "#1", { from, navigationType: "push" }], - ["committed fulfilled", "#1", { from, navigationType: "push" }], - ["transition.committed fulfilled", "#1", { from, navigationType: "push" }], - ["promise microtask", "#1", { from, navigationType: "push" }], ["navigatesuccess", "#1", { from, navigationType: "push" }], + ["committed fulfilled", "#1", null], + ["transition.committed fulfilled", "#1", null], + ["promise microtask", "#1", null], ["finished fulfilled", "#1", null], ["transition.finished fulfilled", "#1", null], ]);
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/navigate-intercept_currententrychange-expected.txt b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/navigate-intercept_currententrychange-expected.txt new file mode 100644 index 0000000..7748f795 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/navigate-intercept_currententrychange-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] event and promise ordering for same-document navigation.navigate() intercepted by intercept() + assert_array_equals: expected property 3 to be "navigatesuccess" but got "committed fulfilled" (expected array ["navigate", "currententrychange", "handler run", "navigatesuccess", "committed fulfilled", "transition.committed fulfilled", "promise microtask", "finished fulfilled", "transition.finished fulfilled"] got ["navigate", "currententrychange", "handler run", "committed fulfilled", "transition.committed fulfilled", "promise microtask", "navigatesuccess", "finished fulfilled", "transition.finished fulfilled"]) +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/navigate-intercept_no-currententrychange-expected.txt b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/navigate-intercept_no-currententrychange-expected.txt new file mode 100644 index 0000000..0acee39 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/navigate-intercept_no-currententrychange-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] event and promise ordering for same-document navigation.navigate() intercepted by intercept() + assert_array_equals: expected property 2 to be "navigatesuccess" but got "committed fulfilled" (expected array ["navigate", "handler run", "navigatesuccess", "committed fulfilled", "transition.committed fulfilled", "promise microtask", "finished fulfilled", "transition.finished fulfilled"] got ["navigate", "handler run", "committed fulfilled", "transition.committed fulfilled", "promise microtask", "navigatesuccess", "finished fulfilled", "transition.finished fulfilled"]) +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/navigate-same-document-intercept-reject.html b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/navigate-same-document-intercept-reject.html index 1e851cf..64f9612 100644 --- a/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/navigate-same-document-intercept-reject.html +++ b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/navigate-same-document-intercept-reject.html
@@ -41,11 +41,11 @@ ["navigate", "", null], ["currententrychange", "#1", { from, navigationType: "push" }], ["handler run", "#1", { from, navigationType: "push" }], - ["committed fulfilled", "#1", { from, navigationType: "push" }], - ["transition.committed fulfilled", "#1", { from, navigationType: "push" }], - ["promise microtask", "#1", { from, navigationType: "push" }], ["AbortSignal abort", "#1", { from, navigationType: "push" }], ["navigateerror", "#1", { from, navigationType: "push" }], + ["committed fulfilled", "#1", null], + ["transition.committed fulfilled", "#1", null], + ["promise microtask", "#1", null], ["finished rejected", "#1", null], ["transition.finished rejected", "#1", null], ]);
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/navigate-same-document-intercept-reject_currententrychange-expected.txt b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/navigate-same-document-intercept-reject_currententrychange-expected.txt new file mode 100644 index 0000000..81a0c84 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/navigate-same-document-intercept-reject_currententrychange-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] event and promise ordering for same-document navigation.navigate() intercepted by passing a rejected promise to intercept() + assert_array_equals: expected property 3 to be "AbortSignal abort" but got "committed fulfilled" (expected array ["navigate", "currententrychange", "handler run", "AbortSignal abort", "navigateerror", "committed fulfilled", "transition.committed fulfilled", "promise microtask", "finished rejected", "transition.finished rejected"] got ["navigate", "currententrychange", "handler run", "committed fulfilled", "transition.committed fulfilled", "promise microtask", "AbortSignal abort", "navigateerror", "finished rejected", "transition.finished rejected"]) +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/navigate-same-document-intercept-reject_no-currententrychange-expected.txt b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/navigate-same-document-intercept-reject_no-currententrychange-expected.txt new file mode 100644 index 0000000..744c862 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/navigate-same-document-intercept-reject_no-currententrychange-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] event and promise ordering for same-document navigation.navigate() intercepted by passing a rejected promise to intercept() + assert_array_equals: expected property 2 to be "AbortSignal abort" but got "committed fulfilled" (expected array ["navigate", "handler run", "AbortSignal abort", "navigateerror", "committed fulfilled", "transition.committed fulfilled", "promise microtask", "finished rejected", "transition.finished rejected"] got ["navigate", "handler run", "committed fulfilled", "transition.committed fulfilled", "promise microtask", "AbortSignal abort", "navigateerror", "finished rejected", "transition.finished rejected"]) +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/navigate-same-document.html b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/navigate-same-document.html index fc506ce..d96393f 100644 --- a/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/navigate-same-document.html +++ b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/navigate-same-document.html
@@ -30,9 +30,9 @@ /* event name, location.hash value, navigation.transition properties */ ["navigate", "", null], ["currententrychange", "#1", null], + ["navigatesuccess", "#1", null], ["committed fulfilled", "#1", null], ["promise microtask", "#1", null], - ["navigatesuccess", "#1", null], ["finished fulfilled", "#1", null], ]); }, "event and promise ordering for same-document navigation.navigate()");
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/navigate-same-document_currententrychange-expected.txt b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/navigate-same-document_currententrychange-expected.txt new file mode 100644 index 0000000..33b4bbf --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/navigate-same-document_currententrychange-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] event and promise ordering for same-document navigation.navigate() + assert_array_equals: expected property 2 to be "navigatesuccess" but got "committed fulfilled" (expected array ["navigate", "currententrychange", "navigatesuccess", "committed fulfilled", "promise microtask", "finished fulfilled"] got ["navigate", "currententrychange", "committed fulfilled", "promise microtask", "navigatesuccess", "finished fulfilled"]) +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/navigate-same-document_no-currententrychange-expected.txt b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/navigate-same-document_no-currententrychange-expected.txt new file mode 100644 index 0000000..82f9fc2 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/navigate-same-document_no-currententrychange-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] event and promise ordering for same-document navigation.navigate() + assert_array_equals: expected property 1 to be "navigatesuccess" but got "committed fulfilled" (expected array ["navigate", "navigatesuccess", "committed fulfilled", "promise microtask", "finished fulfilled"] got ["navigate", "committed fulfilled", "promise microtask", "navigatesuccess", "finished fulfilled"]) +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/reload-intercept-reject.html b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/reload-intercept-reject.html index 9c8894b..8183383c 100644 --- a/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/reload-intercept-reject.html +++ b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/reload-intercept-reject.html
@@ -41,11 +41,11 @@ ["navigate", "", null], ["currententrychange", "", { from, navigationType: "reload" }], ["handler run", "", { from, navigationType: "reload" }], - ["committed fulfilled", "", { from, navigationType: "reload" }], - ["transition.committed fulfilled", "", { from, navigationType: "reload" }], - ["promise microtask", "", { from, navigationType: "reload" }], ["AbortSignal abort", "", { from, navigationType: "reload" }], ["navigateerror", "", { from, navigationType: "reload" }], + ["committed fulfilled", "", null], + ["transition.committed fulfilled", "", null], + ["promise microtask", "", null], ["finished rejected", "", null], ["transition.finished rejected", "", null], ]);
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/reload-intercept-reject_currententrychange-expected.txt b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/reload-intercept-reject_currententrychange-expected.txt new file mode 100644 index 0000000..42e114c --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/reload-intercept-reject_currententrychange-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] event and promise ordering for navigation.reload() intercepted by intercept() + assert_array_equals: expected property 3 to be "AbortSignal abort" but got "committed fulfilled" (expected array ["navigate", "currententrychange", "handler run", "AbortSignal abort", "navigateerror", "committed fulfilled", "transition.committed fulfilled", "promise microtask", "finished rejected", "transition.finished rejected"] got ["navigate", "currententrychange", "handler run", "committed fulfilled", "transition.committed fulfilled", "promise microtask", "AbortSignal abort", "navigateerror", "finished rejected", "transition.finished rejected"]) +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/reload-intercept-reject_no-currententrychange-expected.txt b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/reload-intercept-reject_no-currententrychange-expected.txt new file mode 100644 index 0000000..96d82c2 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/reload-intercept-reject_no-currententrychange-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] event and promise ordering for navigation.reload() intercepted by intercept() + assert_array_equals: expected property 2 to be "AbortSignal abort" but got "committed fulfilled" (expected array ["navigate", "handler run", "AbortSignal abort", "navigateerror", "committed fulfilled", "transition.committed fulfilled", "promise microtask", "finished rejected", "transition.finished rejected"] got ["navigate", "handler run", "committed fulfilled", "transition.committed fulfilled", "promise microtask", "AbortSignal abort", "navigateerror", "finished rejected", "transition.finished rejected"]) +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/reload-intercept.html b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/reload-intercept.html index 1494136e..da1ae20 100644 --- a/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/reload-intercept.html +++ b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/reload-intercept.html
@@ -37,10 +37,10 @@ ["navigate", "", null], ["currententrychange", "", { from, navigationType: "reload" }], ["handler run", "", { from, navigationType: "reload" }], - ["committed fulfilled", "", { from, navigationType: "reload" }], - ["transition.committed fulfilled", "", { from, navigationType: "reload" }], - ["promise microtask", "", { from, navigationType: "reload" }], ["navigatesuccess", "", { from, navigationType: "reload" }], + ["committed fulfilled", "", null], + ["transition.committed fulfilled", "", null], + ["promise microtask", "", null], ["finished fulfilled", "", null], ["transition.finished fulfilled", "", null], ]);
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/reload-intercept_currententrychange-expected.txt b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/reload-intercept_currententrychange-expected.txt new file mode 100644 index 0000000..39f1916b --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/reload-intercept_currententrychange-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] event and promise ordering for navigation.reload() intercepted by intercept() + assert_array_equals: expected property 3 to be "navigatesuccess" but got "committed fulfilled" (expected array ["navigate", "currententrychange", "handler run", "navigatesuccess", "committed fulfilled", "transition.committed fulfilled", "promise microtask", "finished fulfilled", "transition.finished fulfilled"] got ["navigate", "currententrychange", "handler run", "committed fulfilled", "transition.committed fulfilled", "promise microtask", "navigatesuccess", "finished fulfilled", "transition.finished fulfilled"]) +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/reload-intercept_no-currententrychange-expected.txt b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/reload-intercept_no-currententrychange-expected.txt new file mode 100644 index 0000000..468af8f3 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/reload-intercept_no-currententrychange-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] event and promise ordering for navigation.reload() intercepted by intercept() + assert_array_equals: expected property 2 to be "navigatesuccess" but got "committed fulfilled" (expected array ["navigate", "handler run", "navigatesuccess", "committed fulfilled", "transition.committed fulfilled", "promise microtask", "finished fulfilled", "transition.finished fulfilled"] got ["navigate", "handler run", "committed fulfilled", "transition.committed fulfilled", "promise microtask", "navigatesuccess", "finished fulfilled", "transition.finished fulfilled"]) +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/reload-no-popstate-expected.txt b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/reload-no-popstate-expected.txt new file mode 100644 index 0000000..39f1916b --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/reload-no-popstate-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] event and promise ordering for navigation.reload() intercepted by intercept() + assert_array_equals: expected property 3 to be "navigatesuccess" but got "committed fulfilled" (expected array ["navigate", "currententrychange", "handler run", "navigatesuccess", "committed fulfilled", "transition.committed fulfilled", "promise microtask", "finished fulfilled", "transition.finished fulfilled"] got ["navigate", "currententrychange", "handler run", "committed fulfilled", "transition.committed fulfilled", "promise microtask", "navigatesuccess", "finished fulfilled", "transition.finished fulfilled"]) +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/reload-no-popstate.html b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/reload-no-popstate.html index 6c4592b6..5f67b25 100644 --- a/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/reload-no-popstate.html +++ b/third_party/blink/web_tests/external/wpt/navigation-api/ordering-and-transition/reload-no-popstate.html
@@ -36,10 +36,10 @@ ["navigate", "", null], ["currententrychange", "", { from, navigationType: "reload" }], ["handler run", "", { from, navigationType: "reload" }], - ["committed fulfilled", "", { from, navigationType: "reload" }], - ["transition.committed fulfilled", "", { from, navigationType: "reload" }], - ["promise microtask", "", { from, navigationType: "reload" }], ["navigatesuccess", "", { from, navigationType: "reload" }], + ["committed fulfilled", "", null], + ["transition.committed fulfilled", "", null], + ["promise microtask", "", null], ["finished fulfilled", "", null], ["transition.finished fulfilled", "", null], ]);
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/precommit-handler/precommitHandler-window-stop-before-commit-expected.txt b/third_party/blink/web_tests/external/wpt/navigation-api/precommit-handler/precommitHandler-window-stop-before-commit-expected.txt new file mode 100644 index 0000000..59f4a80 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/navigation-api/precommit-handler/precommitHandler-window-stop-before-commit-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[FAIL] precommitHandler with window.stop() before fragment navigation commit + assert_unreached: onnavigateerror must not fire Reached unreachable code +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/precommit-handler/precommitHandler-window-stop-before-commit.html b/third_party/blink/web_tests/external/wpt/navigation-api/precommit-handler/precommitHandler-window-stop-before-commit.html index 857a21e..c1a11fa9 100644 --- a/third_party/blink/web_tests/external/wpt/navigation-api/precommit-handler/precommitHandler-window-stop-before-commit.html +++ b/third_party/blink/web_tests/external/wpt/navigation-api/precommit-handler/precommitHandler-window-stop-before-commit.html
@@ -8,7 +8,9 @@ // Wait for after the load event because window.stop() hangs the test harness // if called before the load event. await new Promise(resolve => window.onload = () => t.step_timeout(resolve, 0)); +}, "Setup"); +promise_test(async t => { navigation.onnavigate = e => { e.intercept({ precommitHandler: async () => {} }); }; @@ -20,7 +22,7 @@ assert_equals(location.hash, ""); }); - let promises = navigation.navigate("#ShouldNotCommit"); + let promises = navigation.navigate("?ShouldNotCommit"); assert_equals(location.hash, ""); window.stop(); @@ -28,6 +30,28 @@ assert_equals(location.hash, ""); assert_true(navigateerror_called); -}, " precommitHandler with window.stop() before commit"); +}, " precommitHandler with window.stop() before navigation commit"); + +promise_test(async t => { + navigation.onnavigate = e => { + e.intercept({ precommitHandler: async () => {} }); + }; + + navigation.onnavigateerror = t.unreached_func("onnavigateerror must not fire"); + let navigatesuccess_called = false; + navigation.onnavigatesuccess = t.step_func(() => { + navigatesuccess_called = true; + assert_equals(location.hash, "#ShouldCommit"); + }); + + let promises = navigation.navigate("#ShouldCommit"); + assert_equals(location.hash, ""); + + window.stop(); + await assertBothFulfillEntryNotAvailable(t, promises); + + assert_equals(location.hash, "#ShouldCommit"); + assert_true(navigatesuccess_called); +}, " precommitHandler with window.stop() before fragment navigation commit"); </script> </body>
diff --git a/third_party/blink/web_tests/external/wpt/preload/preload-type-match.html b/third_party/blink/web_tests/external/wpt/preload/preload-type-match.html index f429670b..746c179 100644 --- a/third_party/blink/web_tests/external/wpt/preload/preload-type-match.html +++ b/third_party/blink/web_tests/external/wpt/preload/preload-type-match.html
@@ -76,7 +76,6 @@ test_type_with_destination('text/plain', 'json', 'json', 'timeout'); test_type_with_destination('application/javascript', 'json', 'json', 'timeout'); -test_type_with_destination('', 'text', 'text', 'timeout'); test_type_with_destination('text/plain', 'text', 'text', 'timeout'); test_type_with_destination('application/json', 'text', 'text', 'timeout'); test_type_with_destination('application/javascript', 'text', 'text', 'timeout');
diff --git a/third_party/blink/web_tests/external/wpt/selection/crashtests/selection-modify-line-boundary-around-empty-details.html b/third_party/blink/web_tests/external/wpt/selection/crashtests/selection-modify-line-boundary-around-empty-details.html index 815a819..ff7760e 100644 --- a/third_party/blink/web_tests/external/wpt/selection/crashtests/selection-modify-line-boundary-around-empty-details.html +++ b/third_party/blink/web_tests/external/wpt/selection/crashtests/selection-modify-line-boundary-around-empty-details.html
@@ -9,7 +9,19 @@ let i = 0; const details = document.querySelector("details"); const id = setInterval(() => { - getSelection().modify("move", "forward", "lineboundary"); + const selection = getSelection(); + if (!selection) { + clearInterval(id); + throw new Error("Should always have a selection"); + } + // This means that the browser doesn't support modify. + // Rather than endless looping and crashing the browser, + // exit early. + if (!selection.modify) { + clearInterval(id); + return; + } + selection.modify("move", "forward", "lineboundary"); if (details.isConnected) { details.outerHTML = undefined; }
diff --git a/third_party/blink/web_tests/external/wpt/shadow-dom/declarative/tentative/shadowrootadoptedstylesheets/shadowrootadoptedstylesheets-clonenode-async-fetch.html b/third_party/blink/web_tests/external/wpt/shadow-dom/declarative/tentative/shadowrootadoptedstylesheets/shadowrootadoptedstylesheets-clonenode-async-fetch.html new file mode 100644 index 0000000..94b83b5 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/shadow-dom/declarative/tentative/shadowrootadoptedstylesheets/shadowrootadoptedstylesheets-clonenode-async-fetch.html
@@ -0,0 +1,70 @@ +<!DOCTYPE html> +<title>cloneNode of a host with an async-fetched shadowrootadoptedstylesheets specifier</title> +<meta name="author" title="Kurt Catti-Schmidt" href="mailto:kschmi@microsoft.com" /> +<link rel="help" href="https://github.com/whatwg/html/pull/11687"> +<link rel="help" href="https://dom.spec.whatwg.org/#concept-node-clone"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="./support/helpers.js"></script> +<body> +<script type="module"> + promise_test(async (t) => { + // Build a host whose shadowrootadoptedstylesheets references a URL + // that has not yet been fetched. This produces a placeholder + // CSSStyleSheet at index 0 of the original's adoptedStyleSheets. + // Cloning before the fetch resolves should also produce a clone + // with one entry (a placeholder), and cloning after resolution + // should yield the resolved sheet. + // + // createStylesheetHost() does NOT add shadowrootclonable, so we + // build the host markup directly via setHTMLUnsafe to make sure + // cloneNode actually clones the shadow root. + const cssUrl = new URL("./support/styles.css?clonenode_async", + location.href).href; + document.body.setHTMLUnsafe( + `<div id="host_pre">` + + `<template shadowrootmode="open" shadowrootclonable ` + + `shadowrootadoptedstylesheets="${cssUrl}">` + + `<span id="t">async pre-clone</span>` + + `</template>` + + `</div>` + ); + const preHost = document.getElementById("host_pre"); + assert_equals(preHost.shadowRoot.adoptedStyleSheets.length, 1, + "Original has 1 placeholder before fetch resolves."); + assert_equals(preHost.shadowRoot.adoptedStyleSheets[0].cssRules.length, 0, + "Original placeholder has 0 rules before resolution."); + + // Clone BEFORE the fetch completes. The clone should have its own + // placeholder at index 0 (also empty). + const clonePre = preHost.cloneNode(true); + assert_true(!!clonePre.shadowRoot, + "Pre-resolution clone has a shadow root."); + assert_equals(clonePre.shadowRoot.adoptedStyleSheets.length, 1, + "Pre-resolution clone has 1 entry (placeholder) at the same index."); + + // Drive the fetch to completion. + await fetchAndWait(cssUrl); + + assertSheetRule(preHost.shadowRoot, 0, "span { color: blue; }", + "Original after fetch"); + + // Clone AFTER the fetch resolves. The cloned shadow root should + // resolve synchronously from the now-cached module map and end up + // with the same resolved CSSStyleSheet instance. + const clonePost = preHost.cloneNode(true); + assert_true(!!clonePost.shadowRoot, + "Post-resolution clone has a shadow root."); + assert_equals(clonePost.shadowRoot.adoptedStyleSheets.length, 1, + "Post-resolution clone has 1 adopted stylesheet."); + assertSheetRule(clonePost.shadowRoot, 0, "span { color: blue; }", + "Post-resolution clone"); + assert_equals( + clonePost.shadowRoot.adoptedStyleSheets[0], + preHost.shadowRoot.adoptedStyleSheets[0], + "Post-resolution clone shares the original's resolved CSSStyleSheet " + + "instance (single module-map entry per URL)." + ); + }, "cloneNode handles both placeholder and resolved async-fetched adoptedStyleSheets."); +</script> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/shadow-dom/declarative/tentative/shadowrootadoptedstylesheets/shadowrootadoptedstylesheets-clonenode.html b/third_party/blink/web_tests/external/wpt/shadow-dom/declarative/tentative/shadowrootadoptedstylesheets/shadowrootadoptedstylesheets-clonenode.html new file mode 100644 index 0000000..85a5222 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/shadow-dom/declarative/tentative/shadowrootadoptedstylesheets/shadowrootadoptedstylesheets-clonenode.html
@@ -0,0 +1,287 @@ +<!DOCTYPE html> +<title>cloneNode preserves shadowrootadoptedstylesheets on declarative shadow roots</title> +<meta name="author" title="Kurt Catti-Schmidt" href="mailto:kschmi@microsoft.com" /> +<link rel="help" href="https://github.com/whatwg/html/pull/11687"> +<link rel="help" href="https://dom.spec.whatwg.org/#concept-node-clone"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script type="importmap"> +{ + "imports": { + "foo": "data:text/css,span{color:blue}", + "bar": "data:text/css,span{text-decoration:underline}" + } +} +</script> + +<!-- Single specifier, clonable host. --> +<div id="host_basic"> + <template shadowrootmode="open" + shadowrootclonable + shadowrootadoptedstylesheets="foo"> + <span id="t">basic</span> + </template> +</div> + +<!-- Multiple specifiers (whitespace-separated). --> +<div id="host_multi"> + <template shadowrootmode="open" + shadowrootclonable + shadowrootadoptedstylesheets="foo bar"> + <span id="t">multi</span> + </template> +</div> + +<!-- Empty (present-but-empty) attribute. --> +<div id="host_empty"> + <template shadowrootmode="open" + shadowrootclonable + shadowrootadoptedstylesheets=""> + <span id="t">empty</span> + </template> +</div> + +<!-- Absent attribute. --> +<div id="host_absent"> + <template shadowrootmode="open" shadowrootclonable> + <span id="t">absent</span> + </template> +</div> + +<!-- Non-clonable host: clone should have NO shadow root at all. --> +<div id="host_nonclonable"> + <template shadowrootmode="open" + shadowrootadoptedstylesheets="foo"> + <span id="t">nonclonable</span> + </template> +</div> + +<!-- Whitespace-only authored value. --> +<div id="host_whitespace"> + <template shadowrootmode="open" + shadowrootclonable + shadowrootadoptedstylesheets=" foo bar "> + <span id="t">whitespace</span> + </template> +</div> + +<!-- Serializable + clonable for the round-trip test. --> +<div id="host_serializable"> + <template shadowrootmode="open" + shadowrootclonable + shadowrootserializable + shadowrootadoptedstylesheets="foo"> + <span id="t">serializable</span> + </template> +</div> + +<script> +test(() => { + const host = document.getElementById("host_basic"); + assert_equals(host.shadowRoot.adoptedStyleSheets.length, 1, + "Sanity: original shadow root has 1 adopted stylesheet."); + const clone = host.cloneNode(true); + assert_true(!!clone.shadowRoot, + "Clone of clonable host has a shadow root."); + assert_equals(clone.shadowRoot.adoptedStyleSheets.length, 1, + "Clone's shadow root has the same number of adopted stylesheets as the original."); + assert_equals(clone.shadowRoot.adoptedStyleSheets[0], + host.shadowRoot.adoptedStyleSheets[0], + "Clone's adopted stylesheet is the same CSSStyleSheet instance " + + "(import-map specifiers resolve to one shared module sheet)."); +}, "cloneNode(true) re-processes shadowrootadoptedstylesheets and the clone shares the resolved sheet."); + +test(() => { + const host = document.getElementById("host_multi"); + assert_equals(host.shadowRoot.adoptedStyleSheets.length, 2, + "Sanity: original has 2 adopted stylesheets."); + const clone = host.cloneNode(true); + assert_equals(clone.shadowRoot.adoptedStyleSheets.length, 2, + "Clone has the same 2 adopted stylesheets."); + assert_array_equals( + Array.from(clone.shadowRoot.adoptedStyleSheets), + Array.from(host.shadowRoot.adoptedStyleSheets), + "Clone's adoptedStyleSheets list matches the original element-by-element." + ); +}, "cloneNode(true) preserves order of multiple shadowrootadoptedstylesheets specifiers."); + +test(() => { + const host = document.getElementById("host_empty"); + assert_equals(host.shadowRoot.adoptedStyleSheets.length, 0, + "Sanity: empty attribute yields empty array."); + const clone = host.cloneNode(true); + assert_true(!!clone.shadowRoot, "Clone has a shadow root."); + assert_equals(clone.shadowRoot.adoptedStyleSheets.length, 0, + "Clone of host with empty shadowrootadoptedstylesheets has empty adoptedStyleSheets."); +}, "cloneNode(true) with empty shadowrootadoptedstylesheets produces an empty adoptedStyleSheets on the clone."); + +test(() => { + const host = document.getElementById("host_absent"); + assert_equals(host.shadowRoot.adoptedStyleSheets.length, 0, + "Sanity: absent attribute yields empty array."); + const clone = host.cloneNode(true); + assert_true(!!clone.shadowRoot, "Clone has a shadow root."); + assert_equals(clone.shadowRoot.adoptedStyleSheets.length, 0, + "Clone of host without shadowrootadoptedstylesheets has empty adoptedStyleSheets."); +}, "cloneNode(true) with absent shadowrootadoptedstylesheets does not crash and produces an empty adoptedStyleSheets."); + +test(() => { + const host = document.getElementById("host_nonclonable"); + assert_equals(host.shadowRoot.adoptedStyleSheets.length, 1, + "Sanity: non-clonable original still has its adopted stylesheet."); + const clone = host.cloneNode(true); + assert_true(!clone.shadowRoot, + "Non-clonable declarative shadow root is not cloned at all."); +}, "cloneNode(true) on a non-clonable host does not produce a shadow root regardless of shadowrootadoptedstylesheets."); + +test(() => { + const host = document.getElementById("host_whitespace"); + // Whitespace-only authored value still resolves to two specifiers + // (SpaceSplitString collapses adjacent whitespace). + assert_equals(host.shadowRoot.adoptedStyleSheets.length, 2, + "Sanity: whitespace-padded list resolves to 2 sheets."); + const clone = host.cloneNode(true); + assert_equals(clone.shadowRoot.adoptedStyleSheets.length, 2, + "Clone resolves the same 2 specifiers from the whitespace-padded value."); +}, "cloneNode(true) preserves resolution semantics for whitespace-padded shadowrootadoptedstylesheets values."); + +test(() => { + // Mutating original's adoptedStyleSheets after attachment must NOT + // be reflected in the clone — clone is built from the attribute, not + // the live array. + const host = document.getElementById("host_basic"); + const sheet = new CSSStyleSheet(); + sheet.replaceSync("span{font-weight:bold}"); + host.shadowRoot.adoptedStyleSheets = + [...host.shadowRoot.adoptedStyleSheets, sheet]; + assert_equals(host.shadowRoot.adoptedStyleSheets.length, 2, + "Sanity: original now has 2 adopted stylesheets after mutation."); + const clone = host.cloneNode(true); + assert_equals(clone.shadowRoot.adoptedStyleSheets.length, 1, + "Clone reflects the original attribute value, not the post-attachment mutation."); + // Restore to keep test isolation across runs. + host.shadowRoot.adoptedStyleSheets = + host.shadowRoot.adoptedStyleSheets.slice(0, 1); +}, "cloneNode(true) reflects only the shadowrootadoptedstylesheets attribute, not script mutations to adoptedStyleSheets."); + +test(() => { + // Round-trip: serialized clone still carries the attribute. + const host = document.getElementById("host_serializable"); + const clone = host.cloneNode(true); + const html = clone.getHTML({ serializableShadowRoots: true }); + assert_true(html.includes("shadowrootadoptedstylesheets=\"foo\""), + `Clone serializes back with the original attribute value. Got: ${html}`); +}, "cloneNode(true) followed by getHTML() round-trips the shadowrootadoptedstylesheets attribute."); + +test(() => { + // Style application: confirm the resolved sheet in the clone actually + // styles the cloned tree once attached to the document. + const host = document.getElementById("host_basic"); + const clone = host.cloneNode(true); + document.body.appendChild(clone); + try { + const t = clone.shadowRoot.getElementById("t"); + assert_equals(getComputedStyle(t).color, "rgb(0, 0, 255)", + "Clone's adopted stylesheet styles its content."); + } finally { + clone.remove(); + } +}, "Adopted stylesheets resolved from the cloned shadow root style the cloned tree."); + +promise_test(async (t) => { + // Cross-document importNode: the source host lives in an iframe that + // declares its own import map. importNode must resolve specifiers + // against the destination document's import map (not the source's), + // because ResolveAdoptedStyleSheets uses the cloned root's document. + const iframe = document.createElement("iframe"); + iframe.srcdoc = ` + <!DOCTYPE html> + <script type="importmap"> + { "imports": { "iframe-only": "data:text/css,span{color:green}" } } + <\/script> + <body> + <div id="ihost"> + <template shadowrootmode="open" + shadowrootclonable + shadowrootadoptedstylesheets="iframe-only"> + <span id="t">iframe</span> + </template> + </div> + `; + await new Promise(resolve => { + iframe.addEventListener("load", resolve, { once: true }); + document.body.appendChild(iframe); + }); + try { + const sourceHost = iframe.contentDocument.getElementById("ihost"); + assert_equals(sourceHost.shadowRoot.adoptedStyleSheets.length, 1, + "Sanity: source host (iframe-only specifier) resolved in the iframe."); + + // The source specifier is "iframe-only" which exists in the iframe's + // import map but NOT in the parent document's import map. Importing + // into the parent document must therefore produce a placeholder / + // empty resolution — NOT inherit the iframe's resolution. + const importedHost = document.importNode(sourceHost, true); + assert_true(!!importedHost.shadowRoot, + "Imported host has a shadow root."); + // "iframe-only" is not a valid specifier in the parent doc's import + // map, so resolution silently skips it (per ResolveAdoptedStyleSheets: + // invalid specifiers are dropped). The clone's adoptedStyleSheets + // should be empty. + assert_equals(importedHost.shadowRoot.adoptedStyleSheets.length, 0, + "importNode resolves against the destination document's import map; " + + "an iframe-only specifier does not resolve in the parent document."); + document.body.appendChild(importedHost); + try { + assert_equals( + importedHost.shadowRoot.adoptedStyleSheets.length, 0, + "After insertion, no stylesheets resolved from iframe-only specifier." + ); + } finally { + importedHost.remove(); + } + } finally { + iframe.remove(); + } +}, "document.importNode resolves shadowrootadoptedstylesheets against the destination document."); + +promise_test(async (t) => { + // Cross-document importNode where BOTH documents have a matching + // import map entry — the clone resolves against the destination map. + const iframe = document.createElement("iframe"); + iframe.srcdoc = ` + <!DOCTYPE html> + <script type="importmap"> + { "imports": { "shared": "data:text/css,span{color:green}" } } + <\/script> + <body> + <div id="ihost"> + <template shadowrootmode="open" + shadowrootclonable + shadowrootadoptedstylesheets="shared"> + <span id="t">shared-iframe</span> + </template> + </div> + `; + await new Promise(resolve => { + iframe.addEventListener("load", resolve, { once: true }); + document.body.appendChild(iframe); + }); + try { + const sourceHost = iframe.contentDocument.getElementById("ihost"); + assert_equals(sourceHost.shadowRoot.adoptedStyleSheets.length, 1, + "Sanity: source host resolved in the iframe (green)."); + + // The parent document's import map (declared at top of this file) + // does NOT define "shared", so the clone should resolve to nothing. + // (If we wanted same-resolution, we'd add "shared" to the parent + // import map; this test asserts the destination-doc semantic.) + const imported = document.importNode(sourceHost, true); + assert_equals(imported.shadowRoot.adoptedStyleSheets.length, 0, + "Destination document lacks the 'shared' specifier; resolution is empty."); + } finally { + iframe.remove(); + } +}, "document.importNode does NOT inherit the source document's import map resolution."); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/shadow-dom/declarative/tentative/shadowrootadoptedstylesheets/shadowrootadoptedstylesheets-serialization.html b/third_party/blink/web_tests/external/wpt/shadow-dom/declarative/tentative/shadowrootadoptedstylesheets/shadowrootadoptedstylesheets-serialization.html index e36882d8..743ffd8 100644 --- a/third_party/blink/web_tests/external/wpt/shadow-dom/declarative/tentative/shadowrootadoptedstylesheets/shadowrootadoptedstylesheets-serialization.html +++ b/third_party/blink/web_tests/external/wpt/shadow-dom/declarative/tentative/shadowrootadoptedstylesheets/shadowrootadoptedstylesheets-serialization.html
@@ -92,4 +92,69 @@ `ShadowRoot.getHTML() returns children-only markup; must not include the wrapping template attribute. Got: ${html}` ); }, "ShadowRoot.getHTML() returns children-only markup (no wrapping template)."); + +test(() => { + // The shadowrootadoptedstylesheets content attribute is populated only + // by the HTML parser when the declarative <template> is processed. + // Subsequent mutations to ShadowRoot.adoptedStyleSheets (e.g., pushing a + // constructor sheet) update the live IDL list but do NOT update the + // serialized attribute value. As a consequence, script-added sheets are + // necessarily dropped on serialization (and, by extension, on cloneNode + // / setHTMLUnsafe round-trips), since constructor sheets have no URL or + // import-map specifier that could be emitted. + const host = document.getElementById("host_basic"); + const constructed = new CSSStyleSheet(); + constructed.replaceSync("span { font-weight: bold; }"); + const original = Array.from(host.shadowRoot.adoptedStyleSheets); + host.shadowRoot.adoptedStyleSheets = [...original, constructed]; + try { + assert_equals(host.shadowRoot.adoptedStyleSheets.length, 2, + "Sanity: live adoptedStyleSheets reflects the script mutation."); + const html = host.getHTML(opts); + assert_true( + html.includes("shadowrootadoptedstylesheets=\"foo\""), + `Serialized markup must still emit the original attribute value. Got: ${html}` + ); + // The constructor sheet's rule must not leak into the serialized + // markup in any form (it has no URL / specifier representation). + assert_false( + html.includes("font-weight"), + `Serialized markup must not contain text from the script-added constructor sheet. Got: ${html}` + ); + // No second occurrence of the attribute either (the serializer emits + // it once, regardless of the live list length). + assert_equals( + (html.match(/shadowrootadoptedstylesheets/g) || []).length, 1, + `shadowrootadoptedstylesheets attribute must appear exactly once. Got: ${html}` + ); + } finally { + host.shadowRoot.adoptedStyleSheets = original; + } +}, "getHTML() ignores script-added entries in adoptedStyleSheets and emits only the authored shadowrootadoptedstylesheets value."); + +test(() => { + // Same invariant when the authored value is the present-but-empty form: + // pushing a constructor sheet does not promote the empty attribute to a + // non-empty one in the serialized markup. + const host = document.getElementById("host_empty"); + const constructed = new CSSStyleSheet(); + constructed.replaceSync("span { font-style: italic; }"); + const original = Array.from(host.shadowRoot.adoptedStyleSheets); + host.shadowRoot.adoptedStyleSheets = [...original, constructed]; + try { + assert_equals(host.shadowRoot.adoptedStyleSheets.length, 1, + "Sanity: live adoptedStyleSheets reflects the script mutation."); + const html = host.getHTML(opts); + assert_true( + html.includes("shadowrootadoptedstylesheets=\"\""), + `Empty authored value must round-trip as present-and-empty even after script mutation. Got: ${html}` + ); + assert_false( + html.includes("font-style"), + `Constructor-sheet rule text must not appear in serialized markup. Got: ${html}` + ); + } finally { + host.shadowRoot.adoptedStyleSheets = original; + } +}, "getHTML() with an empty authored shadowrootadoptedstylesheets value is unaffected by script mutations."); </script>
diff --git a/third_party/blink/web_tests/external/wpt/shadow-dom/nested-hover-pseudo-class-removal.html b/third_party/blink/web_tests/external/wpt/shadow-dom/nested-hover-pseudo-class-removal.html new file mode 100644 index 0000000..8b66c86 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/shadow-dom/nested-hover-pseudo-class-removal.html
@@ -0,0 +1,45 @@ +<!DOCTYPE html> +<html class="reftest-wait"> +<meta charset="utf-8"> +<title>Shadow DOM: :hover pseudo-class should be removed from all ancestors when cursor moves away</title> +<link rel="author" href="mailto:martin@abandonedwig.info"> +<link rel="help" href="https://drafts.csswg.org/selectors/#the-hover-pseudo"> +<link rel="help" href="https://github.com/servo/servo/issues/43863"> +<link rel="match" href="/css/reference/ref-filled-green-100px-square.xht"> +<script src="/common/reftest-wait.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> + +<style> + #host { + width: 100px; + height: 100px; + background: green; + } + + #host:hover { + background:red; + } +</style> + +<p>Test passes if there is a filled green square and <strong>no red</strong>.</p> +<div id="host"> + <template shadowrootmode="open"> + <div style="width: 100px; height: 100px"></div> + </template> +</div> + +<script> + window.onload = async () => { + let rectangle = host.getBoundingClientRect(); + await new test_driver.Actions() + .pointerMove(rectangle.left + 5, rectangle.top + 5) + .send(); + await new test_driver.Actions() + .pointerMove(rectangle.right + 100, rectangle.bottom + 100) + .send(); + takeScreenshot(); + } +</script> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/streams/readable-streams/from.any-expected.txt b/third_party/blink/web_tests/external/wpt/streams/readable-streams/from.any-expected.txt index 9045cde..ccbc6617 100644 --- a/third_party/blink/web_tests/external/wpt/streams/readable-streams/from.any-expected.txt +++ b/third_party/blink/web_tests/external/wpt/streams/readable-streams/from.any-expected.txt
@@ -1,4 +1,5 @@ This is a testharness.js-based test. +Found 37 FAIL, 0 TIMEOUT, 0 NOTRUN. [FAIL] ReadableStream.from accepts an array of values promise_test: Unhandled rejection with value: object "TypeError: ReadableStream.from is not a function" [FAIL] ReadableStream.from accepts an array of promises @@ -19,8 +20,12 @@ promise_test: Unhandled rejection with value: object "TypeError: ReadableStream.from is not a function" [FAIL] ReadableStream.from accepts a sync iterable of promises promise_test: Unhandled rejection with value: object "TypeError: ReadableStream.from is not a function" +[FAIL] ReadableStream.from accepts a sync iterable with a function iterator + promise_test: Unhandled rejection with value: object "TypeError: ReadableStream.from is not a function" [FAIL] ReadableStream.from accepts an async iterable promise_test: Unhandled rejection with value: object "TypeError: ReadableStream.from is not a function" +[FAIL] ReadableStream.from accepts an async iterable with a function iterator + promise_test: Unhandled rejection with value: object "TypeError: ReadableStream.from is not a function" [FAIL] ReadableStream.from accepts a ReadableStream promise_test: Unhandled rejection with value: object "TypeError: ReadableStream.from is not a function" [FAIL] ReadableStream.from accepts a ReadableStream async iterator @@ -70,3 +75,4 @@ [FAIL] ReadableStream.from(array), push() to array while reading promise_test: Unhandled rejection with value: object "TypeError: ReadableStream.from is not a function" Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/streams/readable-streams/from.any.js b/third_party/blink/web_tests/external/wpt/streams/readable-streams/from.any.js index 2b28a05..77f2bbf 100644 --- a/third_party/blink/web_tests/external/wpt/streams/readable-streams/from.any.js +++ b/third_party/blink/web_tests/external/wpt/streams/readable-streams/from.any.js
@@ -81,6 +81,19 @@ return iterable; }], + ['a sync iterable with a function iterator', () => { + const chunks = ['a', 'b']; + function functionIterator() {} + functionIterator.next = () => ({ + done: chunks.length === 0, + value: chunks.shift() + }); + const iterable = { + [Symbol.iterator]: () => functionIterator + }; + return iterable; + }], + ['an async iterable', () => { const chunks = ['a', 'b']; const asyncIterator = { @@ -97,6 +110,19 @@ return asyncIterable; }], + ['an async iterable with a function iterator', () => { + const chunks = ['a', 'b']; + function functionAsyncIterator() {} + functionAsyncIterator.next = () => Promise.resolve({ + done: chunks.length === 0, + value: chunks.shift() + }); + const asyncIterable = { + [Symbol.asyncIterator]: () => functionAsyncIterator + }; + return asyncIterable; + }], + ['a ReadableStream', () => { return new ReadableStream({ start(c) {
diff --git a/third_party/blink/web_tests/external/wpt/streams/readable-streams/from.any.serviceworker-expected.txt b/third_party/blink/web_tests/external/wpt/streams/readable-streams/from.any.serviceworker-expected.txt index 9045cde..ccbc6617 100644 --- a/third_party/blink/web_tests/external/wpt/streams/readable-streams/from.any.serviceworker-expected.txt +++ b/third_party/blink/web_tests/external/wpt/streams/readable-streams/from.any.serviceworker-expected.txt
@@ -1,4 +1,5 @@ This is a testharness.js-based test. +Found 37 FAIL, 0 TIMEOUT, 0 NOTRUN. [FAIL] ReadableStream.from accepts an array of values promise_test: Unhandled rejection with value: object "TypeError: ReadableStream.from is not a function" [FAIL] ReadableStream.from accepts an array of promises @@ -19,8 +20,12 @@ promise_test: Unhandled rejection with value: object "TypeError: ReadableStream.from is not a function" [FAIL] ReadableStream.from accepts a sync iterable of promises promise_test: Unhandled rejection with value: object "TypeError: ReadableStream.from is not a function" +[FAIL] ReadableStream.from accepts a sync iterable with a function iterator + promise_test: Unhandled rejection with value: object "TypeError: ReadableStream.from is not a function" [FAIL] ReadableStream.from accepts an async iterable promise_test: Unhandled rejection with value: object "TypeError: ReadableStream.from is not a function" +[FAIL] ReadableStream.from accepts an async iterable with a function iterator + promise_test: Unhandled rejection with value: object "TypeError: ReadableStream.from is not a function" [FAIL] ReadableStream.from accepts a ReadableStream promise_test: Unhandled rejection with value: object "TypeError: ReadableStream.from is not a function" [FAIL] ReadableStream.from accepts a ReadableStream async iterator @@ -70,3 +75,4 @@ [FAIL] ReadableStream.from(array), push() to array while reading promise_test: Unhandled rejection with value: object "TypeError: ReadableStream.from is not a function" Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/streams/readable-streams/from.any.sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/streams/readable-streams/from.any.sharedworker-expected.txt index 9045cde..ccbc6617 100644 --- a/third_party/blink/web_tests/external/wpt/streams/readable-streams/from.any.sharedworker-expected.txt +++ b/third_party/blink/web_tests/external/wpt/streams/readable-streams/from.any.sharedworker-expected.txt
@@ -1,4 +1,5 @@ This is a testharness.js-based test. +Found 37 FAIL, 0 TIMEOUT, 0 NOTRUN. [FAIL] ReadableStream.from accepts an array of values promise_test: Unhandled rejection with value: object "TypeError: ReadableStream.from is not a function" [FAIL] ReadableStream.from accepts an array of promises @@ -19,8 +20,12 @@ promise_test: Unhandled rejection with value: object "TypeError: ReadableStream.from is not a function" [FAIL] ReadableStream.from accepts a sync iterable of promises promise_test: Unhandled rejection with value: object "TypeError: ReadableStream.from is not a function" +[FAIL] ReadableStream.from accepts a sync iterable with a function iterator + promise_test: Unhandled rejection with value: object "TypeError: ReadableStream.from is not a function" [FAIL] ReadableStream.from accepts an async iterable promise_test: Unhandled rejection with value: object "TypeError: ReadableStream.from is not a function" +[FAIL] ReadableStream.from accepts an async iterable with a function iterator + promise_test: Unhandled rejection with value: object "TypeError: ReadableStream.from is not a function" [FAIL] ReadableStream.from accepts a ReadableStream promise_test: Unhandled rejection with value: object "TypeError: ReadableStream.from is not a function" [FAIL] ReadableStream.from accepts a ReadableStream async iterator @@ -70,3 +75,4 @@ [FAIL] ReadableStream.from(array), push() to array while reading promise_test: Unhandled rejection with value: object "TypeError: ReadableStream.from is not a function" Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/streams/readable-streams/from.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/streams/readable-streams/from.any.worker-expected.txt index 9045cde..ccbc6617 100644 --- a/third_party/blink/web_tests/external/wpt/streams/readable-streams/from.any.worker-expected.txt +++ b/third_party/blink/web_tests/external/wpt/streams/readable-streams/from.any.worker-expected.txt
@@ -1,4 +1,5 @@ This is a testharness.js-based test. +Found 37 FAIL, 0 TIMEOUT, 0 NOTRUN. [FAIL] ReadableStream.from accepts an array of values promise_test: Unhandled rejection with value: object "TypeError: ReadableStream.from is not a function" [FAIL] ReadableStream.from accepts an array of promises @@ -19,8 +20,12 @@ promise_test: Unhandled rejection with value: object "TypeError: ReadableStream.from is not a function" [FAIL] ReadableStream.from accepts a sync iterable of promises promise_test: Unhandled rejection with value: object "TypeError: ReadableStream.from is not a function" +[FAIL] ReadableStream.from accepts a sync iterable with a function iterator + promise_test: Unhandled rejection with value: object "TypeError: ReadableStream.from is not a function" [FAIL] ReadableStream.from accepts an async iterable promise_test: Unhandled rejection with value: object "TypeError: ReadableStream.from is not a function" +[FAIL] ReadableStream.from accepts an async iterable with a function iterator + promise_test: Unhandled rejection with value: object "TypeError: ReadableStream.from is not a function" [FAIL] ReadableStream.from accepts a ReadableStream promise_test: Unhandled rejection with value: object "TypeError: ReadableStream.from is not a function" [FAIL] ReadableStream.from accepts a ReadableStream async iterator @@ -70,3 +75,4 @@ [FAIL] ReadableStream.from(array), push() to array while reading promise_test: Unhandled rejection with value: object "TypeError: ReadableStream.from is not a function" Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/svg/animations/animate-path-additive-sum-both-empty-over-base.tentative.html b/third_party/blink/web_tests/external/wpt/svg/animations/animate-path-additive-sum-both-empty-over-base.tentative.html new file mode 100644 index 0000000..3398f9e --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/svg/animations/animate-path-additive-sum-both-empty-over-base.tentative.html
@@ -0,0 +1,33 @@ +<!doctype html> +<title>SVG path 'd' additive animation with both-empty over non-empty base</title> +<link rel="help" href="https://svgwg.org/svg2-draft/paths.html#TheDProperty"/> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/SVGAnimationTestCase-testharness.js"></script> +<script src="support/animated-path-helpers.js"></script> +<svg> + <path id="path" fill="green" d="M 10 10 L 90 10 L 90 90 L 10 90 Z"> + <animate id="animation" attributeName="d" + from="" to="" additive="sum" + begin="0s" dur="4s" fill="freeze"/> + </path> +</svg> +<script> +const rootSVGElement = document.querySelector("svg"); + +// Additive animation where both from and to are empty. The empty result cannot +// be added to the non-empty base, so the animation fails and the base value is +// preserved throughout. +function sample1() { + assert_animated_path_equals(path, "M 10 10 L 90 10 L 90 90 L 10 90 Z"); +} + +smil_async_test((t) => { + const expectedValues = [ + ["animation", 0.001, sample1], + ["animation", 2.0, sample1], + ["animation", 3.999, sample1], + ]; + runAnimationTest(t, expectedValues); +}); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/svg/animations/animate-path-by-animation-empty-base.tentative.html b/third_party/blink/web_tests/external/wpt/svg/animations/animate-path-by-animation-empty-base.tentative.html new file mode 100644 index 0000000..c674aa1f --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/svg/animations/animate-path-by-animation-empty-base.tentative.html
@@ -0,0 +1,33 @@ +<!doctype html> +<title>SVG path 'd' by-animation with empty base value</title> +<link rel="help" href="https://svgwg.org/svg2-draft/paths.html#TheDProperty"/> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/SVGAnimationTestCase-testharness.js"></script> +<script src="support/animated-path-helpers.js"></script> +<svg> + <path id="path" fill="green" d=""> + <animate id="animation" attributeName="d" + by="M 0 0 L 100 0 L 100 100 L 0 100 Z" + begin="0s" dur="4s" fill="freeze"/> + </path> +</svg> +<script> +const rootSVGElement = document.querySelector("svg"); + +// by-animation is additive. An empty base path cannot be added to a non-empty +// by value (structurally incompatible), so the animation fails and the base +// value is preserved. +function sample1() { + assert_animated_path_equals(path, ""); +} + +smil_async_test((t) => { + const expectedValues = [ + ["animation", 0.001, sample1], + ["animation", 2.0, sample1], + ["animation", 3.999, sample1], + ]; + runAnimationTest(t, expectedValues); +}); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/svg/animations/animate-path-from-by-animation-both-empty.tentative.html b/third_party/blink/web_tests/external/wpt/svg/animations/animate-path-from-by-animation-both-empty.tentative.html new file mode 100644 index 0000000..9a1b4c8 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/svg/animations/animate-path-from-by-animation-both-empty.tentative.html
@@ -0,0 +1,32 @@ +<!doctype html> +<title>SVG path 'd' from-by animation with both values empty</title> +<link rel="help" href="https://svgwg.org/svg2-draft/paths.html#TheDProperty"/> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/SVGAnimationTestCase-testharness.js"></script> +<script src="support/animated-path-helpers.js"></script> +<svg> + <path id="path" fill="green" d="M 40 40 L 60 40 L 60 60 L 40 60 Z"> + <animate id="animation" attributeName="d" + from="" by="" + begin="0s" dur="4s" fill="freeze"/> + </path> +</svg> +<script> +const rootSVGElement = document.querySelector("svg"); + +// from-by with both empty: the empty by value cannot be added to the from +// value, so the animation is invalid. The base value is preserved throughout. +function sample1() { + assert_animated_path_equals(path, "M 40 40 L 60 40 L 60 60 L 40 60 Z"); +} + +smil_async_test((t) => { + const expectedValues = [ + ["animation", 0.001, sample1], + ["animation", 2.0, sample1], + ["animation", 3.999, sample1], + ]; + runAnimationTest(t, expectedValues); +}); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/svg/animations/animate-path-from-by-animation-empty-by.tentative.html b/third_party/blink/web_tests/external/wpt/svg/animations/animate-path-from-by-animation-empty-by.tentative.html new file mode 100644 index 0000000..9079965 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/svg/animations/animate-path-from-by-animation-empty-by.tentative.html
@@ -0,0 +1,32 @@ +<!doctype html> +<title>SVG path 'd' from-by animation with empty 'by' value</title> +<link rel="help" href="https://svgwg.org/svg2-draft/paths.html#TheDProperty"/> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/SVGAnimationTestCase-testharness.js"></script> +<script src="support/animated-path-helpers.js"></script> +<svg> + <path id="path" fill="green" d="M 40 40 L 60 40 L 60 60 L 40 60 Z"> + <animate id="animation" attributeName="d" + from="M 10 10 L 90 10 L 90 90 L 10 90 Z" by="" + begin="0s" dur="4s" fill="freeze"/> + </path> +</svg> +<script> +const rootSVGElement = document.querySelector("svg"); + +// from-by with empty by: the empty by value cannot be added to the from +// value, so the animation is invalid. The base value is preserved throughout. +function sample1() { + assert_animated_path_equals(path, "M 40 40 L 60 40 L 60 60 L 40 60 Z"); +} + +smil_async_test((t) => { + const expectedValues = [ + ["animation", 0.001, sample1], + ["animation", 2.0, sample1], + ["animation", 3.999, sample1], + ]; + runAnimationTest(t, expectedValues); +}); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/svg/animations/animate-path-from-by-animation-empty-from.tentative.html b/third_party/blink/web_tests/external/wpt/svg/animations/animate-path-from-by-animation-empty-from.tentative.html new file mode 100644 index 0000000..ac380415 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/svg/animations/animate-path-from-by-animation-empty-from.tentative.html
@@ -0,0 +1,32 @@ +<!doctype html> +<title>SVG path 'd' from-by animation with empty 'from' value</title> +<link rel="help" href="https://svgwg.org/svg2-draft/paths.html#TheDProperty"/> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/SVGAnimationTestCase-testharness.js"></script> +<script src="support/animated-path-helpers.js"></script> +<svg> + <path id="path" fill="green" d="M 40 40 L 60 40 L 60 60 L 40 60 Z"> + <animate id="animation" attributeName="d" + from="" by="M 0 0 L 100 0 L 100 100 L 0 100 Z" + begin="0s" dur="4s" fill="freeze"/> + </path> +</svg> +<script> +const rootSVGElement = document.querySelector("svg"); + +// from-by with empty from: the by value can't be added to an empty from, +// so the animation is invalid. The base value is preserved throughout. +function sample1() { + assert_animated_path_equals(path, "M 40 40 L 60 40 L 60 60 L 40 60 Z"); +} + +smil_async_test((t) => { + const expectedValues = [ + ["animation", 0.001, sample1], + ["animation", 2.0, sample1], + ["animation", 3.999, sample1], + ]; + runAnimationTest(t, expectedValues); +}); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/svg/animations/animate-path-from-to-animation-both-empty.tentative.html b/third_party/blink/web_tests/external/wpt/svg/animations/animate-path-from-to-animation-both-empty.tentative.html new file mode 100644 index 0000000..82c4c96d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/svg/animations/animate-path-from-to-animation-both-empty.tentative.html
@@ -0,0 +1,31 @@ +<!doctype html> +<title>SVG path 'd' from-to animation with both values empty</title> +<link rel="help" href="https://svgwg.org/svg2-draft/paths.html#TheDProperty"/> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/SVGAnimationTestCase-testharness.js"></script> +<script src="support/animated-path-helpers.js"></script> +<svg> + <path id="path" fill="green" d="M 40 40 L 60 40 L 60 60 L 40 60 Z"> + <animate id="animation" attributeName="d" + from="" to="" + begin="0s" dur="4s" fill="freeze"/> + </path> +</svg> +<script> +const rootSVGElement = document.querySelector("svg"); + +// Both from and to are empty; the animated value is empty throughout. +function sample1() { + assert_animated_path_equals(path, ""); +} + +smil_async_test((t) => { + const expectedValues = [ + ["animation", 0.001, sample1], + ["animation", 2.0, sample1], + ["animation", 3.999, sample1], + ]; + runAnimationTest(t, expectedValues); +}); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/svg/animations/animate-path-from-to-animation-empty-from.tentative.html b/third_party/blink/web_tests/external/wpt/svg/animations/animate-path-from-to-animation-empty-from.tentative.html new file mode 100644 index 0000000..37ce541 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/svg/animations/animate-path-from-to-animation-empty-from.tentative.html
@@ -0,0 +1,36 @@ +<!doctype html> +<title>SVG path 'd' from-to animation with empty 'from' value</title> +<link rel="help" href="https://svgwg.org/svg2-draft/paths.html#TheDProperty"/> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/SVGAnimationTestCase-testharness.js"></script> +<script src="support/animated-path-helpers.js"></script> +<svg> + <path id="path" fill="green" d="M 40 40 L 60 40 L 60 60 L 40 60 Z"> + <animate id="animation" attributeName="d" + from="" to="M 0 0 L 100 0 L 100 100 L 0 100 Z" + begin="0s" dur="4s" fill="freeze"/> + </path> +</svg> +<script> +const rootSVGElement = document.querySelector("svg"); + +// Empty from and non-empty to are structurally incompatible; discrete at 50%. +function sample1() { + assert_animated_path_equals(path, ""); +} + +function sample2() { + assert_animated_path_equals(path, "M 0 0 L 100 0 L 100 100 L 0 100 Z"); +} + +smil_async_test((t) => { + const expectedValues = [ + ["animation", 0.001, sample1], + ["animation", 1.999, sample1], + ["animation", 2.001, sample2], + ["animation", 3.999, sample2], + ]; + runAnimationTest(t, expectedValues); +}); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/svg/animations/animate-path-from-to-animation-empty-to.tentative.html b/third_party/blink/web_tests/external/wpt/svg/animations/animate-path-from-to-animation-empty-to.tentative.html new file mode 100644 index 0000000..4598acf --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/svg/animations/animate-path-from-to-animation-empty-to.tentative.html
@@ -0,0 +1,36 @@ +<!doctype html> +<title>SVG path 'd' from-to animation with empty 'to' value</title> +<link rel="help" href="https://svgwg.org/svg2-draft/paths.html#TheDProperty"/> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/SVGAnimationTestCase-testharness.js"></script> +<script src="support/animated-path-helpers.js"></script> +<svg> + <path id="path" fill="green" d="M 40 40 L 60 40 L 60 60 L 40 60 Z"> + <animate id="animation" attributeName="d" + from="M 0 0 L 100 0 L 100 100 L 0 100 Z" to="" + begin="0s" dur="4s" fill="freeze"/> + </path> +</svg> +<script> +const rootSVGElement = document.querySelector("svg"); + +// Non-empty from and empty to are structurally incompatible; discrete at 50%. +function sample1() { + assert_animated_path_equals(path, "M 0 0 L 100 0 L 100 100 L 0 100 Z"); +} + +function sample2() { + assert_animated_path_equals(path, ""); +} + +smil_async_test((t) => { + const expectedValues = [ + ["animation", 0.001, sample1], + ["animation", 1.999, sample1], + ["animation", 2.001, sample2], + ["animation", 3.999, sample2], + ]; + runAnimationTest(t, expectedValues); +}); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/svg/animations/animate-path-to-animation-empty-base.tentative.html b/third_party/blink/web_tests/external/wpt/svg/animations/animate-path-to-animation-empty-base.tentative.html new file mode 100644 index 0000000..c40478c4 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/svg/animations/animate-path-to-animation-empty-base.tentative.html
@@ -0,0 +1,37 @@ +<!doctype html> +<title>SVG path 'd' to-animation with empty base value</title> +<link rel="help" href="https://svgwg.org/svg2-draft/paths.html#TheDProperty"/> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/SVGAnimationTestCase-testharness.js"></script> +<script src="support/animated-path-helpers.js"></script> +<svg> + <path id="path" fill="green" d=""> + <animate id="animation" attributeName="d" + to="M 0 0 L 100 0 L 100 100 L 0 100 Z" + begin="0s" dur="4s" fill="freeze"/> + </path> +</svg> +<script> +const rootSVGElement = document.querySelector("svg"); + +// to-animation uses the base value as implicit from. Base is empty (d=""), +// which is structurally incompatible with the to value; discrete at 50%. +function sample1() { + assert_animated_path_equals(path, ""); +} + +function sample2() { + assert_animated_path_equals(path, "M 0 0 L 100 0 L 100 100 L 0 100 Z"); +} + +smil_async_test((t) => { + const expectedValues = [ + ["animation", 0.001, sample1], + ["animation", 1.999, sample1], + ["animation", 2.001, sample2], + ["animation", 3.999, sample2], + ]; + runAnimationTest(t, expectedValues); +}); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGGraphicsElement.getBBox-05.html b/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGGraphicsElement.getBBox-05.html index 8c0d11e..af25641d 100644 --- a/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGGraphicsElement.getBBox-05.html +++ b/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGGraphicsElement.getBBox-05.html
@@ -396,15 +396,15 @@ test(t => { let opt = { fill: true, stroke: true, markers: true, clipped: true }; - assert_bbox("path1", opt, 6.2, 20.8, 115.8, 91.2, 0.1); - assert_bbox("path2", opt, 156.2, 20.8, 115.8, 91.2, 0.1); - assert_bbox("path3", opt, 6.2, 120.7, 115.8, 91.2, 0.1); - assert_bbox("path4", opt, 6.2, 20.8, 93.8, 79.2, 0.1); - assert_bbox("path5", opt, 156.2, 20.8, 43.8, 79.2, 0.1); + assert_bbox("path1", opt, 6.2, 21, 115.8, 91, 0.1); + assert_bbox("path2", opt, 156.2, 21, 115.8, 91, 0.1); + assert_bbox("path3", opt, 6.2, 121, 115.8, 91, 0.1); + assert_bbox("path4", opt, 6.2, 21, 93.8, 79, 0.1); + assert_bbox("path5", opt, 156.2, 21, 43.8, 79, 0.1); assert_bbox("path6", opt, 6.2, 150, 93.8, 62, 0.1); - assert_bbox("path7", opt, 6.2, 20.8, 93.8, 79.2, 0.1); - assert_bbox("path8", opt, 156.2, 20.8, 93.8, 79.2, 0.1); - assert_bbox("path9", opt, 6.2, 120.8, 93.8, 79.2, 0.1); + assert_bbox("path7", opt, 6.2, 21, 93.8, 79, 0.1); + assert_bbox("path8", opt, 156.2, 21, 93.8, 79, 0.1); + assert_bbox("path9", opt, 6.2, 121, 93.8, 79, 0.1); assert_bbox("path10", opt, 10, 25, 100, 75); assert_bbox("path11", opt, 160, 25, 100, 75); assert_bbox("path12", opt, 10, 125, 100, 75); @@ -445,18 +445,18 @@ test(t => { let opt = { fill: false, stroke: true, markers: false, clipped: false }; - assert_bbox("path1", opt, 6.2, 20.8, 107.8, 83.2, 0.1); - assert_bbox("path2", opt, 156.2, 20.8, 107.8, 83.2, 0.1); - assert_bbox("path3", opt, 6.2, 120.8, 107.8, 83.2, 0.1); - assert_bbox("path4", opt, 6.2, 20.8, 107.8, 83.2, 0.1); - assert_bbox("path5", opt, 156.2, 20.8, 107.8, 83.2, 0.1); - assert_bbox("path6", opt, 6.2, 120.8, 107.8, 83.2, 0.1); - assert_bbox("path7", opt, 6.2, 20.8, 107.8, 83.2, 0.1); - assert_bbox("path8", opt, 156.2, 20.8, 107.8, 83.2, 0.1); - assert_bbox("path9", opt, 6.2, 120.8, 107.8, 83.2, 0.1); - assert_bbox("path10", opt, 6.2, 20.8, 107.8, 83.2, 0.1); - assert_bbox("path11", opt, 156.2, 20.8, 107.8, 83.2, 0.1); - assert_bbox("path12", opt, 6.2, 120.8, 107.8, 83.2, 0.1); + assert_bbox("path1", opt, 6.2, 21, 107.8, 83, 0.1); + assert_bbox("path2", opt, 156.2, 21, 107.8, 83, 0.1); + assert_bbox("path3", opt, 6.2, 121, 107.8, 83, 0.1); + assert_bbox("path4", opt, 6.2, 21, 107.8, 83, 0.1); + assert_bbox("path5", opt, 156.2, 21, 107.8, 83, 0.1); + assert_bbox("path6", opt, 6.2, 121, 107.8, 83, 0.1); + assert_bbox("path7", opt, 6.2, 21, 107.8, 83, 0.1); + assert_bbox("path8", opt, 156.2, 21, 107.8, 83, 0.1); + assert_bbox("path9", opt, 6.2, 121, 107.8, 83, 0.1); + assert_bbox("path10", opt, 6.2, 21, 107.8, 83, 0.1); + assert_bbox("path11", opt, 156.2, 21, 107.8, 83, 0.1); + assert_bbox("path12", opt, 6.2, 121, 107.8, 83, 0.1); }, "path with stroke"); test(t => {
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-secondary-document-expected.txt b/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-secondary-document-expected.txt new file mode 100644 index 0000000..4481d22 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-secondary-document-expected.txt
@@ -0,0 +1,6 @@ +This is a testharness.js-based test. +Found 1 FAIL, 0 TIMEOUT, 0 NOTRUN. +[FAIL] Document execCommand throws with a plain string + assert_throws_js: function "_ => {\n secondaryDocument.execCommand("insertHTML", false, "2+2");\n }" did not throw +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-secondary-document.html b/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-secondary-document.html new file mode 100644 index 0000000..01dd93d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-secondary-document.html
@@ -0,0 +1,340 @@ +<!DOCTYPE html> +<head> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="support/namespaces.js"></script> + <meta http-equiv="Content-Security-Policy" content="require-trusted-types-for 'script'"> +</head> +<body> +<script> +const policyWithoutModification = + window.trustedTypes.createPolicy('policyWithoutModification', { + createHTML: s => s, + createScript: s => s, + createScriptURL: s => s, + }); + +function createTrustedOutput(type, input) { + return type ? + policyWithoutModification[type.replace("Trusted", "create")](input) : input; +} + +const secondaryDocument = document.implementation.createHTMLDocument(""); +const testData = [ + { + name: "HTMLElement innerHTML", + subject: () => secondaryDocument.createElement("div"), + property: "innerHTML", + type: "TrustedHTML", + }, + { + name: "HTMLElement setHTMLUnsafe", + subject: () => secondaryDocument.createElement("div"), + method: "setHTMLUnsafe", + type: "TrustedHTML", + }, + { + name: "ShadowRoot innerHTML", + subject: () => { + const div = secondaryDocument.createElement("div"); + return div.attachShadow({mode: 'open'}); + }, + property: "innerHTML", + type: "TrustedHTML", + }, + { + name: "ShadowRoot setHTMLUnsafe", + subject: () => { + const div = secondaryDocument.createElement("div"); + return div.attachShadow({mode: 'open'}); + }, + method: "setHTMLUnsafe", + type: "TrustedHTML", + }, + { + name: "HTMLIFrameElement srcdoc", + subject: () => secondaryDocument.createElement("iframe"), + property: "srcdoc", + type: "TrustedHTML", + }, + { + name: "HTMLScriptElement textContent", + subject: () => secondaryDocument.createElement("script"), + property: "textContent", + type: "TrustedScript", + }, + { + name: "HTMLScriptElement innerText", + subject: () => secondaryDocument.createElement("script"), + property: "innerText", + type: "TrustedScript", + }, + { + name: "HTMLScriptElement text", + subject: () => secondaryDocument.createElement("script"), + property: "text", + type: "TrustedScript", + }, +]; + +for (let entry of testData) { + test(_ => { + const subject = entry.subject(); + assert_throws_js(TypeError, _ => { + if (entry.property) + subject[entry.property] = "2+2"; + else if (entry.method) + subject[entry.method]("2+2"); + }); + }, entry.name + " throws with a plain string"); +} + +test(_ => { + assert_throws_js(TypeError, _ => { + let element = secondaryDocument.createElement("div"); + element.insertAdjacentHTML("afterbegin", "2+2"); + }); +}, "Element insertAdjacentHTML throws with a plain string"); + +test(_ => { + assert_throws_js(TypeError, _ => { + secondaryDocument.execCommand("insertHTML", false, "2+2"); + }); +}, "Document execCommand throws with a plain string"); + +test(_ => { + assert_throws_js(TypeError, _ => { + let range = secondaryDocument.createRange(); + range.selectNodeContents(secondaryDocument.documentElement); + range.createContextualFragment("2+2"); + }); +}, "Range createContextualFragment throws with a plain string"); + +for (let entry of testData) { + test(_ => { + const subject = entry.subject(); + let trustedInput = createTrustedOutput(entry.type, "somevalue"); + if (entry.property) + subject[entry.property] = trustedInput; + else if (entry.method) + subject[entry.method](trustedInput); + }, entry.name + " works with a " + entry.type); +} + +test(_ => { + let trustedInput = createTrustedOutput("TrustedHTML", "somevalue"); + let element = secondaryDocument.createElement("div"); + element.insertAdjacentHTML("afterbegin", trustedInput); +}, "Element insertAdjacentHTML works with a TrustedHTML"); + +test(_ => { + let trustedInput = createTrustedOutput("TrustedHTML", "somevalue"); + secondaryDocument.execCommand("insertHTML", false, trustedInput); +}, "Document execCommand works with a TrustedHTML"); + +test(_ => { + assert_throws_js(TypeError, _ => { + let range = secondaryDocument.createRange(); + range.selectNodeContents(secondaryDocument.documentElement); + range.createContextualFragment("1+1"); + }); +}, "Trusted Type assignment required for Range createContextualFragment"); + +const trustedTypeDataForAttribute = [ + { + element: _ => secondaryDocument.createElement("div"), + attrNS: null, + attrName: "onclick", + sink: "Element onclick", + type: "TrustedScript" + }, + { + element: _ => secondaryDocument.createElementNS(NSURI_SVG, "g"), + attrNS: null, + attrName: "ondblclick", + sink: "Element ondblclick", + type: "TrustedScript" + }, + { + element: _ => secondaryDocument.createElementNS(NSURI_MATHML, "mrow"), + attrNS: null, + attrName: "onmousedown", + sink: "Element onmousedown", + type: "TrustedScript" + }, + { + element: _ => secondaryDocument.createElement("iframe"), + attrNS: null, + attrName: "srcdoc", + sink: "HTMLIFrameElement srcdoc", + type: "TrustedHTML" + }, + { + element: _ => secondaryDocument.createElement("script"), + attrNS: null, + attrName: "src", + sink: "HTMLScriptElement src", + type: "TrustedScriptURL" + }, + { + element: _ => secondaryDocument.createElementNS(NSURI_SVG, "script"), + attrNS: null, + attrName: "href", + sink: "SVGScriptElement href", + type: "TrustedScriptURL" + }, + { + element: _ => secondaryDocument.createElementNS(NSURI_SVG, "script"), + attrNS: NSURI_XLINK, + attrName: "href", + sink: "SVGScriptElement href", + type: "TrustedScriptURL" + }, +]; + +function findAttribute(element, attrNS, attrName) { + for (let i = 0; i < element.attributes.length; i++) { + let attr = element.attributes[i]; + if (attr.namespaceURI === attrNS && + attr.localName === attrName) { + return attr; + } + } +} + +const attributeSetterData = [ + { + api: "Element.setAttribute", + acceptNS: false, + acceptTrustedTypeArgumentInIDL: true, + runSetter: function(element, attrNS, attrName, attrValue) { + assert_equals(attrNS, null); + this.lastAttributeNode = findAttribute(element, attrNS, attrName); + return element.setAttribute(attrName, attrValue); + }, + }, + { + api: "Element.setAttributeNS", + acceptNS: true, + acceptTrustedTypeArgumentInIDL: true, + runSetter: function(element, attrNS, attrName, attrValue) { + this.lastAttributeNode = findAttribute(element, attrNS, attrName); + return element.setAttributeNS(attrNS, attrName, attrValue); + }, + }, + { + api: "Element.setAttributeNode", + acceptNS: true, + setterClass: "setAttributeNode", + runSetter: function(element, attrNS, attrName, attrValue, type) { + this.lastAttributeNode = secondaryDocument.createAttributeNS(attrNS, attrName); + this.lastAttributeNode.value = attrValue; + return element.setAttributeNode(this.lastAttributeNode); + }, + }, + { + api: "Element.setAttributeNodeNS", + acceptNS: true, + runSetter: function(element, attrNS, attrName, attrValue, type) { + this.lastAttributeNode = document.createAttributeNS(attrNS, attrName); + this.lastAttributeNode.value = attrValue; + return element.setAttributeNodeNS(this.lastAttributeNode); + }, + }, + { + api: "NamedNodeMap.setNamedItem", + acceptNS: true, + runSetter: function(element, attrNS, attrName, attrValue, type) { + const nodeMap = element.attributes; + this.lastAttributeNode = secondaryDocument.createAttributeNS(attrNS, attrName); + this.lastAttributeNode.value = attrValue; + return nodeMap.setNamedItem(this.lastAttributeNode); + }, + }, + { + api: "NamedNodeMap.setNamedItemNS", + acceptNS: true, + runSetter: function(element, attrNS, attrName, attrValue, type) { + const nodeMap = element.attributes; + this.lastAttributeNode = secondaryDocument.createAttributeNS(attrNS, attrName); + this.lastAttributeNode.value = attrValue; + return nodeMap.setNamedItemNS(this.lastAttributeNode); + }, + }, + { + api:"Attr.value", + acceptNS: true, + runSetter: function(element, attrNS, attrName, attrValue, type) { + element.setAttributeNS(attrNS, attrName, createTrustedOutput(type, "")); + this.lastAttributeNode = findAttribute(element, attrNS, attrName); + assert_true(!!this.lastAttributeNode); + return (this.lastAttributeNode.value = attrValue); + }, + }, + { + api: "Node.nodeValue", + acceptNS: true, + runSetter: function(element, attrNS, attrName, attrValue, type) { + element.setAttributeNS(attrNS, attrName, createTrustedOutput(type, "")); + this.lastAttributeNode = findAttribute(element, attrNS, attrName); + assert_true(!!this.lastAttributeNode); + return (this.lastAttributeNode.nodeValue = attrValue); + }, + }, + { + api: "Node.textContent", + acceptNS: true, + runSetter: function(element, attrNS, attrName, attrValue, type) { + element.setAttributeNS(attrNS, attrName, createTrustedOutput(type, "")); + this.lastAttributeNode = findAttribute(element, attrNS, attrName); + assert_true(!!this.lastAttributeNode); + return (this.lastAttributeNode.textContent = attrValue); + }, + }, +]; + +// Set an attribute for each testcase of trustedTypeDataForAttribute. The CSP +// rule and a null default policy will block those corresponding to trusted +// type sinks. +attributeSetterData.forEach(setterData => { + trustedTypeDataForAttribute.forEach(testData => { + if (testData.attrNS && !setterData.acceptNS) return; + test(() => { + let element = testData.element(); + // This is a trusted type sink and should be blocked. + assert_throws_js(TypeError, () => { + setterData.runSetter(element, testData.attrNS, testData.attrName, + "neverset", testData.type); + }); + }, `${setterData.api} throws for \ +elementNS=${testData.element().namespaceURI}, \ +element=${testData.element().tagName}, \ +${testData.attrNS ? 'attrNS='+testData.attrNS+', ' : ''} \ +attrName=${testData.attrName} with a plain string`); + }); +}); + + + // For attributes that are trusted type sinks, try setting them to a value + // that has the expected trusted type. + attributeSetterData.filter(setterData => setterData.acceptTrustedTypeArgumentInIDL).forEach(setterData => { + trustedTypeDataForAttribute.forEach(testData => { + if (!testData.type) return; + if (testData.attrNS && !setterData.acceptNS) return; + test(() => { + let element = testData.element(); + let trustedInput = createTrustedOutput(testData.type, "somevalue"); + // Passing a trusted type should work normally. + setterData.runSetter(element, testData.attrNS, testData.attrName, + trustedInput, testData.type); + assert_equals(element.getAttributeNS(testData.attrNS, + testData.attrName), "somevalue"); + }, `${setterData.api} works for \ +elementNS=${testData.element().namespaceURI}, \ +element=${testData.element().tagName}, \ +${testData.attrNS ? 'attrNS='+testData.attrNS+', ' : ''} \ +attrName=${testData.attrName} with a ${testData.type} input.`); + }); + }); +</script> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-sinkid-state-change.https.html b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-sinkid-state-change.https.html index 8462b52..d9369e3 100644 --- a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-sinkid-state-change.https.html +++ b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-sinkid-state-change.https.html
@@ -32,14 +32,16 @@ assert_equals(audioContext.state, 'suspended'); // Step 11.5. Fire an event named sinkchange at the associated AudioContext. - audioContext.onsinkchange = t.step_func(() => { - events.push('sinkchange'); - assert_equals(audioContext.sinkId, firstDeviceId); - }); + return new Promise(resolve => { + audioContext.onsinkchange = t.step_func(() => { + events.push('sinkchange'); + assert_equals(audioContext.sinkId, firstDeviceId); + assert_equals(events[0], 'sinkchange'); + resolve(); + }); - await audioContext.setSinkId(firstDeviceId); - assert_equals(events[0], 'sinkchange'); - t.done(); + audioContext.setSinkId(firstDeviceId); + }); }, 'Calling setSinkId() on a suspended AudioContext should fire only sink ' + 'change events.'); @@ -78,7 +80,8 @@ // The following event handler will catch 3 state change events: // - The initial 'running' state change. - // - Step 9.2.1. Set the state attribute of the AudioContext to "suspended". + // - Step 9.2.1. Set the state attribute of the AudioContext to + // "suspended". // Fire an event named statechange at the associated AudioContext. // - Step 12.2. Set the state attribute of the AudioContext to "running". // Fire an event named statechange at the associated AudioContext. @@ -94,5 +97,42 @@ }); }, 'Calling setSinkId() on a running AudioContext should fire both state ' + 'and sink change events.'); + + // Test that the setSinkId promise resolves before the sinkchange event. + promise_test(async t => { + let events = []; + const audioContext = new AudioContext(); + + await audioContext.resume(); + + function eventCheckpoint(resolve) { + assert_equals(events[0], 'promise_resolved', + 'Promise should resolve first'); + assert_equals(events[1], 'sinkchange', 'Event should fire second'); + assert_equals(events[2], 'sinkchange_microtask', + 'Event microtasks run last'); + resolve(); + } + + return new Promise((resolve, reject) => { + audioContext.onsinkchange = t.step_func(() => { + events.push('sinkchange'); + Promise.resolve().then(() => { + events.push('sinkchange_microtask'); + if (events.length === 3) { + eventCheckpoint(resolve); + } + }); + }); + + audioContext.setSinkId({ type: 'none' }).then(() => { + events.push('promise_resolved'); + if (events.length === 3) { + eventCheckpoint(resolve); + } + }).catch(reject); + }); + }, 'setSinkId() promise should resolve before the sinkchange event is ' + + 'fired.'); </script> </html>
diff --git a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/mediaElementAudioSourceToScriptProcessorTest.html b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/mediaElementAudioSourceToScriptProcessorTest.html index 1099ee8d..39d238ec 100644 --- a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/mediaElementAudioSourceToScriptProcessorTest.html +++ b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/mediaElementAudioSourceToScriptProcessorTest.html
@@ -8,7 +8,7 @@ to those of a loaded AudioBuffer with the same source. Somewhat similiar to a test from Mozilla: -https://searchfox.org/mozilla-central/source/dom/media/webaudio/test/test_mediaElementAudioSourceNode.html +https://searchfox.org/firefox-main/source/dom/media/webaudio/test/test_mediaElementAudioSourceNode.html --> <html class="a">
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/network/continue_request/cookies.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/network/continue_request/cookies.py index d403f27..7dfafdf 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/network/continue_request/cookies.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/network/continue_request/cookies.py
@@ -1,4 +1,5 @@ import pytest +import pytest_asyncio from webdriver.bidi.modules.network import CookieHeader, Header, NetworkStringValue from webdriver.bidi.modules.script import ContextTarget @@ -9,13 +10,34 @@ pytestmark = pytest.mark.asyncio +@pytest_asyncio.fixture(autouse=True) +async def delete_cookies(bidi_session): + await bidi_session.storage.delete_cookies() + + @pytest.mark.parametrize( - "document_cookies, modified_cookies", + "document_cookies, modified_cookies, expected_event_cookies", [ - [{"a": "1"}, {}], - [{}, {"b": "2"}], - [{"a": "1", "b": "2"}, {"c": "3", "d": "4"}], - [{"a": "1"}, {"a": "not-1"}], + [{"a": "from-store"}, {}, []], + [{"a": "from-store"}, {"b": "from-command"}, []], + [{}, {"b": "from-command"}, []], + [ + {"a": "from-store"}, + {"a": "from-command"}, + [{"name": "a", "value": {"type": "string", "value": "from-store"}}], + ], + [ + {"a": "from-store-a", "b": "from-store-b"}, + {"b": "from-command-b", "c": "from-command-c"}, + [{"name": "b", "value": {"type": "string", "value": "from-store-b"}}], + ], + ], + ids=[ + "store_cookie_removed", + "store_cookies_replaced", + "new_cookie_in_command", + "modified_cookie_in_command", + "common_cookie", ], ) async def test_modify_cookies( @@ -26,13 +48,14 @@ top_context, document_cookies, modified_cookies, - url + expected_event_cookies, + url, ): # Navigate away from about:blank to make sure document.cookies can be used. await bidi_session.browsing_context.navigate( context=top_context["context"], url=url("/webdriver/tests/bidi/network/support/empty.html"), - wait="complete" + wait="complete", ) expression = "" @@ -57,12 +80,12 @@ response_event = await on_response_completed event_cookies = response_event["request"]["cookies"] - assert len(event_cookies) == len(cookies) - for cookie in cookies: + assert len(event_cookies) == len(expected_event_cookies) + for expected in expected_event_cookies: event_cookie = next( - filter(lambda c: c["name"] == cookie["name"], event_cookies), None + filter(lambda c: c["name"] == expected["name"], event_cookies), None ) - recursive_compare(cookie, event_cookie) + recursive_compare(expected, event_cookie) await bidi_session.storage.delete_cookies() @@ -84,21 +107,23 @@ response_event = await on_response_completed event_cookies = response_event["request"]["cookies"] - recursive_compare([cookie], event_cookies) + assert event_cookies == [] await bidi_session.storage.delete_cookies() +@pytest.mark.parametrize( + "header_cookie", + ["a=from-header", "b=from-header"], + ids=["different_cookie", "same_cookie"], +) async def test_override_modified_header_cookies( - setup_blocked_request, - subscribe_events, - wait_for_event, - bidi_session, + setup_blocked_request, subscribe_events, wait_for_event, bidi_session, header_cookie ): request = await setup_blocked_request("beforeRequestSent") await subscribe_events(events=[RESPONSE_COMPLETED_EVENT]) - header = Header(name="Cookie", value=NetworkStringValue("a=1")) + header = Header(name="Cookie", value=NetworkStringValue(header_cookie)) cookie = CookieHeader(name="b", value=NetworkStringValue("2")) on_response_completed = wait_for_event(RESPONSE_COMPLETED_EVENT) await bidi_session.network.continue_request( @@ -107,6 +132,6 @@ response_event = await on_response_completed event_cookies = response_event["request"]["cookies"] - recursive_compare([cookie], event_cookies) + assert event_cookies == [] await bidi_session.storage.delete_cookies()
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-remote-track-mute.https.html b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-remote-track-mute.https.html index f625623e..e1becf00 100644 --- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-remote-track-mute.https.html +++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-remote-track-mute.https.html
@@ -148,4 +148,41 @@ pc1.close(); await mutePromise; }, 'pc.close() on one side causes mute events on the other'); + +promise_test(async t => { + const pc1 = createPeerConnectionWithCleanup(t); + const pc1Sender = pc1.addTrack(...await createTrackAndStreamWithCleanup(t)); + const localTransceiver = findTransceiverForSender(pc1, pc1Sender); + const pc2 = createPeerConnectionWithCleanup(t); + exchangeIceCandidates(pc1, pc2); + + let pc2Track; + let pc2Transceiver; + let unmutePromise; + pc2.ontrack = t.step_func(e => { + pc2Track = e.track; + pc2Transceiver = pc2.getTransceivers()[0]; + const watcher = new EventWatcher(t, e.track, ['unmute'], () => waitForTimeout(t)); + unmutePromise = watcher.wait_for('unmute'); + }); + await exchangeOfferAnswer(pc1, pc2); + await unmutePromise; + + // Stop the transceiver on the receiving side. Per spec the receiver track + // must end when a transceiver is stopped. + pc2Transceiver.stop(); + await new Promise(r => { pc2Track.onended = r; }); + + // A 'mute' event must not fire on an already-ended track when the remote + // side renegotiates away from sending. + pc2Track.onmute = t.step_func(() => { + assert_unreached('mute event must not fire on an ended track'); + }); + + localTransceiver.direction = 'recvonly'; + await exchangeOfferAnswer(pc1, pc2); + + assert_equals(pc2Track.readyState, 'ended', + 'receiver track remains ended after renegotiation'); +}, 'No mute event fires on a stopped transceiver\'s track when remote renegotiates to recvonly'); </script>
diff --git a/third_party/blink/web_tests/external/wpt/workers/baseurl/alpha/sharedworker-in-worker-expected.txt b/third_party/blink/web_tests/external/wpt/workers/baseurl/alpha/sharedworker-in-worker-expected.txt deleted file mode 100644 index c78623f..0000000 --- a/third_party/blink/web_tests/external/wpt/workers/baseurl/alpha/sharedworker-in-worker-expected.txt +++ /dev/null
@@ -1,5 +0,0 @@ -This is a testharness.js-based test. -[FAIL] Base URL in workers: new SharedWorker() - assert_unreached: Got error event Reached unreachable code -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/workers/baseurl/alpha/sharedworker-in-worker.html b/third_party/blink/web_tests/external/wpt/workers/baseurl/alpha/sharedworker-in-worker.html deleted file mode 100644 index 25d25823..0000000 --- a/third_party/blink/web_tests/external/wpt/workers/baseurl/alpha/sharedworker-in-worker.html +++ /dev/null
@@ -1,14 +0,0 @@ -<!doctype html> -<meta charset=utf-8> -<title>Base URL in workers: new SharedWorker()</title> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script> -async_test(function() { - var worker = new Worker("../beta/sharedworker.py"); - worker.onmessage = this.step_func_done(function(e) { - assert_equals(e.data, "gamma"); - }); - worker.onerror = this.unreached_func("Got error event"); -}); -</script>
diff --git a/third_party/blink/web_tests/external/wpt/workers/baseurl/beta/sharedworker.py b/third_party/blink/web_tests/external/wpt/workers/baseurl/beta/sharedworker.py deleted file mode 100644 index bd6f70e..0000000 --- a/third_party/blink/web_tests/external/wpt/workers/baseurl/beta/sharedworker.py +++ /dev/null
@@ -1,3 +0,0 @@ -def main(request, response): - return (302, b"Moved"), [(b"Location", b"../gamma/sharedworker.js")], u"postMessage('executed redirecting script');" -
diff --git a/third_party/blink/web_tests/external/wpt/workers/baseurl/gamma/sharedworker.js b/third_party/blink/web_tests/external/wpt/workers/baseurl/gamma/sharedworker.js deleted file mode 100644 index d0718cfd..0000000 --- a/third_party/blink/web_tests/external/wpt/workers/baseurl/gamma/sharedworker.js +++ /dev/null
@@ -1,4 +0,0 @@ -var worker = new SharedWorker("subsharedworker.js"); -worker.port.onmessage = function(e) { - postMessage(e.data); -}
diff --git a/third_party/blink/web_tests/external/wpt/workers/baseurl/gamma/subsharedworker.js b/third_party/blink/web_tests/external/wpt/workers/baseurl/gamma/subsharedworker.js deleted file mode 100644 index e23602f..0000000 --- a/third_party/blink/web_tests/external/wpt/workers/baseurl/gamma/subsharedworker.js +++ /dev/null
@@ -1,3 +0,0 @@ -onconnect = function(e) { - e.source.postMessage('gamma'); -}
diff --git a/third_party/blink/web_tests/external/wpt/workers/constructors/Worker/expected-self-properties.worker.js b/third_party/blink/web_tests/external/wpt/workers/constructors/Worker/expected-self-properties.worker.js index 0ce41b59..72edf49 100644 --- a/third_party/blink/web_tests/external/wpt/workers/constructors/Worker/expected-self-properties.worker.js +++ b/third_party/blink/web_tests/external/wpt/workers/constructors/Worker/expected-self-properties.worker.js
@@ -1,6 +1,6 @@ importScripts("/resources/testharness.js"); -var expected = ['XMLHttpRequest', 'WebSocket', 'EventSource', 'MessageChannel', 'Worker', 'SharedWorker']; +var expected = ['XMLHttpRequest', 'WebSocket', 'EventSource', 'MessageChannel', 'Worker']; for (var i = 0; i < expected.length; ++i) { var property = expected[i]; test(function() {
diff --git a/third_party/blink/web_tests/external/wpt/workers/constructors/Worker/unexpected-self-properties.worker.js b/third_party/blink/web_tests/external/wpt/workers/constructors/Worker/unexpected-self-properties.worker.js index 69d29b2..acdd0eb 100644 --- a/third_party/blink/web_tests/external/wpt/workers/constructors/Worker/unexpected-self-properties.worker.js +++ b/third_party/blink/web_tests/external/wpt/workers/constructors/Worker/unexpected-self-properties.worker.js
@@ -1,6 +1,6 @@ importScripts("/resources/testharness.js"); -var unexpected = ['open', 'print', 'stop', 'getComputedStyle', 'getSelection', 'releaseEvents', 'captureEvents', 'alert', 'confirm', 'prompt', 'addEventStream', 'removeEventStream', 'back', 'forward', 'attachEvent', 'detachEvent', 'navigate', 'DOMParser', 'XMLSerializer', 'XPathEvaluator', 'XSLTProcessor', 'opera', 'Image', 'Option', 'frames', 'Audio', 'SVGUnitTypes', 'SVGZoomAndPan', 'java', 'netscape', 'sun', 'Packages', 'ByteArray', 'closed', 'defaultStatus', 'document', 'event', 'frameElement', 'history', 'innerHeight', 'innerWidth', 'opener', 'outerHeight', 'outerWidth', 'pageXOffset', 'pageYOffset', 'parent', 'screen', 'screenLeft', 'screenTop', 'screenX', 'screenY', 'status', 'top', 'window', 'length']; // iterated window in opera and removed expected ones +var unexpected = ['open', 'print', 'stop', 'getComputedStyle', 'getSelection', 'releaseEvents', 'captureEvents', 'alert', 'confirm', 'prompt', 'addEventStream', 'removeEventStream', 'back', 'forward', 'attachEvent', 'detachEvent', 'navigate', 'DOMParser', 'XMLSerializer', 'XPathEvaluator', 'XSLTProcessor', 'opera', 'Image', 'Option', 'frames', 'Audio', 'SVGUnitTypes', 'SVGZoomAndPan', 'java', 'netscape', 'sun', 'Packages', 'ByteArray', 'closed', 'defaultStatus', 'document', 'event', 'frameElement', 'history', 'innerHeight', 'innerWidth', 'opener', 'outerHeight', 'outerWidth', 'pageXOffset', 'pageYOffset', 'parent', 'screen', 'screenLeft', 'screenTop', 'screenX', 'screenY', 'status', 'top', 'window', 'length', 'SharedWorker']; // iterated window in opera and removed expected ones for (var i = 0; i < unexpected.length; ++i) { var property = unexpected[i]; test(function() {
diff --git a/third_party/blink/web_tests/external/wpt/xhr/abort-during-navigation.window.js b/third_party/blink/web_tests/external/wpt/xhr/abort-during-navigation.window.js new file mode 100644 index 0000000..79bab92 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/xhr/abort-during-navigation.window.js
@@ -0,0 +1,27 @@ +// META: title=XMLHttpRequest: navigation should not fire abort event + +async_test(function(t) { + var iframe = document.createElement("iframe"); + var events = []; + + window.addEventListener("message", t.step_func(function(e) { + if (e.data.type === "xhr-event") { + events.push(e.data.event); + } + if (e.data.type === "ready") { + iframe.src = "/common/blank.html"; + iframe.onload = t.step_func(function() { + t.step_timeout(t.step_func_done(function() { + assert_false(events.includes("error"), "error event should not fire"); + assert_false(events.includes("abort"), "abort event should not fire"); + assert_false(events.includes("load"), "load event should not fire"); + assert_false(events.includes("upload.error"), "upload error event should not fire"); + assert_false(events.includes("upload.abort"), "upload abort event should not fire"); + }), 500); + }); + } + })); + + iframe.src = "/xhr/resources/abort-during-navigation-iframe.html"; + document.body.appendChild(iframe); +}, "XHR should not fire abort or error events when cancelled by navigation");
diff --git a/third_party/blink/web_tests/external/wpt/xhr/resources/abort-during-navigation-iframe.html b/third_party/blink/web_tests/external/wpt/xhr/resources/abort-during-navigation-iframe.html new file mode 100644 index 0000000..836a9032 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/xhr/resources/abort-during-navigation-iframe.html
@@ -0,0 +1,28 @@ +<!DOCTYPE html> +<script> +var xhr = new XMLHttpRequest(); +xhr.onerror = function() { + parent.postMessage({type: "xhr-event", event: "error"}, "*"); +}; +xhr.onabort = function() { + parent.postMessage({type: "xhr-event", event: "abort"}, "*"); +}; +xhr.onload = function() { + parent.postMessage({type: "xhr-event", event: "load"}, "*"); +}; +xhr.onloadend = function() { + parent.postMessage({type: "xhr-event", event: "loadend"}, "*"); +}; +xhr.onreadystatechange = function() { + parent.postMessage({type: "xhr-event", event: "readystatechange:" + xhr.readyState}, "*"); +}; +xhr.upload.onerror = function() { + parent.postMessage({type: "xhr-event", event: "upload.error"}, "*"); +}; +xhr.upload.onabort = function() { + parent.postMessage({type: "xhr-event", event: "upload.abort"}, "*"); +}; +xhr.open("GET", "delay.py?ms=10000", true); +xhr.send(); +parent.postMessage({type: "ready"}, "*"); +</script>
diff --git a/third_party/blink/web_tests/http/tests/misc/drag-bookmark-expected.txt b/third_party/blink/web_tests/http/tests/misc/drag-bookmark-expected.txt index ff43ca4..36c1fa0 100644 --- a/third_party/blink/web_tests/http/tests/misc/drag-bookmark-expected.txt +++ b/third_party/blink/web_tests/http/tests/misc/drag-bookmark-expected.txt
@@ -1 +1 @@ -SUCCESS +PASS: Dropped bookmark
diff --git a/third_party/blink/web_tests/virtual/scoped-custom-element-registry-disabled/external/wpt/custom-elements/registries/ShadowRoot-init-customElementRegistry-expected.txt b/third_party/blink/web_tests/virtual/scoped-custom-element-registry-disabled/external/wpt/custom-elements/registries/ShadowRoot-init-customElementRegistry-expected.txt index 97f8cd2..94b4e92 100644 --- a/third_party/blink/web_tests/virtual/scoped-custom-element-registry-disabled/external/wpt/custom-elements/registries/ShadowRoot-init-customElementRegistry-expected.txt +++ b/third_party/blink/web_tests/virtual/scoped-custom-element-registry-disabled/external/wpt/custom-elements/registries/ShadowRoot-init-customElementRegistry-expected.txt
@@ -3,6 +3,10 @@ assert_equals: expected (object) object "[object CustomElementRegistry]" but got (undefined) undefined [FAIL] A newly attached connected ShadowRoot should use the global registry by default assert_equals: expected (object) object "[object CustomElementRegistry]" but got (undefined) undefined +[FAIL] A newly attached ShadowRoot should use the global registry by default even if the host uses a custom registry + Failed to construct 'CustomElementRegistry': Illegal constructor +[FAIL] A newly attached ShadowRoot should use the global registry by default even if the host is within another shadow tree that uses a custom registry + Failed to construct 'CustomElementRegistry': Illegal constructor [FAIL] A newly attached disconnected ShadowRoot should use the scoped registry if explicitly specified in attachShadow Failed to construct 'CustomElementRegistry': Illegal constructor [FAIL] A newly attached connected ShadowRoot should use the scoped registry if explicitly specified in attachShadow
diff --git a/third_party/blink/web_tests/virtual/scoped-custom-element-registry-disabled/external/wpt/custom-elements/registries/ShadowRoot-init-declarative-expected.txt b/third_party/blink/web_tests/virtual/scoped-custom-element-registry-disabled/external/wpt/custom-elements/registries/ShadowRoot-init-declarative-expected.txt index fb899f8..15f8c12b 100644 --- a/third_party/blink/web_tests/virtual/scoped-custom-element-registry-disabled/external/wpt/custom-elements/registries/ShadowRoot-init-declarative-expected.txt +++ b/third_party/blink/web_tests/virtual/scoped-custom-element-registry-disabled/external/wpt/custom-elements/registries/ShadowRoot-init-declarative-expected.txt
@@ -1,7 +1,7 @@ This is a testharness.js-based test. -[FAIL] Custom element inside 'shadowrootcustomelementregistry' declarative shadow root +[FAIL] Custom element inside 'shadowrootcustomelementregistry' declarative shadow root should use document's registry as attachShadow default registry assert_equals: expected (object) null but got (undefined) undefined -[FAIL] Built-in element inside 'shadowrootcustomelementregistry' declarative shadow root +[FAIL] Built-in element inside 'shadowrootcustomelementregistry' declarative shadow root should use document's registry as attachShadow default registry assert_equals: expected (object) null but got (undefined) undefined Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/virtual/scoped-custom-element-registry-disabled/external/wpt/custom-elements/registries/scoped-custom-element-registry-customelementregistry-attribute-expected.txt b/third_party/blink/web_tests/virtual/scoped-custom-element-registry-disabled/external/wpt/custom-elements/registries/scoped-custom-element-registry-customelementregistry-attribute-expected.txt index 269c219..0919657f 100644 --- a/third_party/blink/web_tests/virtual/scoped-custom-element-registry-disabled/external/wpt/custom-elements/registries/scoped-custom-element-registry-customelementregistry-attribute-expected.txt +++ b/third_party/blink/web_tests/virtual/scoped-custom-element-registry-disabled/external/wpt/custom-elements/registries/scoped-custom-element-registry-customelementregistry-attribute-expected.txt
@@ -21,4 +21,28 @@ assert_equals: expected (object) null but got (undefined) undefined [FAIL] Setting customelementregistry content attribute during constructor should not make it use null registry assert_equals: expected (object) object "[object CustomElementRegistry]" but got (undefined) undefined +[FAIL] Body with customelementregistry attribute during initial parse should have null registry and propagate to children + assert_equals: body should have null registry expected (object) null but got (undefined) undefined +[FAIL] Custom element candidate child of body with customelementregistry should have null registry during initial parse + assert_equals: custom element candidate child of body with customelementregistry should have null registry expected (object) null but got (undefined) undefined +[FAIL] Descendants of body with customelementregistry should all have null registry during initial parse + assert_equals: div child should have null registry expected (object) null but got (undefined) undefined +[FAIL] Body with customelementregistry in a complete document structure should have null registry + assert_equals: body should have null registry expected (object) null but got (undefined) undefined +[FAIL] Initial parse: built-in element with customelementregistry has null registry + assert_equals: Built-in element with customelementregistry attribute should have null registry expected (object) null but got (undefined) undefined +[FAIL] Initial parse: custom element candidate with customelementregistry has null registry + assert_equals: Custom element candidate with customelementregistry attribute should have null registry expected (object) null but got (undefined) undefined +[FAIL] Initial parse: built-in element without customelementregistry uses global registry + assert_equals: Built-in element without customelementregistry should use the global registry expected (object) object "[object CustomElementRegistry]" but got (undefined) undefined +[FAIL] Initial parse: custom element candidate without customelementregistry uses global registry + assert_equals: Custom element candidate without customelementregistry should use the global registry expected (object) object "[object CustomElementRegistry]" but got (undefined) undefined +[FAIL] Initial parse: child of element with customelementregistry inherits null registry + assert_equals: Child of element with customelementregistry should have null registry expected (object) null but got (undefined) undefined +[FAIL] Initial parse: custom element candidate child inherits null registry from parent + assert_equals: Custom element candidate child of element with customelementregistry should have null registry expected (object) null but got (undefined) undefined +[FAIL] Initial parse: deeply nested descendant inherits null registry + assert_equals: Deeply nested custom element candidate should have null registry expected (object) null but got (undefined) undefined +[FAIL] Initial parse: global registry define only upgrades elements without customelementregistry + assert_equals: Custom element candidate with null registry should still not be upgraded after defining in global registry expected function "function HTMLElement() { [native code] }" but got function "class extends HTMLElement {}" Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/virtual/webcrypto-pqc/external/wpt/WebCryptoAPI/supports-modern.tentative.https.any-expected.txt b/third_party/blink/web_tests/virtual/webcrypto-pqc/external/wpt/WebCryptoAPI/supports-modern.tentative.https.any-expected.txt index 23d6168b..9831779 100644 --- a/third_party/blink/web_tests/virtual/webcrypto-pqc/external/wpt/WebCryptoAPI/supports-modern.tentative.https.any-expected.txt +++ b/third_party/blink/web_tests/virtual/webcrypto-pqc/external/wpt/WebCryptoAPI/supports-modern.tentative.https.any-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 5 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 6 FAIL, 0 TIMEOUT, 0 NOTRUN. [FAIL] supports(generateKey, ML-KEM-512) assert_true: ML-KEM-512 should support generateKey expected true got false [FAIL] supports(importKey, ML-KEM-512) @@ -8,6 +8,9 @@ assert_true: ML-KEM-512 should support encapsulateKey expected true got false [FAIL] supports(encapsulateBits, ML-KEM-512) assert_true: ML-KEM-512 should support encapsulateBits expected true got false +[FAIL] supports(decapsulateKey, ML-KEM-512) + assert_true: ML-KEM-512 should support decapsulateKey expected true got false [FAIL] supports(decapsulateBits, ML-KEM-512) assert_true: ML-KEM-512 should support decapsulateBits expected true got false Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/virtual/webcrypto-pqc/external/wpt/WebCryptoAPI/supports-modern.tentative.https.any.worker-expected.txt b/third_party/blink/web_tests/virtual/webcrypto-pqc/external/wpt/WebCryptoAPI/supports-modern.tentative.https.any.worker-expected.txt index 23d6168b..9831779 100644 --- a/third_party/blink/web_tests/virtual/webcrypto-pqc/external/wpt/WebCryptoAPI/supports-modern.tentative.https.any.worker-expected.txt +++ b/third_party/blink/web_tests/virtual/webcrypto-pqc/external/wpt/WebCryptoAPI/supports-modern.tentative.https.any.worker-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 5 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 6 FAIL, 0 TIMEOUT, 0 NOTRUN. [FAIL] supports(generateKey, ML-KEM-512) assert_true: ML-KEM-512 should support generateKey expected true got false [FAIL] supports(importKey, ML-KEM-512) @@ -8,6 +8,9 @@ assert_true: ML-KEM-512 should support encapsulateKey expected true got false [FAIL] supports(encapsulateBits, ML-KEM-512) assert_true: ML-KEM-512 should support encapsulateBits expected true got false +[FAIL] supports(decapsulateKey, ML-KEM-512) + assert_true: ML-KEM-512 should support decapsulateKey expected true got false [FAIL] supports(decapsulateBits, ML-KEM-512) assert_true: ML-KEM-512 should support decapsulateBits expected true got false Harness: the test ran to completion. +
diff --git a/third_party/boringssl/README.chromium b/third_party/boringssl/README.chromium index 131780b0..997fda6 100644 --- a/third_party/boringssl/README.chromium +++ b/third_party/boringssl/README.chromium
@@ -1,7 +1,7 @@ Name: BoringSSL URL: https://boringssl.googlesource.com/boringssl Version: N/A -Revision: 6474716769bcf85be5509b728af82a988f26fb2e +Revision: 950495856681c75e929963673dff12351378af60 Update Mechanism: Autoroll License: Apache-2.0, BSD-3-Clause License File: src/LICENSE
diff --git a/third_party/boringssl/src b/third_party/boringssl/src index 6474716..9504958 160000 --- a/third_party/boringssl/src +++ b/third_party/boringssl/src
@@ -1 +1 @@ -Subproject commit 6474716769bcf85be5509b728af82a988f26fb2e +Subproject commit 950495856681c75e929963673dff12351378af60
diff --git a/third_party/crossbench b/third_party/crossbench index 50443e9..7e536e3 160000 --- a/third_party/crossbench +++ b/third_party/crossbench
@@ -1 +1 @@ -Subproject commit 50443e9356593c8a1ac9f18bc6a66378cdc8810d +Subproject commit 7e536e3a169d2862d9cde1633829d9aba5e137f5
diff --git a/third_party/dawn b/third_party/dawn index 1fa8f21..5326a2a 160000 --- a/third_party/dawn +++ b/third_party/dawn
@@ -1 +1 @@ -Subproject commit 1fa8f21027a55087ded8e9c0d5fef8ab74b39924 +Subproject commit 5326a2acd1a0bc04637e3618b2095894ba97f3bd
diff --git a/third_party/devtools-frontend/README.chromium b/third_party/devtools-frontend/README.chromium index 0ba2b57..8fdbc0c1 100644 --- a/third_party/devtools-frontend/README.chromium +++ b/third_party/devtools-frontend/README.chromium
@@ -1,7 +1,7 @@ Name: Devtools-Frontend URL: https://chromium.googlesource.com/devtools/devtools-frontend Version: N/A -Revision: d71632604eea6ff3492da15af59ffe3ea201399b +Revision: 8c8963f2e817337256efa9d06b79abbc257887fc Update Mechanism: Autoroll License: BSD-3-Clause License File: src/LICENSE
diff --git a/third_party/devtools-frontend/src b/third_party/devtools-frontend/src index d716326..8c8963f 160000 --- a/third_party/devtools-frontend/src +++ b/third_party/devtools-frontend/src
@@ -1 +1 @@ -Subproject commit d71632604eea6ff3492da15af59ffe3ea201399b +Subproject commit 8c8963f2e817337256efa9d06b79abbc257887fc
diff --git a/third_party/ipcz/.clang-format b/third_party/ipcz/.clang-format index 275db31..f6e81b8e 100644 --- a/third_party/ipcz/.clang-format +++ b/third_party/ipcz/.clang-format
@@ -1,5 +1,5 @@ BasedOnStyle: Chromium -Standard: Cpp11 +Standard: Latest ColumnLimit: 80 MacroBlockBegin: "^\
diff --git a/third_party/libaom/README.chromium b/third_party/libaom/README.chromium index e12c1e7..9f1ecf9 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: e86de95f799ebfe82db8b279bfb1386d4f74ab1d +Revision: e67178f5ef15f7568be9f1e162a32b643c6bbd72 Update Mechanism: Manual CPEPrefix: cpe:/a:aomedia:aomedia:3.13.3 License: Alliance-for-Open-Media-Patent, BSD-2-Clause
diff --git a/third_party/libaom/source/config/config/aom_version.h b/third_party/libaom/source/config/config/aom_version.h index 9022f55..d03a34b 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 3 -#define VERSION_EXTRA "431-ge86de95f79" +#define VERSION_EXTRA "433-ge67178f5ef" #define VERSION_PACKED \ ((VERSION_MAJOR << 16) | (VERSION_MINOR << 8) | (VERSION_PATCH)) -#define VERSION_STRING_NOSP "3.13.3-431-ge86de95f79" -#define VERSION_STRING " 3.13.3-431-ge86de95f79" +#define VERSION_STRING_NOSP "3.13.3-433-ge67178f5ef" +#define VERSION_STRING " 3.13.3-433-ge67178f5ef" #endif // AOM_VERSION_H_
diff --git a/third_party/libaom/source/libaom b/third_party/libaom/source/libaom index e86de95..e67178f 160000 --- a/third_party/libaom/source/libaom +++ b/third_party/libaom/source/libaom
@@ -1 +1 @@ -Subproject commit e86de95f799ebfe82db8b279bfb1386d4f74ab1d +Subproject commit e67178f5ef15f7568be9f1e162a32b643c6bbd72
diff --git a/third_party/libvpx/README.chromium b/third_party/libvpx/README.chromium index 84e6de2..2ccf053f 100644 --- a/third_party/libvpx/README.chromium +++ b/third_party/libvpx/README.chromium
@@ -1,7 +1,7 @@ Name: libvpx URL: https://chromium.googlesource.com/webm/libvpx Version: N/A -Revision: 640d4ce27ba918783e28a0da46a8a37abe4a65b6 +Revision: 76b08021715417b48f01713c6100f86d9b7ab450 Update Mechanism: Manual CPEPrefix: cpe:/a:webmproject:libvpx:1.16.0 License: BSD-3-Clause, WebM-Project-Patent
diff --git a/third_party/libvpx/source/config/vpx_version.h b/third_party/libvpx/source/config/vpx_version.h index ff70802..b3ec189 100644 --- a/third_party/libvpx/source/config/vpx_version.h +++ b/third_party/libvpx/source/config/vpx_version.h
@@ -4,8 +4,8 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 16 #define VERSION_PATCH 0 -#define VERSION_EXTRA "108-g640d4ce27" +#define VERSION_EXTRA "113-g76b080217" #define VERSION_PACKED ((VERSION_MAJOR<<16)|(VERSION_MINOR<<8)|(VERSION_PATCH)) -#define VERSION_STRING_NOSP "v1.16.0-108-g640d4ce27" -#define VERSION_STRING " v1.16.0-108-g640d4ce27" +#define VERSION_STRING_NOSP "v1.16.0-113-g76b080217" +#define VERSION_STRING " v1.16.0-113-g76b080217" #endif // VPX_VERSION_H_
diff --git a/third_party/libvpx/source/libvpx b/third_party/libvpx/source/libvpx index 640d4ce..76b0802 160000 --- a/third_party/libvpx/source/libvpx +++ b/third_party/libvpx/source/libvpx
@@ -1 +1 @@ -Subproject commit 640d4ce27ba918783e28a0da46a8a37abe4a65b6 +Subproject commit 76b08021715417b48f01713c6100f86d9b7ab450
diff --git a/third_party/perfetto b/third_party/perfetto index c9f7b8a..0861793 160000 --- a/third_party/perfetto +++ b/third_party/perfetto
@@ -1 +1 @@ -Subproject commit c9f7b8a8e0f461dd8335af67ae9e097622d47152 +Subproject commit 08617935301242fb7a9cb649ed65f035dcaf04f9
diff --git a/third_party/webrtc b/third_party/webrtc index 125a9d2..f9c143a 160000 --- a/third_party/webrtc +++ b/third_party/webrtc
@@ -1 +1 @@ -Subproject commit 125a9d22b0edd885012a492fcb2fb2d795e5a106 +Subproject commit f9c143a1b1a960b179f63eea1e511d1871a91b00
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 9165e49..e7a84f9 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -23523,11 +23523,6 @@ <int value="89" label="kFormSubmitWhenPrerendering"/> </enum> -<enum name="PrimaryButtonRight"> - <int value="0" label="Right-handed"/> - <int value="1" label="Left-handed"/> -</enum> - <enum name="PrintPreviewFailureType"> <!-- This must be kept current with PrintPreviewErrorBuckets in components/printing/renderer/print_render_frame_helper.h. -->
diff --git a/tools/metrics/histograms/metadata/android/enums.xml b/tools/metrics/histograms/metadata/android/enums.xml index 63d781f40..72f41fe2 100644 --- a/tools/metrics/histograms/metadata/android/enums.xml +++ b/tools/metrics/histograms/metadata/android/enums.xml
@@ -2863,6 +2863,7 @@ <int value="107" label="getDefaultCookieManager"/> <int value="108" label="getProfileStore"/> <int value="109" label="webViewInstanceGetSettings"/> + <int value="110" label="webViewInstanceGetAwContents"/> </enum> <!-- LINT.ThenChange(//base/tracing/protos/chrome_track_event.proto:WebViewStartup) -->
diff --git a/tools/metrics/histograms/metadata/ash/enums.xml b/tools/metrics/histograms/metadata/ash/enums.xml index 19acb13..4980584 100644 --- a/tools/metrics/histograms/metadata/ash/enums.xml +++ b/tools/metrics/histograms/metadata/ash/enums.xml
@@ -430,12 +430,6 @@ <int value="3" label="kTopRight"/> </enum> -<enum name="CameraPrivacySwitchEvent"> - <int value="0" label="Camera privacy switch toggled on"/> - <int value="1" label="Camera privacy switch toggled off"/> - <int value="2" label="Camera privacy switch on notification shown"/> -</enum> - <enum name="CaptureModeBarButtonType"> <int value="0" label="Screen Capture Button"/> <int value="1" label="Screen Record Button"/>
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml index d46809ce..431ba44 100644 --- a/tools/metrics/histograms/metadata/ash/histograms.xml +++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -5189,43 +5189,6 @@ <token key="MantaMetricType" variants="MantaMetricType"/> </histogram> -<histogram name="Ash.Media.CameraPrivacySwitch.Event" - enum="CameraPrivacySwitchEvent" expires_after="2023-09-03"> - <owner>tbarzic@chromium.org</owner> - <owner>gzadina@google.com</owner> - <summary> - Reports events related to camera privacy switch state. The camera privacy - switch is a hardware toggle supported by some Chrome OS devices that - disables the built in camera video feed. The histogram is reported (1) when - a camera privacy switch state change is detected (which generally causes a - system toast to get shown), and (2) when a notification informing the user - that the camera privacy switch is on (the notification is shown if the user - tries to use their camera with the privacy switch tuned on). The camera - privacy switch state is only recorded if the state change is a result of a - user action - it will not be recorded for state changes that are a result of - camera privacy switch state initialization. - </summary> -</histogram> - -<histogram name="Ash.Media.CameraPrivacySwitch.TimeFromNotificationToOff" - units="5 seconds" expires_after="2023-09-10"> - <owner>tbarzic@chromium.org</owner> - <owner>gzadina@google.com</owner> - <summary> - Time from showing a notification informing the user about the camera privacy - switch to the user turning the privacy switch off. The camera privacy switch - is a hardware switch supported by some Chrome OS devices that cuts the video - camera feed off. The Chrome OS UI shows a notification if the user tries to - use the camera with the privacy switch on. The intention is to track the - time it takes for the user to flip the privacy switch after they're notified - the camera is disabled. The histogram is recorded if the user toggles the - camera privacy switch after seeing the notification about the privacy switch - being on (if the switch is toggled more than once after the notification - gets shown, only the first toggle action will be reported). The time is - reported in seconds with 5 second granularity. - </summary> -</histogram> - <histogram name="Ash.MessageCenter.Scroll.PresentationTime" units="ms" expires_after="2026-07-14"> <owner>newcomer@chromium.org</owner> @@ -7905,17 +7868,6 @@ <token key="SearchType" variants="DriveFsSearchType"/> </histogram> -<histogram name="Ash.SearchModelUpdateTime.{TabletOrClamshellMode}" units="ms" - expires_after="2023-10-01"> - <owner>yulunwu@google.com</owner> - <owner>tbarzic@google.com</owner> - <summary> - Records the time interval between user-initiated search model updates after - the user starts a search query. Used to record how quickly users update the - search model in {TabletOrClamshellMode} after the first keystroke. - </summary> -</histogram> - <histogram name="Ash.ServerBasedSpeechRecognition.AudioLengthLeftWhenAudioCaptureEnd" units="ms" expires_after="2026-09-27"> @@ -10236,25 +10188,6 @@ </summary> </histogram> -<histogram name="Mouse.PrimaryButtonRight.Changed" enum="PrimaryButtonRight" - expires_after="2024-03-10"> - <owner>gavinwill@google.com</owner> - <owner>cros-device-enablement@chromium.org</owner> - <summary> - Tracks mouse PrimaryButtonRight setting. Only reported on Chrome OS. - </summary> -</histogram> - -<histogram name="Mouse.PrimaryButtonRight.Started" enum="PrimaryButtonRight" - expires_after="2024-03-10"> - <owner>gavinwill@google.com</owner> - <owner>cros-device-enablement@chromium.org</owner> - <summary> - Tracks mouse PrimaryButtonRight setting on startup. Only reported on Chrome - OS. - </summary> -</histogram> - <histogram name="Mouse.ScrollAcceleration{PreferenceChangeType}" enum="BooleanEnabled" expires_after="2025-12-01"> <owner>zhangwenyu@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/blink/enums.xml b/tools/metrics/histograms/metadata/blink/enums.xml index c3130834..c9df8cf 100644 --- a/tools/metrics/histograms/metadata/blink/enums.xml +++ b/tools/metrics/histograms/metadata/blink/enums.xml
@@ -8992,6 +8992,7 @@ <int value="434" label="Webgl2"/> <int value="435" label="DigitalCredentials"/> <int value="436" label="MediaPseudos"/> + <int value="437" label="GapDecorations"/> </enum> <!-- LINT.ThenChange(//third_party/blink/public/mojom/use_counter/metrics/webdx_feature.mojom:WebDXFeature) -->
diff --git a/tools/metrics/histograms/metadata/download/histograms.xml b/tools/metrics/histograms/metadata/download/histograms.xml index aea6f1e..1f7af603 100644 --- a/tools/metrics/histograms/metadata/download/histograms.xml +++ b/tools/metrics/histograms/metadata/download/histograms.xml
@@ -138,8 +138,8 @@ </histogram> <histogram name="Download.Android.WarningBypassDialog.Events" - enum="AndroidDownloadWarningBypassDialogEvent" expires_after="2026-05-30"> - <owner>chlily@chromium.org</owner> + enum="AndroidDownloadWarningBypassDialogEvent" expires_after="2026-11-30"> + <owner>yawfrempong@google.com</owner> <owner>chrome-counter-abuse-alerts@google.com</owner> <summary> Records events and user interactions with the download warning bypass dialog
diff --git a/tools/metrics/histograms/metadata/extensions/histograms.xml b/tools/metrics/histograms/metadata/extensions/histograms.xml index e8a4f813..12af06d9 100644 --- a/tools/metrics/histograms/metadata/extensions/histograms.xml +++ b/tools/metrics/histograms/metadata/extensions/histograms.xml
@@ -4387,23 +4387,6 @@ </summary> </histogram> -<histogram - name="Extensions.ServiceWorkerBackground.WorkerRegistrationRetryForUnregistrationAttemptsResult" - enum="Boolean" expires_after="2026-05-03"> - <owner>andreaorru@chromium.org</owner> - <owner>extensions-core@chromium.org</owner> - <summary> - When an extension with a service worker is loaded immediately after it was - unloaded the service worker registration can fail if the previous - unregistration has not completed yet. When this happens we delay the - registration and retry multiple times to try to make the registration - succeed. - - Emits true if the retry results in a successful registration. Emits false if - all retry attempts have been exhausted without success. - </summary> -</histogram> - <histogram name="Extensions.ServiceWorkerBackground.WorkerRegistrationState" enum="Boolean" expires_after="2026-09-06"> <owner>jlulejian@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/glic/histograms.xml b/tools/metrics/histograms/metadata/glic/histograms.xml index af97553..72980f8 100644 --- a/tools/metrics/histograms/metadata/glic/histograms.xml +++ b/tools/metrics/histograms/metadata/glic/histograms.xml
@@ -1756,6 +1756,17 @@ <summary>Recorded when a page gets screenshot error from Viz.</summary> </histogram> +<histogram name="Glic.PageContextFetcher.ScreenshotRedacted" enum="Boolean" + expires_after="2026-11-05"> + <owner>linnan@google.com</owner> + <owner>shivanisha@google.com</owner> + <owner>chrome-synapse-team@google.com</owner> + <summary> + Recorded when a screenshot is processed for Glic. Records true if any part + of the screenshot was redacted client-side, and false otherwise. + </summary> +</histogram> + <histogram name="Glic.PageContextFetcher.Total" units="ms" expires_after="2026-11-04"> <owner>carlosk@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/ios/histograms.xml b/tools/metrics/histograms/metadata/ios/histograms.xml index d19e85b..97951744 100644 --- a/tools/metrics/histograms/metadata/ios/histograms.xml +++ b/tools/metrics/histograms/metadata/ios/histograms.xml
@@ -2674,6 +2674,18 @@ </summary> </histogram> +<histogram name="IOS.Gemini.GlicContextualCue.Decision" + enum="OptimizationGuideOptimizationGuideDecision" + expires_after="2027-05-01"> + <owner>ogallant@google.com</owner> + <owner>bling-alchemy-eng@google.com</owner> + <summary> + Records the optimization guide decision for Gemini contextual cueing. Logged + when a response is received from the optimization guide service following a + navigation. + </summary> +</histogram> + <histogram name="IOS.Gemini.ImageActionButton" enum="IOSGeminiImageActionButtonType" expires_after="2027-02-02"> <owner>joepeplowski@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/magic_stack/enums.xml b/tools/metrics/histograms/metadata/magic_stack/enums.xml index f6da27f..86062109 100644 --- a/tools/metrics/histograms/metadata/magic_stack/enums.xml +++ b/tools/metrics/histograms/metadata/magic_stack/enums.xml
@@ -34,19 +34,21 @@ <int value="5" label="6th module"/> </enum> +<!-- LINT.IfChange(ModuleType) --> + <enum name="ModuleType"> <int value="0" label="Single tab module"/> <int value="1" label="Price change module"/> - <int value="2" label="Tab resumption module"/> + <int value="2" label="Deprecated Tab resumption module"/> <int value="3" label="Safety hub module"/> - <int value="4" label="Educational tip module"/> + <int value="4" label="Deprecated Educational tip module"/> <int value="5" label="Auxiliary search module"/> <int value="6" label="Default Browser Promo Card"/> <int value="7" label="Tab Group Promo Card"/> <int value="8" label="Tab Group Sync Promo Card"/> <int value="9" label="Quick Delete Promo Card"/> <int value="10" label="History Sync Promo Card"/> - <int value="11" label="Tips Notifications Promo Card"/> + <int value="11" label="Deprecated Tips Notifications Promo Card"/> <int value="12" label="Enhanced Safe Browsing Promo Card"/> <int value="13" label="Address bar placement Promo Card"/> <int value="14" label="Settings container Promo Card"/> @@ -57,6 +59,8 @@ <int value="19" label="Ntp Theme Promo Card"/> </enum> +<!-- LINT.ThenChange(//chrome/browser/magic_stack/android/java/src/org/chromium/chrome/browser/magic_stack/ModuleDelegate.java:HomeModuleTypes) --> + </enums> </histogram-configuration>
diff --git a/tools/metrics/histograms/metadata/magic_stack/histograms.xml b/tools/metrics/histograms/metadata/magic_stack/histograms.xml index f9d7802..cfe8ecd 100644 --- a/tools/metrics/histograms/metadata/magic_stack/histograms.xml +++ b/tools/metrics/histograms/metadata/magic_stack/histograms.xml
@@ -27,10 +27,14 @@ <variant name="Startup"/> </variants> +<!-- LINT.IfChange(ModuleType) --> + <variants name="ModuleType"> <variant name="AddressBarPlacementPromo"/> <variant name="AuxiliarySearch"/> <variant name="DefaultBrowserPromo"/> + <variant name="DeprecatedTabResumption"/> + <variant name="DeprecatedTipsNotificationsPromo"/> <variant name="EnhancedSafeBrowsingPromo"/> <variant name="HistorySyncPromo"/> <variant name="NtpThemePromo"/> @@ -44,10 +48,10 @@ <variant name="SingleTab"/> <variant name="TabGroupPromo"/> <variant name="TabGroupSyncPromo"/> - <variant name="TabResumption"/> - <variant name="TipsNotificationsPromo"/> </variants> +<!-- LINT.ThenChange(//chrome/browser/magic_stack/android/java/src/org/chromium/chrome/browser/magic_stack/ModuleDelegate.java:HomeModuleTypes) --> + <variants name="ScrollState"> <variant name="NotScrolled"/> <variant name="Scrolled"/>
diff --git a/tools/metrics/histograms/metadata/others/enums.xml b/tools/metrics/histograms/metadata/others/enums.xml index e1a66aa..d9b63da 100644 --- a/tools/metrics/histograms/metadata/others/enums.xml +++ b/tools/metrics/histograms/metadata/others/enums.xml
@@ -68,6 +68,7 @@ <int value="10" label="NoSuggestionsForTheme"/> <int value="11" label="FailedToScheduleNotification"/> <int value="12" label="DisabledByEnterprisePolicy"/> + <int value="13" label="ModelExecutionDisabledByParam"/> </enum> <!-- LINT.ThenChange(//chrome/browser/finds/core/finds_service.h:Status) -->
diff --git a/tools/metrics/histograms/metadata/safe_browsing/histograms.xml b/tools/metrics/histograms/metadata/safe_browsing/histograms.xml index 6f97c1d..0560cbe 100644 --- a/tools/metrics/histograms/metadata/safe_browsing/histograms.xml +++ b/tools/metrics/histograms/metadata/safe_browsing/histograms.xml
@@ -288,8 +288,8 @@ <histogram name="SafeBrowsing.AndroidTelemetry.DownloadDirectlyTriggeredByIntent" - enum="Boolean" expires_after="2026-06-08"> - <owner>chlily@chromium.org</owner> + enum="Boolean" expires_after="2026-12-08"> + <owner>yawfrempong@google.com</owner> <owner>chrome-counter-abuse-alerts@google.com</owner> <summary> This records whether an APK download on Android was triggered by an intent.
diff --git a/tools/metrics/histograms/metadata/sb_client/enums.xml b/tools/metrics/histograms/metadata/sb_client/enums.xml index a37a2287..55e0e66 100644 --- a/tools/metrics/histograms/metadata/sb_client/enums.xml +++ b/tools/metrics/histograms/metadata/sb_client/enums.xml
@@ -516,6 +516,9 @@ <int value="12" label="Classification is ongoing when another classification request comes in"/> + <int value="13" + label="A new page load comes in while old detection request was waiting + on an old page load"/> </enum> <enum name="TailoredWarningType">
diff --git a/tools/metrics/histograms/metadata/sb_client/histograms.xml b/tools/metrics/histograms/metadata/sb_client/histograms.xml index 43d581f..e9c15470 100644 --- a/tools/metrics/histograms/metadata/sb_client/histograms.xml +++ b/tools/metrics/histograms/metadata/sb_client/histograms.xml
@@ -128,8 +128,8 @@ </histogram> <histogram name="SBClientDownload.CancelEphemeralWarning" - enum="CancelEphemeralWarningEvent" expires_after="2026-06-07"> - <owner>chlily@chromium.org</owner> + enum="CancelEphemeralWarningEvent" expires_after="2026-12-07"> + <owner>yawfrempong@google.com</owner> <owner>chrome-counter-abuse-alerts@google.com</owner> <summary> Records the events related to ephemeral warning cancellation. Compare the
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json index 5ea39acf..ee5f08daa 100644 --- a/tools/perf/core/perfetto_binary_roller/binary_deps.json +++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -5,8 +5,8 @@ "full_remote_path": "perfetto-luci-artifacts/v52.0/linux-arm64/trace_processor_shell" }, "win": { - "hash": "41c748fbc4c9c84d76053f779d8f2467d1ff1c92", - "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/afc643c1b766b35907343229f6fcf33ee9b68509/trace_processor_shell.exe" + "hash": "1d61b0ba15b0e1458090fc93def42812c3ffa8f1", + "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/c9f7b8a8e0f461dd8335af67ae9e097622d47152/trace_processor_shell.exe" }, "linux_arm": { "hash": "46d798c1864490cbb2ee053d6eda436184470e69", @@ -21,8 +21,8 @@ "full_remote_path": "perfetto-luci-artifacts/ebf44e57a3b734c5281bdff53d9945805486004e/mac-arm64/trace_processor_shell" }, "linux": { - "hash": "08276439e2cc181197beac56191c5e84a446fd02", - "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/afc643c1b766b35907343229f6fcf33ee9b68509/trace_processor_shell" + "hash": "233618457037b0cac325981730d8b4734c25e689", + "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/c9f7b8a8e0f461dd8335af67ae9e097622d47152/trace_processor_shell" } }, "power_profile.sql": {
diff --git a/ui/accessibility/platform/ax_platform_node_base.cc b/ui/accessibility/platform/ax_platform_node_base.cc index b9458b8f..809e129 100644 --- a/ui/accessibility/platform/ax_platform_node_base.cc +++ b/ui/accessibility/platform/ax_platform_node_base.cc
@@ -1905,7 +1905,7 @@ // TODO(crbug.com/40897578): Make sure this doesn't fire then turn the last // conditional into a CHECK_GT(endpoint_index_in_common_parent, // index_in_common_parent); and remove this code path. - DUMP_WILL_BE_NOTREACHED() + DCHECK(false) << "Was not in descendant, so the endpoint_index_in_common_parent should " "be < or > than the index_in_common_parent:\n" << "\n* This: " << this << "\n* Endpoint object: " << endpoint_object
diff --git a/ui/android/java/src/org/chromium/ui/base/ViewUtils.java b/ui/android/java/src/org/chromium/ui/base/ViewUtils.java index 919e7f7e..045a41d 100644 --- a/ui/android/java/src/org/chromium/ui/base/ViewUtils.java +++ b/ui/android/java/src/org/chromium/ui/base/ViewUtils.java
@@ -174,6 +174,16 @@ } /** + * Converts pixels on the screen (px) to density-independent pixels (dp). + * + * @param px The physical pixels on the screen. + * @return The density-independent pixels that correspond to this many physical pixels. + */ + public static int pxToDp(Context context, int px) { + return Math.round(px / context.getResources().getDisplayMetrics().density); + } + + /** * As {@link #setAncestorsShouldClipChildren(ViewGroup, boolean, int)}, defaulting to stopping * at the view with id android.R.id.content. */
diff --git a/ui/display/mac/vsync_provider_mac.cc b/ui/display/mac/vsync_provider_mac.cc index c47f2d3a..4ec862c 100644 --- a/ui/display/mac/vsync_provider_mac.cc +++ b/ui/display/mac/vsync_provider_mac.cc
@@ -21,12 +21,6 @@ VSyncProviderMac::~VSyncProviderMac() = default; -VSyncProviderMac::DisplayState::DisplayState() = default; -VSyncProviderMac::DisplayState::~DisplayState() = default; -VSyncProviderMac::DisplayState::DisplayState(DisplayState&& other) = default; -VSyncProviderMac::DisplayState& VSyncProviderMac::DisplayState::operator=( - DisplayState&& other) = default; - void VSyncProviderMac::SetSupportedDisplayLinkId(int64_t display_id, bool is_supported) { if (is_supported) { @@ -40,9 +34,14 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(vsync_sequence_checker_); base::AutoLock lock(id_lock_); - auto found = display_states_.find(display_id); - if (found == display_states_.end()) { - display_states_.emplace(display_id, DisplayState()); + auto found = callback_lists_.find(display_id); + if (found == callback_lists_.end()) { + std::list<VSyncCallbackMac::Callback> callbacks; + // Insert an empty callback list + auto result = callback_lists_.insert( + std::make_pair(display_id, std::move(callbacks))); + bool inserted = result.second; + DCHECK(inserted); } } @@ -50,7 +49,10 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(vsync_sequence_checker_); base::AutoLock lock(id_lock_); - display_states_.erase(display_id); + auto found = callback_lists_.find(display_id); + if (found != callback_lists_.end()) { + callback_lists_.erase(display_id); + } } void VSyncProviderMac::RegisterCallback(VSyncCallbackMac::Callback callback, @@ -63,15 +65,15 @@ return; } - auto found = display_states_.find(display_id); - if (found == display_states_.end()) { + auto found = callback_lists_.find(display_id); + if (found == callback_lists_.end()) { return; } - DisplayState& display_state = found->second; - bool should_request_begin_frame = display_state.callbacks.empty(); + std::list<VSyncCallbackMac::Callback>& callbacks = found->second; + bool should_request_begin_frame = callbacks.empty(); - display_state.callbacks.push_back(std::move(callback)); + callbacks.push_back(std::move(callback)); // Request BeginFrame in browser via IPC. if (should_request_begin_frame) { @@ -90,15 +92,19 @@ return; } - auto found = display_states_.find(display_id); - if (found == display_states_.end()) { + auto found = callback_lists_.find(display_id); + if (found == callback_lists_.end()) { return; } - found->second.callbacks.remove(callback); + std::list<VSyncCallbackMac::Callback>& callbacks = found->second; + callbacks.remove(callback); - // Do not request stopping BeginFrame in browser via IPC at this stage. VSyncs - // will be stopped in OnVSync() if needed. + // Stop BeginFrame in browser via IPC. + if (callbacks.empty()) { + needs_begin_frame_callback_.Run(display_id, + /*needs_begin_frames=*/false); + } } void VSyncProviderMac::OnVSync(const VSyncParamsMac& params, @@ -106,42 +112,21 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(vsync_sequence_checker_); TRACE_EVENT0("gpu", "VSyncProviderMac::OnVSync"); - // DisplayLink entry might no longer exist after display removal. - auto found = display_states_.find(display_id); - if (found == display_states_.end()) { + // DisplayLink entry might no longer exist. + auto found = callback_lists_.find(display_id); + if (found == callback_lists_.end()) { return; } - DisplayState& display_state = found->second; - // Unregister() might be called inside the loop and - // |display_state.callbacks| size changes while callbacks are called. Get + // |callback_lists_.[display_id]| size changes while callbacks are called. Get // a local copy here. - std::list<VSyncCallbackMac::Callback> local_callbacks = - display_state.callbacks; + std::list<VSyncCallbackMac::Callback> local_callbacks = found->second; // Run callbacks for (auto& cb : local_callbacks) { cb.Run(params); } - - // Defer stopping VSync after the last client unregisters. - if (!display_state.callbacks.empty()) { - display_state.consecutive_vsyncs_with_no_callbacks = 0; - return; - } - - // Keep VSync alive for a short period. - display_state.consecutive_vsyncs_with_no_callbacks++; - if (display_state.consecutive_vsyncs_with_no_callbacks < - kMaxExtraVSyncCallbacks) { - return; - } - - // Now stop BeginFrame in the Browser via IPC. - display_state.consecutive_vsyncs_with_no_callbacks = 0; - needs_begin_frame_callback_.Run(display_id, - /*needs_begin_frames=*/false); } void VSyncProviderMac::SetCallbackForRemoteNeedsBeginFrame( @@ -155,10 +140,10 @@ return false; } - // |display_states_| is updated on Viz thread. A lock is needed when this + // |callback_lists_| is updated on Viz thread. A lock is needed when this // function is called on CrGpuMain or CompositorGpuThread (DrDC). base::AutoLock lock(id_lock_); - return display_states_.find(display_id) != display_states_.end(); + return callback_lists_.find(display_id) != callback_lists_.end(); } bool VSyncProviderMac::BelongsToCurrentThread() {
diff --git a/ui/display/mac/vsync_provider_mac.h b/ui/display/mac/vsync_provider_mac.h index 75a82a0..526dac4 100644 --- a/ui/display/mac/vsync_provider_mac.h +++ b/ui/display/mac/vsync_provider_mac.h
@@ -53,34 +53,19 @@ private: friend class base::NoDestructor<VSyncProviderMac>; - // To prevent CADisplayLink from frequently switching between the on and off - // states, keep VSync alive for extra callbacks after all clients are - // unregistered. This reduces IPC latency for the first frame after pause. - static constexpr int kMaxExtraVSyncCallbacks = 20; - VSyncProviderMac(); virtual ~VSyncProviderMac(); void AddSupportedDisplayLinkId(int64_t display_id); void RemoveSupportedDisplayLinkId(int64_t display_id); - struct DisplayState { - DisplayState(); - ~DisplayState(); - DisplayState(DisplayState&& other); - DisplayState& operator=(DisplayState&& other); - - std::list<VSyncCallbackMac::Callback> callbacks; - int consecutive_vsyncs_with_no_callbacks = 0; - }; - NeedsBeginFrameCB needs_begin_frame_callback_; // Updated on Viz thread and read back on both Viz and gpu main thread. // Use this lock when it's written on the Viz thread and read back on the gpu // main thread. No need to lock when read on Viz thread. base::Lock id_lock_; - std::map<int64_t, DisplayState> display_states_; + std::map<int64_t, std::list<VSyncCallbackMac::Callback>> callback_lists_; scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
diff --git a/ui/events/event.cc b/ui/events/event.cc index dd4343f5..e444a79e 100644 --- a/ui/events/event.cc +++ b/ui/events/event.cc
@@ -363,8 +363,18 @@ } std::string LocatedEvent::ToString() const { - return base::StrCat({Event::ToString(), " location=", location_.ToString(), - " root_location=", root_location_.ToString()}); + return base::StrCat( + {Event::ToString(), " location=", location_.ToString(), + " root_location=", root_location_.ToString(), + " target=", base::StringPrintf("%p", target()), +#if BUILDFLAG(IS_OZONE) + " native=", (native_event() ? native_event()->ToString() : "(nil)") +#elif BUILDFLAG(IS_WIN) + " native={hwnd=", base::StringPrintf("%p", native_event().hwnd), " pt=", + base::StringPrintf("%d,%d", native_event().pt.x, native_event().pt.y), + "}" +#endif + }); } ////////////////////////////////////////////////////////////////////////////////
diff --git a/ui/views/accessibility/atomic_view_ax_tree_manager.cc b/ui/views/accessibility/atomic_view_ax_tree_manager.cc index 859db31..e17d9c7 100644 --- a/ui/views/accessibility/atomic_view_ax_tree_manager.cc +++ b/ui/views/accessibility/atomic_view_ax_tree_manager.cc
@@ -56,10 +56,9 @@ } ui::AXNode* AtomicViewAXTreeManager::GetNode(ui::AXNodeID node_id) const { - // This here is the key to the whole thing. The AtomicViewAXTreeManager is - // fetching and updating the AXNodeData from the View itself whenever this - // function gets called. - ax_tree_->root()->SetData(delegate_->GetData()); + // Fetch and update the AXNodeData from the View itself whenever this function + // gets called. + RefreshRootDataFromDelegate(); DCHECK_EQ(node_id, ax_tree_->root()->id()) << "The AtomicViewAXTreeManager should only allow callers to get the " "root node as it is the only managed node."; @@ -75,7 +74,7 @@ return nullptr; } - ax_tree_->root()->SetData(delegate_->GetData()); + RefreshRootDataFromDelegate(); return AXTreeManager::GetRoot(); } @@ -101,4 +100,13 @@ return ax_tree_->root()->ClearComputedNodeData(); } +void AtomicViewAXTreeManager::RefreshRootDataFromDelegate() const { + ui::AXNodeData data = delegate_->GetData(); + // The delegate can return fallback data with kInvalidAXNodeID after the view + // has detached from its widget during teardown. Preserve the root id so the + // node remains reachable through AXTree::id_map_ when the tree is destroyed. + data.id = ax_tree_->root()->id(); + ax_tree_->root()->SetData(data); +} + } // namespace views
diff --git a/ui/views/accessibility/atomic_view_ax_tree_manager.h b/ui/views/accessibility/atomic_view_ax_tree_manager.h index 2df99d70..144d6b0 100644 --- a/ui/views/accessibility/atomic_view_ax_tree_manager.h +++ b/ui/views/accessibility/atomic_view_ax_tree_manager.h
@@ -52,6 +52,8 @@ explicit AtomicViewAXTreeManager(ViewAXPlatformNodeDelegate* delegate, const ui::AXNodeData& node_data); + void RefreshRootDataFromDelegate() const; + raw_ptr<ViewAXPlatformNodeDelegate> delegate_; };
diff --git a/ui/views/accessibility/atomic_view_ax_tree_manager_unittest.cc b/ui/views/accessibility/atomic_view_ax_tree_manager_unittest.cc index cbc7a31..c677189 100644 --- a/ui/views/accessibility/atomic_view_ax_tree_manager_unittest.cc +++ b/ui/views/accessibility/atomic_view_ax_tree_manager_unittest.cc
@@ -103,4 +103,25 @@ ->data()); } +TEST_F(AtomicViewAXTreeManagerTest, GetRootPreservesNodeIdAfterWidgetRemoval) { + AtomicViewAXTreeManager* manager = + delegate_->GetAtomicViewAXTreeManagerForTesting(); + const ui::AXNodeID root_id = manager->GetRoot()->id(); + + std::unique_ptr<Textfield> textfield = + widget_->GetContentsView()->RemoveChildViewT(textfield_.get()); + ASSERT_FALSE(textfield->GetWidget()); + + EXPECT_EQ(ui::kInvalidAXNodeID, delegate_->GetData().id); + + const ui::AXNodeData& root_data = manager->GetRoot()->data(); + EXPECT_EQ(root_id, root_data.id); + EXPECT_EQ(ax::mojom::Role::kUnknown, root_data.role); + EXPECT_EQ(ax::mojom::Restriction::kDisabled, root_data.GetRestriction()); + EXPECT_EQ(root_id, manager->GetNode(root_id)->id()); + + delegate_ = nullptr; + textfield_ = nullptr; +} + } // namespace views
diff --git a/ui/views/bubble/bubble_dialog_delegate_view.cc b/ui/views/bubble/bubble_dialog_delegate_view.cc index e92bdcc..5062c1f 100644 --- a/ui/views/bubble/bubble_dialog_delegate_view.cc +++ b/ui/views/bubble/bubble_dialog_delegate_view.cc
@@ -524,42 +524,63 @@ } // static -Widget* BubbleDialogDelegate::CreateBubbleDeprecated( - BubbleDialogDelegate* bubble_delegate, - Widget::InitParams::Ownership ownership) { +Widget* BubbleDialogDelegate::CreateBubbleInternal( + BubbleDialogDelegate* delegate, + Widget::InitParams::Ownership ownership, + Widget::ClosedCallback on_close) { // On Mac, ModalType::kWindow is implemented using sheets, which can't be // anchored at a specific point - they are always placed near the top center // of the window. To avoid unpleasant surprises, disallow setting an anchor // view or rectangle on these types of bubbles. - if (bubble_delegate->GetModalType() == ui::mojom::ModalType::kWindow) { - DCHECK(!bubble_delegate->GetAnchorView()); - DCHECK_EQ(bubble_delegate->GetAnchorRect(), gfx::Rect()); + if (delegate->GetModalType() == ui::mojom::ModalType::kWindow) { + DCHECK(!delegate->GetAnchorView()); + DCHECK_EQ(delegate->GetAnchorRect(), gfx::Rect()); } - bubble_delegate->Init(); + delegate->Init(); // Get the latest anchor widget from the anchor view at bubble creation time. - if (auto* anchor_view = bubble_delegate->GetAnchorView()) { - bubble_delegate->SetAnchorView(anchor_view); + if (auto* anchor_view = delegate->GetAnchorView()) { + delegate->SetAnchorView(anchor_view); } - Widget* const bubble_widget = CreateBubbleWidget(bubble_delegate, ownership); - bubble_delegate->set_adjust_if_offscreen( - PlatformStyle::kAdjustBubbleIfOffscreen); + Widget* const bubble_widget = CreateBubbleWidget(delegate, ownership); - bubble_delegate->SizeToContents(); - bubble_delegate->bubble_widget_observer_ = - std::make_unique<BubbleWidgetObserver>(bubble_delegate, bubble_widget); + delegate->set_adjust_if_offscreen(PlatformStyle::kAdjustBubbleIfOffscreen); + delegate->SizeToContents(); + delegate->bubble_widget_observer_ = + std::make_unique<BubbleWidgetObserver>(delegate, bubble_widget); + + if (on_close) { + bubble_widget->MakeCloseSynchronous(std::move(on_close)); + } + return bubble_widget; } // static Widget* BubbleDialogDelegate::CreateBubbleDeprecated( + BubbleDialogDelegate* bubble_delegate, + Widget::InitParams::Ownership ownership) { + return CreateBubbleInternal(bubble_delegate, ownership); +} + +// static +Widget* BubbleDialogDelegate::CreateBubbleDeprecated( std::unique_ptr<BubbleDialogDelegate> bubble_delegate_unique, Widget::InitParams::Ownership ownership) { return CreateBubbleDeprecated(bubble_delegate_unique.release(), ownership); } // static +std::unique_ptr<Widget> BubbleDialogDelegate::CreateBubble( + std::unique_ptr<BubbleDialogDelegate> delegate, + base::OnceCallback<void(Widget::ClosedReason)> on_close) { + return base::WrapUnique(CreateBubbleInternal( + delegate.release(), Widget::InitParams::CLIENT_OWNS_WIDGET, + std::move(on_close))); +} + +// static Widget* BubbleDialogDelegateView::CreateBubble( BubbleDialogDelegateView* delegate_view, Widget::InitParams::Ownership ownership) {
diff --git a/ui/views/bubble/bubble_dialog_delegate_view.h b/ui/views/bubble/bubble_dialog_delegate_view.h index b2dbc94..4b6b8e1 100644 --- a/ui/views/bubble/bubble_dialog_delegate_view.h +++ b/ui/views/bubble/bubble_dialog_delegate_view.h
@@ -12,6 +12,8 @@ #include <utility> #include "base/check.h" +#include "base/functional/callback_forward.h" +#include "base/functional/callback_helpers.h" #include "base/gtest_prod_util.h" #include "base/memory/raw_ptr.h" #include "base/memory/raw_span.h" @@ -250,14 +252,26 @@ // unique_ptr using base::WrapUnique(). // // If you encounter problems with this ownership mode, please file a bug. + // + // STRONGLY DISCOURAGED. static Widget* CreateBubbleDeprecated( std::unique_ptr<BubbleDialogDelegate> bubble_delegate, Widget::InitParams::Ownership ownership); + // STRONGLY DISCOURAGED. static Widget* CreateBubbleDeprecated( BubbleDialogDelegate* bubble_delegate, Widget::InitParams::Ownership ownership); + // Preferred alternative; defaults to CLIENT_OWNS_WIDGET. `on_close` is + // invoked synchronously when the bubble is closed; note that the callback is + // responsible for deleting the widget. When `on_close` is not provided, the + // caller is responsible to call MakeCloseSynchronous(..) and set the callback + // to handle the close event. + static std::unique_ptr<Widget> CreateBubble( + std::unique_ptr<BubbleDialogDelegate> delegate, + Widget::ClosedCallback on_close = base::NullCallback()); + ////////////////////////////////////////////////////////////////////////////// // The anchor view and rectangle: // @@ -593,6 +607,12 @@ virtual void OnWidgetVisibilityChanged(Widget* widget, bool visible) {} private: + static Widget* CreateBubbleInternal( + BubbleDialogDelegate* delegate, + Widget::InitParams::Ownership ownership, + base::OnceCallback<void(Widget::ClosedReason)> on_close = + base::NullCallback()); + class AnchorViewObserver; class AnchorWidgetObserver; class BubbleWidgetObserver;
diff --git a/ui/views/bubble/bubble_dialog_delegate_view_unittest.cc b/ui/views/bubble/bubble_dialog_delegate_view_unittest.cc index 0bc423a..36ec93b 100644 --- a/ui/views/bubble/bubble_dialog_delegate_view_unittest.cc +++ b/ui/views/bubble/bubble_dialog_delegate_view_unittest.cc
@@ -248,6 +248,29 @@ EXPECT_TRUE(bubble_observer.widget_closed()); } +TEST_F(BubbleDialogDelegateViewTest, CreateBubbleWithUniquePtrAndCallback) { + std::unique_ptr<Widget> anchor_widget = CreateTestWidget( + Widget::InitParams::CLIENT_OWNS_WIDGET, Widget::InitParams::TYPE_WINDOW); + TestBubbleDialogDelegateView* bubble_delegate = + new TestBubbleDialogDelegateView(anchor_widget->GetContentsView()); + + bool close_callback_invoked = false; + auto on_close = base::BindOnce( + [](bool* invoked, Widget::ClosedReason reason) { *invoked = true; }, + &close_callback_invoked); + + // 1. Verify that CreateBubble properly returns a unique_ptr. + std::unique_ptr<Widget> bubble_widget = BubbleDialogDelegate::CreateBubble( + base::WrapUnique(bubble_delegate), std::move(on_close)); + + ASSERT_TRUE(bubble_widget); + EXPECT_FALSE(close_callback_invoked); + + // 2. Verify that destroying the widget invokes the provided callback. + bubble_widget->CloseNow(); + EXPECT_TRUE(close_callback_invoked); +} + TEST_F(BubbleDialogDelegateViewTest, CloseAnchorWidget) { std::unique_ptr<Widget> anchor_widget = CreateTestWidget( Widget::InitParams::CLIENT_OWNS_WIDGET, Widget::InitParams::TYPE_WINDOW);
diff --git a/ui/views/bubble/bubble_frame_view.cc b/ui/views/bubble/bubble_frame_view.cc index 7e859c94..2f973b7 100644 --- a/ui/views/bubble/bubble_frame_view.cc +++ b/ui/views/bubble/bubble_frame_view.cc
@@ -59,6 +59,10 @@ #include "ui/views/window/dialog_delegate.h" #include "ui/views/window/vector_icons/vector_icons.h" +#if BUILDFLAG(IS_OZONE) +#include "ui/ozone/public/ozone_platform.h" +#endif + namespace views { namespace { @@ -995,10 +999,23 @@ gfx::Rect BubbleFrameView::GetAvailableScreenBounds( const gfx::Rect& rect) const { + gfx::Rect work_area = display::Screen::Get() + ->GetDisplayNearestPoint(rect.CenterPoint()) + .work_area(); +#if BUILDFLAG(IS_OZONE) + // When global screen coordinates aren't supported, shift the work area to + // (0,0). If two displays are offset, the work area coordinates may not start + // at 0 which results in invalid comparisons when positioning bubbles. + // TODO(crbug.com/510418617): Consider moving this logic to the display level + // in the future rather than hosting it in Views. + if (!ui::OzonePlatform::GetInstance() + ->GetPlatformProperties() + .supports_global_screen_coordinates) { + work_area.set_origin(gfx::Point(0, 0)); + } +#endif // The bubble attempts to fit within the current screen bounds. - return display::Screen::Get() - ->GetDisplayNearestPoint(rect.CenterPoint()) - .work_area(); + return work_area; } gfx::Rect BubbleFrameView::GetAvailableAnchorWindowBounds() const {
diff --git a/ui/views/interaction/element_tracker_widget_state_unittest.cc b/ui/views/interaction/element_tracker_widget_state_unittest.cc index 351591f..3db569b6 100644 --- a/ui/views/interaction/element_tracker_widget_state_unittest.cc +++ b/ui/views/interaction/element_tracker_widget_state_unittest.cc
@@ -225,7 +225,16 @@ EXPECT_ASYNC_CALL_IN_SCOPE(destroying, Run(widget_.get()), widget_->Close()); } -TEST_F(ElementTrackerWidgetStateTest, HideImmediatelyAfterMinimizeAndRestore) { +// TODO(crbug.com/510130340): Re-enable after fixing. +#if BUILDFLAG(IS_MAC) +#define MAYBE_HideImmediatelyAfterMinimizeAndRestore \ + DISABLED_HideImmediatelyAfterMinimizeAndRestore +#else +#define MAYBE_HideImmediatelyAfterMinimizeAndRestore \ + HideImmediatelyAfterMinimizeAndRestore +#endif +TEST_F(ElementTrackerWidgetStateTest, + MAYBE_HideImmediatelyAfterMinimizeAndRestore) { UNCALLED_MOCK_CALLBACK(WidgetVisibilityChangedCallback, visibility_changed); UNCALLED_MOCK_CALLBACK(WidgetDestroyingCallback, destroying); auto visibility_subscription =
diff --git a/ui/views/widget/widget.h b/ui/views/widget/widget.h index a3413e4c..eabe6e1 100644 --- a/ui/views/widget/widget.h +++ b/ui/views/widget/widget.h
@@ -166,6 +166,9 @@ using ShapeRects = std::vector<gfx::Rect>; using PaintAsActiveCallbackList = base::RepeatingClosureList; + enum class ClosedReason; + using ClosedCallback = base::OnceCallback<void(ClosedReason)>; + enum class FrameType { kDefault, // Use whatever the default would be. kForceCustom, // Force the custom frame. @@ -899,8 +902,7 @@ // It is OK to not reset the Widget in the callback. This blocks the window // from closing. Used for example in web page unload handlers that shows a // dialog to the user to confirm whether to discard changes. - void MakeCloseSynchronous( - base::OnceCallback<void(ClosedReason)> override_close); + void MakeCloseSynchronous(ClosedCallback override_close); // A UI test which tries to asynchronously examine a widget (e.g. the pixel // tests) will fail if the widget is closed before that. This can happen
diff --git a/ui/webui/resources/cr_components/composebox/composebox.html.ts b/ui/webui/resources/cr_components/composebox/composebox.html.ts index 27ebb585..b83f254b 100644 --- a/ui/webui/resources/cr_components/composebox/composebox.html.ts +++ b/ui/webui/resources/cr_components/composebox/composebox.html.ts
@@ -100,7 +100,7 @@ </cr-composebox-submit> ` : ''} </div> - ${this.shouldShowDivider_() ? html` + ${this.shouldShowDivider() ? html` <div class="carousel-divider" part="carousel-divider"></div> ` : ''} <cr-composebox-dropdown
diff --git a/ui/webui/resources/cr_components/composebox/composebox.ts b/ui/webui/resources/cr_components/composebox/composebox.ts index e270d23..27ca03c 100644 --- a/ui/webui/resources/cr_components/composebox/composebox.ts +++ b/ui/webui/resources/cr_components/composebox/composebox.ts
@@ -23,7 +23,6 @@ import {DragAndDropHandler} from '//resources/cr_components/search/drag_drop_handler.js'; import type {DragAndDropHost} from '//resources/cr_components/search/drag_drop_host.js'; import {EventTracker} from '//resources/js/event_tracker.js'; -import {loadTimeData} from '//resources/js/load_time_data.js'; import type {PropertyValues} from '//resources/lit/v3_0/lit.rollup.js'; import {CrLitElement} from '//resources/lit/v3_0/lit.rollup.js'; import type {AutocompleteResult, FileAttachment, PageCallbackRouter as SearchboxPageCallbackRouter, PageHandlerRemote as SearchboxPageHandlerRemote, SearchContext, TabAttachment, TabInfo} from '//resources/mojo/components/omnibox/browser/searchbox.mojom-webui.js'; @@ -144,12 +143,16 @@ type: Boolean, reflect: true, }, + enableFileHint: {type: Boolean}, + inputPlaceholderOverride: {type: String}, }; } accessor energyEffectAnimationEnabled: boolean = false; accessor isZeroState: boolean = false; accessor isFollowupQuery: boolean = false; + accessor enableFileHint: boolean = false; + accessor inputPlaceholderOverride: string = ''; accessor suggestionActivityEnabled: boolean = true; accessor disableCaretColorAnimation: boolean = false; accessor disableComposeboxAnimation: boolean = false; @@ -186,7 +189,7 @@ private searchboxHandler_: SearchboxPageHandlerRemote; private eventTracker_: EventTracker = new EventTracker(); private resizeObservers_: ResizeObserver[] = []; - protected shouldShowDivider_(): boolean { + override shouldShowDivider(): boolean { // TODO(crbug.com/476175193): Remove `entrypointName` condition. if (this.entrypointName === 'Omnibox' && this.searchboxLayoutMode === 'TallBottomContext' && @@ -194,9 +197,7 @@ return false; } - return this.showDropdown && - (this.showFileCarousel || this.shouldShowSubmitButton() || - this.inToolMode); + return super.shouldShowDivider(); } override computeSubmitEnabled(): boolean { @@ -319,6 +320,10 @@ this.isOmniboxInCompactMode_ = this.entrypointName === 'Omnibox' && this.searchboxLayoutMode === 'Compact'; } + if (changedProperties.has('inputPlaceholderOverride') || + changedProperties.has('enableFileHint')) { + this.updateInputPlaceholder(); + } } override updated(changedProperties: PropertyValues<this>) { @@ -833,41 +838,7 @@ } } - if (this.inputState) { - if (this.inputState.activeTool !== ToolMode.kUnspecified) { - const config = this.inputState.toolConfigs.find( - c => c.tool === this.inputState!.activeTool); - if (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 (config?.hintText) { - this.inputPlaceholder = config.hintText; - return; - } - } - - if (this.inputState.hintText) { - this.inputPlaceholder = this.inputState.hintText; - return; - } - } - - if (this.inputState?.activeTool === ToolMode.kDeepSearch) { - this.inputPlaceholder = - loadTimeData.getString('composeDeepSearchPlaceholder'); - } else if (this.inputState?.activeTool === ToolMode.kImageGen) { - this.inputPlaceholder = - loadTimeData.getString('composeCreateImagePlaceholder'); - } else { - this.inputPlaceholder = - loadTimeData.getString('searchboxComposePlaceholder'); - } + super.updateInputPlaceholder(); } protected onComposeboxFocusin_(e: FocusEvent) {
diff --git a/ui/webui/resources/cr_components/composebox/composebox_mixin.ts b/ui/webui/resources/cr_components/composebox/composebox_mixin.ts index 2818cf4..ccaa380b 100644 --- a/ui/webui/resources/cr_components/composebox/composebox_mixin.ts +++ b/ui/webui/resources/cr_components/composebox/composebox_mixin.ts
@@ -51,7 +51,6 @@ reflect: true, type: Boolean, }, - enableFileHint: {type: Boolean}, enableImageContextualSuggestions: { reflect: true, type: Boolean, @@ -82,7 +81,6 @@ }, input: {type: String}, inputPlaceholder: {type: String, reflect: true}, - inputPlaceholderOverride: {type: String}, inputState: {type: Object}, inToolMode: { type: Boolean, @@ -148,7 +146,6 @@ accessor disableVoiceSearchAnimation: boolean = false; accessor addedTabsIds: Map<number, UnguessableToken> = new Map(); accessor isDraggingFile: boolean = false; - accessor enableFileHint: boolean = false; accessor enableImageContextualSuggestions: boolean = loadTimeData.getBoolean('composeboxShowImageSuggest'); accessor smartComposeEnabled: boolean = @@ -190,7 +187,6 @@ accessor input: string = ''; accessor inputPlaceholder: string = loadTimeData.getString('searchboxComposePlaceholder'); - accessor inputPlaceholderOverride: string = ''; accessor inputState: InputState|null = null; accessor inToolMode: boolean = false; accessor inVoiceSearchMode: boolean = false; @@ -332,9 +328,7 @@ })); } - if (changedPrivateProperties.has('inputPlaceholderOverride') || - changedPrivateProperties.has('files') || - changedPrivateProperties.has('enableFileHint') || + if (changedPrivateProperties.has('files') || changedPrivateProperties.has('inputState') || changedPrivateProperties.has('inputState.activeTool')) { this.updateInputPlaceholder(); @@ -747,35 +741,6 @@ } updateInputPlaceholder() { - if (this.inputPlaceholderOverride) { - this.inputPlaceholder = this.inputPlaceholderOverride; - return; - } - - const shouldUseFileHint = this.enableFileHint && this.hasFiles() && - this.inputState?.activeTool === ToolMode.kUnspecified; - if (shouldUseFileHint) { - if (this.files.size > 1) { - this.inputPlaceholder = - this.i18n('composeboxHintTextAskAboutThese'); - return; - } - const file = this.files.values().next().value!; - if (file.type === 'tab') { - this.inputPlaceholder = - this.i18n('composeboxHintTextAskAboutThisTab'); - return; - } else if (file.type.includes('image')) { - this.inputPlaceholder = - this.i18n('composeboxHintTextAskAboutThisImage'); - return; - } else if (file.type === 'pdf' || file.type === 'application/pdf') { - this.inputPlaceholder = - this.i18n('composeboxHintTextAskAboutThisDoc'); - return; - } - } - if (this.inputState) { if (this.inputState.activeTool !== ToolMode.kUnspecified) { const config = this.inputState.toolConfigs.find( @@ -1760,7 +1725,6 @@ automaticActiveTab: ComposeboxFile|null; disableVoiceSearchAnimation: boolean; isDraggingFile: boolean; - enableFileHint: boolean; enableImageContextualSuggestions: boolean; smartComposeEnabled: boolean; smartTabSharingActive: boolean; @@ -1786,7 +1750,6 @@ files: Map<UnguessableToken, ComposeboxFile>; input: string; inputPlaceholder: string; - inputPlaceholderOverride: string; inputState: InputState|null; canSubmitFilesAndInput: boolean; contextMenuEnabled: boolean;
diff --git a/ui/webui/resources/cr_components/search/recording_wave.css b/ui/webui/resources/cr_components/search/recording_wave.css index 084560b..cb08554 100644 --- a/ui/webui/resources/cr_components/search/recording_wave.css +++ b/ui/webui/resources/cr_components/search/recording_wave.css
@@ -15,11 +15,11 @@ display: flex; inline-size: 100%; justify-content: flex-start; - max-inline-size: 100%; - min-inline-size: 100%; - mask-image: linear-gradient(to right, transparent 0%, - black 20%, black 90%, - transparent 100%); + mask-image: linear-gradient(to right, + transparent 0%, + black 20%, + black 70%, + transparent 100%); overflow: visible; padding-block-start: 10px; position: relative;
diff --git a/ui/webui/resources/cr_components/searchbox/searchbox_match.css b/ui/webui/resources/cr_components/searchbox/searchbox_match.css index 84a4a31..bb62940 100644 --- a/ui/webui/resources/cr_components/searchbox/searchbox_match.css +++ b/ui/webui/resources/cr_components/searchbox/searchbox_match.css
@@ -243,7 +243,9 @@ } :host([is-contextual-suggestion_]) .container:not(.actions):hover #description, -:host([is-contextual-suggestion_]) .container:not(.actions):hover #separator { +:host([is-contextual-suggestion_]) .container:not(.actions):hover #separator, +:host-context(cr-searchbox-match:-webkit-any(:focus-within, [selected])):host([is-contextual-suggestion_]) #description, +:host-context(cr-searchbox-match:-webkit-any(:focus-within, [selected])):host([is-contextual-suggestion_]) #separator { display: inline; }